auto import from //branches/cupcake/...@125939
diff --git a/services/java/com/android/server/HeadsetObserver.java b/services/java/com/android/server/HeadsetObserver.java
index cb681e0..2bea731 100644
--- a/services/java/com/android/server/HeadsetObserver.java
+++ b/services/java/com/android/server/HeadsetObserver.java
@@ -88,23 +88,8 @@
             mHeadsetName = newName;
             mHeadsetState = newState;
             AudioManager audioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
-    
-            if (mHeadsetState == 1) {
-                audioManager.setRouting(AudioManager.MODE_NORMAL, AudioManager.ROUTE_HEADSET,
-                                       AudioManager.ROUTE_ALL);
-                audioManager.setRouting(AudioManager.MODE_RINGTONE,
-                                       AudioManager.ROUTE_HEADSET | AudioManager.ROUTE_SPEAKER,
-                                       AudioManager.ROUTE_ALL);
-                audioManager.setRouting(AudioManager.MODE_IN_CALL, AudioManager.ROUTE_HEADSET,
-                                       AudioManager.ROUTE_ALL);
-            } else {
-                audioManager.setRouting(AudioManager.MODE_NORMAL, AudioManager.ROUTE_SPEAKER,
-                                       AudioManager.ROUTE_ALL);
-                audioManager.setRouting(AudioManager.MODE_RINGTONE, AudioManager.ROUTE_SPEAKER,
-                                       AudioManager.ROUTE_ALL);
-                audioManager.setRouting(AudioManager.MODE_IN_CALL, AudioManager.ROUTE_EARPIECE,
-                                       AudioManager.ROUTE_ALL);
-            }
+
+            audioManager.setWiredHeadsetOn(mHeadsetState == 1);
             sendIntent();
         }
     }
diff --git a/services/java/com/android/server/InputMethodManagerService.java b/services/java/com/android/server/InputMethodManagerService.java
index c701ca1..63d7c94 100644
--- a/services/java/com/android/server/InputMethodManagerService.java
+++ b/services/java/com/android/server/InputMethodManagerService.java
@@ -952,7 +952,15 @@
 
     public void setInputMethod(IBinder token, String id) {
         synchronized (mMethodMap) {
-            if (mCurToken == null || mCurToken != token) {
+            if (mCurToken == null) {
+                if (mContext.checkCallingOrSelfPermission(
+                        android.Manifest.permission.WRITE_SECURE_SETTINGS)
+                        != PackageManager.PERMISSION_GRANTED) {
+                    throw new SecurityException(
+                            "Using null token requires permission "
+                            + android.Manifest.permission.WRITE_SECURE_SETTINGS);
+                }
+            } else if (mCurToken != token) {
                 Log.w(TAG, "Ignoring setInputMethod of token: " + token);
             }
 
@@ -1258,6 +1266,100 @@
         }
     }
     
+    // ----------------------------------------------------------------------
+    
+    public boolean setInputMethodEnabled(String id, boolean enabled) {
+        synchronized (mMethodMap) {
+            if (mContext.checkCallingOrSelfPermission(
+                    android.Manifest.permission.WRITE_SECURE_SETTINGS)
+                    != PackageManager.PERMISSION_GRANTED) {
+                throw new SecurityException(
+                        "Requires permission "
+                        + android.Manifest.permission.WRITE_SECURE_SETTINGS);
+            }
+            
+            // Make sure this is a valid input method.
+            InputMethodInfo imm = mMethodMap.get(id);
+            if (imm == null) {
+                if (imm == null) {
+                    throw new IllegalArgumentException("Unknown id: " + mCurMethodId);
+                }
+            }
+            
+            StringBuilder builder = new StringBuilder(256);
+            
+            boolean removed = false;
+            String firstId = null;
+            
+            // Look through the currently enabled input methods.
+            String enabledStr = Settings.Secure.getString(mContext.getContentResolver(),
+                    Settings.Secure.ENABLED_INPUT_METHODS);
+            if (enabledStr != null) {
+                final TextUtils.SimpleStringSplitter splitter = mStringColonSplitter;
+                splitter.setString(enabledStr);
+                while (splitter.hasNext()) {
+                    String curId = splitter.next();
+                    if (curId.equals(id)) {
+                        if (enabled) {
+                            // We are enabling this input method, but it is
+                            // already enabled.  Nothing to do.  The previous
+                            // state was enabled.
+                            return true;
+                        }
+                        // We are disabling this input method, and it is
+                        // currently enabled.  Skip it to remove from the
+                        // new list.
+                        removed = true;
+                    } else if (!enabled) {
+                        // We are building a new list of input methods that
+                        // doesn't contain the given one.
+                        if (firstId == null) firstId = curId;
+                        if (builder.length() > 0) builder.append(':');
+                        builder.append(curId);
+                    }
+                }
+            }
+            
+            if (!enabled) {
+                if (!removed) {
+                    // We are disabling the input method but it is already
+                    // disabled.  Nothing to do.  The previous state was
+                    // disabled.
+                    return false;
+                }
+                // Update the setting with the new list of input methods.
+                Settings.Secure.putString(mContext.getContentResolver(),
+                        Settings.Secure.ENABLED_INPUT_METHODS, builder.toString());
+                // We the disabled input method is currently selected, switch
+                // to another one.
+                String selId = Settings.Secure.getString(mContext.getContentResolver(),
+                        Settings.Secure.DEFAULT_INPUT_METHOD);
+                if (id.equals(selId)) {
+                    Settings.Secure.putString(mContext.getContentResolver(),
+                            Settings.Secure.DEFAULT_INPUT_METHOD,
+                            firstId != null ? firstId : "");
+                }
+                // Previous state was enabled.
+                return true;
+            }
+            
+            // Add in the newly enabled input method.
+            if (enabledStr == null || enabledStr.length() == 0) {
+                enabledStr = id;
+            } else {
+                enabledStr = enabledStr + ':' + id;
+            }
+            
+            Settings.Secure.putString(mContext.getContentResolver(),
+                    Settings.Secure.ENABLED_INPUT_METHODS, enabledStr);
+            
+            // Previous state was disabled.
+            return false;
+        }
+    }
+    
+    // ----------------------------------------------------------------------
+    
     @Override
     protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (mContext.checkCallingPermission("android.permission.DUMP")
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index 831d1d2..ed9ee79 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -569,7 +569,7 @@
 
     private WifiManager.WifiLock getWifiWakelock() {
         if (mWifiLock == null && mWifiManager != null) {
-            mWifiLock = mWifiManager.createWifiLock(WIFILOCK_KEY);
+            mWifiLock = mWifiManager.createWifiLock(WifiManager.WIFI_MODE_SCAN_ONLY, WIFILOCK_KEY);
             mWifiLock.setReferenceCounted(false);
         }
         return mWifiLock;
diff --git a/services/java/com/android/server/MountService.java b/services/java/com/android/server/MountService.java
index 03480d1..002ebed 100644
--- a/services/java/com/android/server/MountService.java
+++ b/services/java/com/android/server/MountService.java
@@ -137,7 +137,11 @@
      * Broadcasts the USB mass storage connected event to all clients.
      */
     void notifyUmsConnected() {
-        setUsbStorageNotificationVisibility(true);
+        String storageState = Environment.getExternalStorageState();
+        if (!storageState.equals(Environment.MEDIA_REMOVED) &&
+                !storageState.equals(Environment.MEDIA_BAD_REMOVAL)) {
+            setUsbStorageNotificationVisibility(true);
+        }
         Intent intent = new Intent(Intent.ACTION_UMS_CONNECTED);
         mContext.sendBroadcast(intent);
     }
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index e86ff02..f0d5eaf 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -204,7 +204,7 @@
     boolean mRestoredSettings;
     boolean mReportedUidError;
 
-    // Group-ids that are given to all packages as read from etc/permissions.xml.
+    // Group-ids that are given to all packages as read from etc/permissions/*.xml.
     int[] mGlobalGids;
 
     // These are the built-in uid -> permission mappings that were read from the
@@ -534,8 +534,43 @@
     }
 
     void readPermissions() {
+        // Read permissions from .../etc/permission directory.
+        File libraryDir = new File(Environment.getRootDirectory(), "etc/permissions");
+        if (!libraryDir.exists() || !libraryDir.isDirectory()) {
+            Log.w(TAG, "No directory " + libraryDir + ", skipping");
+            return;
+        }
+        if (!libraryDir.canRead()) {
+            Log.w(TAG, "Directory " + libraryDir + " cannot be read");
+            return;
+        }
+
+        // Iterate over the files in the directory and scan .xml files
+        for (File f : libraryDir.listFiles()) {
+            // We'll read platform.xml last
+            if (f.getPath().endsWith("etc/permissions/platform.xml")) {
+                continue;
+            }
+            
+            if (!f.getPath().endsWith(".xml")) {
+                Log.i(TAG, "Non-xml file " + f + " in " + libraryDir + " directory, ignoring");
+                continue;
+            }
+            if (!f.canRead()) {
+                Log.w(TAG, "Permissions library file " + f + " cannot be read");
+                continue;
+            }
+
+            readPermissionsFromXml(f);
+        }
+        
+        // Read permissions from .../etc/permissions/platform.xml last so it will take precedence
         final File permFile = new File(Environment.getRootDirectory(),
-                "etc/permissions.xml");
+                "etc/permissions/platform.xml");
+        readPermissionsFromXml(permFile);
+    }
+    
+    private void readPermissionsFromXml(File permFile) {        
         FileReader permReader = null;
         try {
             permReader = new FileReader(permFile);
@@ -566,9 +601,9 @@
                         Log.w(TAG, "<group> without gid at "
                                 + parser.getPositionDescription());
                     }
+
                     XmlUtils.skipCurrentTag(parser);
                     continue;
-                    
                 } else if ("permission".equals(name)) {
                     String perm = parser.getAttributeValue(null, "name");
                     if (perm == null) {
@@ -622,6 +657,7 @@
                         Log.w(TAG, "<library> without file at "
                                 + parser.getPositionDescription());
                     } else {
+                        Log.i(TAG, "Got library " + lname + " in " + lfile);
                         this.mSharedLibraries.put(lname, lfile);
                     }
                     XmlUtils.skipCurrentTag(parser);
diff --git a/services/java/com/android/server/PowerManagerService.java b/services/java/com/android/server/PowerManagerService.java
index 3fa2087..ca0ad1a 100644
--- a/services/java/com/android/server/PowerManagerService.java
+++ b/services/java/com/android/server/PowerManagerService.java
@@ -158,6 +158,7 @@
     private UnsynchronizedWakeLock mBroadcastWakeLock;
     private UnsynchronizedWakeLock mStayOnWhilePluggedInScreenDimLock;
     private UnsynchronizedWakeLock mStayOnWhilePluggedInPartialLock;
+    private UnsynchronizedWakeLock mPreventScreenOnPartialLock;
     private HandlerThread mHandlerThread;
     private Handler mHandler;
     private TimeoutTask mTimeoutTask = new TimeoutTask();
@@ -180,6 +181,7 @@
     private HashMap<IBinder,PokeLock> mPokeLocks = new HashMap<IBinder,PokeLock>();
     private long mScreenOnTime;
     private long mScreenOnStartTime;
+    private boolean mPreventScreenOn;
 
     // Used when logging number and duration of touch-down cycles
     private long mTotalTouchDownTime;
@@ -383,6 +385,8 @@
                                 PowerManager.SCREEN_DIM_WAKE_LOCK, "StayOnWhilePluggedIn Screen Dim", false);
         mStayOnWhilePluggedInPartialLock = new UnsynchronizedWakeLock(
                                 PowerManager.PARTIAL_WAKE_LOCK, "StayOnWhilePluggedIn Partial", false);
+        mPreventScreenOnPartialLock = new UnsynchronizedWakeLock(
+                                PowerManager.PARTIAL_WAKE_LOCK, "PreventScreenOn Partial", false);
 
         mScreenOnIntent = new Intent(Intent.ACTION_SCREEN_ON);
         mScreenOnIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
@@ -790,6 +794,7 @@
         pw.println("  mBroadcastWakeLock=" + mBroadcastWakeLock);
         pw.println("  mStayOnWhilePluggedInScreenDimLock=" + mStayOnWhilePluggedInScreenDimLock);
         pw.println("  mStayOnWhilePluggedInPartialLock=" + mStayOnWhilePluggedInPartialLock);
+        pw.println("  mPreventScreenOnPartialLock=" + mPreventScreenOnPartialLock);
         mScreenBrightness.dump(pw, "  mScreenBrightness: ");
         mKeyboardBrightness.dump(pw, "  mKeyboardBrightness: ");
         mButtonBrightness.dump(pw, "  mButtonBrightness: ");
@@ -1035,6 +1040,118 @@
         }
     }
 
+    /**
+     * Prevents the screen from turning on even if it *should* turn on due
+     * to a subsequent full wake lock being acquired.
+     * <p>
+     * This is a temporary hack that allows an activity to "cover up" any
+     * display glitches that happen during the activity's startup
+     * sequence.  (Specifically, this API was added to work around a
+     * cosmetic bug in the "incoming call" sequence, where the lock screen
+     * would flicker briefly before the incoming call UI became visible.)
+     * TODO: There ought to be a more elegant way of doing this,
+     * probably by having the PowerManager and ActivityManager
+     * work together to let apps specify that the screen on/off
+     * state should be synchronized with the Activity lifecycle.
+     * <p>
+     * Note that calling preventScreenOn(true) will NOT turn the screen
+     * off if it's currently on.  (This API only affects *future*
+     * acquisitions of full wake locks.)
+     * But calling preventScreenOn(false) WILL turn the screen on if
+     * it's currently off because of a prior preventScreenOn(true) call.
+     * <p>
+     * Any call to preventScreenOn(true) MUST be followed promptly by a call
+     * to preventScreenOn(false).  In fact, if the preventScreenOn(false)
+     * call doesn't occur within 5 seconds, we'll turn the screen back on
+     * ourselves (and log a warning about it); this prevents a buggy app
+     * from disabling the screen forever.)
+     * <p>
+     * TODO: this feature should really be controlled by a new type of poke
+     * lock (rather than an IPowerManager call).
+     */
+    public void preventScreenOn(boolean prevent) {
+        // TODO: use a totally new permission (separate from DEVICE_POWER) for this?
+        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER, null);
+
+        synchronized (mLocks) {
+            if (prevent) {
+                // First of all, grab a partial wake lock to
+                // make sure the CPU stays on during the entire
+                // preventScreenOn(true) -> preventScreenOn(false) sequence.
+                mPreventScreenOnPartialLock.acquire();
+
+                // Post a forceReenableScreen() call (for 5 seconds in the
+                // future) to make sure the matching preventScreenOn(false) call
+                // has happened by then.
+                mHandler.removeCallbacks(mForceReenableScreenTask);
+                mHandler.postDelayed(mForceReenableScreenTask, 5000);
+
+                // Finally, set the flag that prevents the screen from turning on.
+                // (Below, in setPowerState(), we'll check mPreventScreenOn and
+                // we *won't* call Power.setScreenState(true) if it's set.)
+                mPreventScreenOn = true;
+            } else {
+                // (Re)enable the screen.
+                mPreventScreenOn = false;
+
+                // We're "undoing" a the prior preventScreenOn(true) call, so we
+                // no longer need the 5-second safeguard.
+                mHandler.removeCallbacks(mForceReenableScreenTask);
+
+                // Forcibly turn on the screen if it's supposed to be on.  (This
+                // handles the case where the screen is currently off because of
+                // a prior preventScreenOn(true) call.)
+                if ((mPowerState & SCREEN_ON_BIT) != 0) {
+                    if (mSpew) {
+                        Log.d(TAG,
+                              "preventScreenOn: turning on after a prior preventScreenOn(true)!");
+                    }
+                    int err = Power.setScreenState(true);
+                    if (err != 0) {
+                        Log.w(TAG, "preventScreenOn: error from Power.setScreenState(): " + err);
+                    }
+                }
+
+                // Release the partial wake lock that we held during the
+                // preventScreenOn(true) -> preventScreenOn(false) sequence.
+                mPreventScreenOnPartialLock.release();
+            }
+        }
+    }
+
+    /**
+     * Sanity-check that gets called 5 seconds after any call to
+     * preventScreenOn(true).  This ensures that the original call
+     * is followed promptly by a call to preventScreenOn(false).
+     */
+    private void forceReenableScreen() {
+        // We shouldn't get here at all if mPreventScreenOn is false, since
+        // we should have already removed any existing
+        // mForceReenableScreenTask messages...
+        if (!mPreventScreenOn) {
+            Log.w(TAG, "forceReenableScreen: mPreventScreenOn is false, nothing to do");
+            return;
+        }
+
+        // Uh oh.  It's been 5 seconds since a call to
+        // preventScreenOn(true) and we haven't re-enabled the screen yet.
+        // This means the app that called preventScreenOn(true) is either
+        // slow (i.e. it took more than 5 seconds to call preventScreenOn(false)),
+        // or buggy (i.e. it forgot to call preventScreenOn(false), or
+        // crashed before doing so.)
+
+        // Log a warning, and forcibly turn the screen back on.
+        Log.w(TAG, "App called preventScreenOn(true) but didn't promptly reenable the screen! "
+              + "Forcing the screen back on...");
+        preventScreenOn(false);
+    }
+
+    private Runnable mForceReenableScreenTask = new Runnable() {
+            public void run() {
+                forceReenableScreen();
+            }
+        };
+
     private void setPowerState(int state)
     {
         setPowerState(state, false, false);
@@ -1096,7 +1213,31 @@
 
             if (oldScreenOn != newScreenOn) {
                 if (newScreenOn) {
-                    err = Power.setScreenState(true);
+                    // Turn on the screen UNLESS there was a prior
+                    // preventScreenOn(true) request.  (Note that the lifetime
+                    // of a single preventScreenOn() request is limited to 5
+                    // seconds to prevent a buggy app from disabling the
+                    // screen forever; see forceReenableScreen().)
+                    boolean reallyTurnScreenOn = true;
+                    if (mSpew) {
+                        Log.d(TAG, "- turning screen on...  mPreventScreenOn = "
+                              + mPreventScreenOn);
+                    }
+
+                    if (mPreventScreenOn) {
+                        if (mSpew) {
+                            Log.d(TAG, "- PREVENTING screen from really turning on!");
+                        }
+                        reallyTurnScreenOn = false;
+                    }
+                    if (reallyTurnScreenOn) {
+                        err = Power.setScreenState(true);
+                    } else {
+                        Power.setScreenState(false);
+                        // But continue as if we really did turn the screen on...
+                        err = 0;
+                    }
+
                     mScreenOnStartTime = SystemClock.elapsedRealtime();
                     mLastTouchDown = 0;
                     mTotalTouchDownTime = 0;
diff --git a/services/java/com/android/server/Watchdog.java b/services/java/com/android/server/Watchdog.java
index 70c3110..fef3598 100644
--- a/services/java/com/android/server/Watchdog.java
+++ b/services/java/com/android/server/Watchdog.java
@@ -36,6 +36,7 @@
 import android.util.EventLog;
 import android.util.Log;
 
+import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Calendar;
 
@@ -43,13 +44,13 @@
 public class Watchdog extends Thread {
     static final String TAG = "Watchdog";
     static final boolean localLOGV = false || Config.LOGV;
-    
+
     // Set this to true to use debug default values.
     static final boolean DB = false;
-    
+
     static final int MONITOR = 2718;
     static final int GLOBAL_PSS = 2719;
-    
+
     static final int TIME_TO_WAIT = DB ? 15*1000 : 60*1000;
     static final int EVENT_LOG_TAG = 2802;
     static final int EVENT_LOG_PROC_PSS_TAG = 2803;
@@ -61,29 +62,29 @@
     static final int EVENT_LOG_MEMINFO_TAG = 2809;
     static final int EVENT_LOG_VMSTAT_TAG = 2810;
     static final int EVENT_LOG_REQUESTED_REBOOT_TAG = 2811;
-    
+
     static final int MEMCHECK_DEFAULT_INTERVAL = DB ? 30 : 30*60; // 30 minutes
     static final int MEMCHECK_DEFAULT_LOG_REALTIME_INTERVAL = DB ? 60 : 2*60*60;      // 2 hours
     static final int MEMCHECK_DEFAULT_SYSTEM_SOFT_THRESHOLD = (DB ? 10:16)*1024*1024; // 16MB
     static final int MEMCHECK_DEFAULT_SYSTEM_HARD_THRESHOLD = (DB ? 14:20)*1024*1024; // 20MB
     static final int MEMCHECK_DEFAULT_PHONE_SOFT_THRESHOLD = (DB ? 4:8)*1024*1024;    // 8MB
     static final int MEMCHECK_DEFAULT_PHONE_HARD_THRESHOLD = (DB ? 8:12)*1024*1024;   // 12MB
-    
+
     static final int MEMCHECK_DEFAULT_EXEC_START_TIME = 1*60*60;           // 1:00am
     static final int MEMCHECK_DEFAULT_EXEC_END_TIME = 5*60*60;             // 5:00am
     static final int MEMCHECK_DEFAULT_MIN_SCREEN_OFF = DB ? 1*60 : 5*60;   // 5 minutes
     static final int MEMCHECK_DEFAULT_MIN_ALARM = DB ? 1*60 : 3*60;        // 3 minutes
     static final int MEMCHECK_DEFAULT_RECHECK_INTERVAL = DB ? 1*60 : 5*60; // 5 minutes
-    
+
     static final int REBOOT_DEFAULT_INTERVAL = DB ? 1 : 0;                 // never force reboot
     static final int REBOOT_DEFAULT_START_TIME = 3*60*60;                  // 3:00am
     static final int REBOOT_DEFAULT_WINDOW = 60*60;                        // within 1 hour
-    
+
     static final String CHECKUP_ACTION = "com.android.service.Watchdog.CHECKUP";
     static final String REBOOT_ACTION = "com.android.service.Watchdog.REBOOT";
-    
+
     static Watchdog sWatchdog;
-    
+
     /* This handler will be used to post message back onto the main thread */
     final Handler mHandler;
     final Runnable mGlobalPssCollected;
@@ -96,11 +97,11 @@
     boolean mCompleted;
     boolean mForceKillSystem;
     Monitor mCurrentMonitor;
-    
+
     PssRequestor mPhoneReq;
     int mPhonePid;
     int mPhonePss;
-    
+
     long mLastMemCheckTime = -(MEMCHECK_DEFAULT_INTERVAL*1000);
     boolean mHavePss;
     long mLastMemCheckRealtime = -(MEMCHECK_DEFAULT_LOG_REALTIME_INTERVAL*1000);
@@ -117,7 +118,7 @@
             MEMCHECK_DEFAULT_PHONE_SOFT_THRESHOLD,
             Settings.Gservices.MEMCHECK_PHONE_HARD_THRESHOLD,
             MEMCHECK_DEFAULT_PHONE_HARD_THRESHOLD);
-    
+
     final Calendar mCalendar = Calendar.getInstance();
     long mMemcheckLastTime;
     long mMemcheckExecStartTime;
@@ -127,10 +128,10 @@
     boolean mNeedScheduledCheck;
     PendingIntent mCheckupIntent;
     PendingIntent mRebootIntent;
-    
+
     long mBootTime;
     int mRebootInterval;
-    
+
     boolean mReqRebootNoWait;     // should wait for one interval before reboot?
     int mReqRebootInterval = -1;  // >= 0 if a reboot has been requested
     int mReqRebootStartTime = -1; // >= 0 if a specific start time has been requested
@@ -138,7 +139,7 @@
     int mReqMinScreenOff = -1;    // >= 0 if a specific screen off time has been requested
     int mReqMinNextAlarm = -1;    // >= 0 if specific time to next alarm has been requested
     int mReqRecheckInterval= -1;  // >= 0 if a specific recheck interval has been requested
-    
+
     /**
      * This class monitors the memory in a particular process.
      */
@@ -147,17 +148,17 @@
         final String mEnabledSetting;
         final String mSoftSetting;
         final String mHardSetting;
-        
+
         int mSoftThreshold;
         int mHardThreshold;
         boolean mEnabled;
         long mLastPss;
-        
+
         static final int STATE_OK = 0;
         static final int STATE_SOFT = 1;
         static final int STATE_HARD = 2;
         int mState;
-        
+
         MemMonitor(String processName, String enabledSetting,
                 String softSetting, int defSoftThreshold,
                 String hardSetting, int defHardThreshold) {
@@ -168,7 +169,7 @@
             mSoftThreshold = defSoftThreshold;
             mHardThreshold = defHardThreshold;
         }
-        
+
         void retrieveSettings(ContentResolver resolver) {
             mSoftThreshold = Settings.Gservices.getInt(
                     resolver, mSoftSetting, mSoftThreshold);
@@ -177,7 +178,7 @@
             mEnabled = Settings.Gservices.getInt(
                     resolver, mEnabledSetting, 0) != 0;
         }
-        
+
         boolean checkLocked(long curTime, int pid, int pss) {
             mLastPss = pss;
             if (mLastPss < mSoftThreshold) {
@@ -188,19 +189,19 @@
                 mState = STATE_HARD;
             }
             EventLog.writeEvent(EVENT_LOG_PROC_PSS_TAG, mProcessName, pid, mLastPss);
-            
+
             if (mState == STATE_OK) {
                 // Memory is good, don't recover.
                 return false;
             }
-            
+
             if (mState == STATE_HARD) {
                 // Memory is really bad, kill right now.
                 EventLog.writeEvent(EVENT_LOG_HARD_RESET_TAG, mProcessName, pid,
                         mHardThreshold, mLastPss);
                 return mEnabled;
             }
-            
+
             // It is time to schedule a reset...
             // Check if we are currently within the time to kill processes due
             // to memory use.
@@ -219,13 +220,13 @@
             }
             return mEnabled;
         }
-        
+
         void clear() {
             mLastPss = 0;
             mState = STATE_OK;
         }
     }
-    
+
     /**
      * Used for scheduling monitor callbacks and checking memory usage.
      */
@@ -242,7 +243,7 @@
                         logGlobalMemory();
                     }
                 } break;
-                
+
                 case MONITOR: {
                     if (mHavePss) {
                         // During the last pass we collected pss information, so
@@ -251,7 +252,7 @@
                         if (localLOGV) Log.v(TAG, "Have pss, checking memory.");
                         checkMemory();
                     }
-                    
+
                     if (mHaveGlobalPss) {
                         // During the last pass we collected pss information, so
                         // now it is time to report it.
@@ -259,9 +260,9 @@
                         if (localLOGV) Log.v(TAG, "Have global pss, logging.");
                         logGlobalMemory();
                     }
-                    
+
                     long now = SystemClock.uptimeMillis();
-                    
+
                     // See if we should force a reboot.
                     int rebootInterval = mReqRebootInterval >= 0
                             ? mReqRebootInterval : Settings.Gservices.getInt(
@@ -273,7 +274,7 @@
                         // be considered...
                         checkReboot(false);
                     }
-                    
+
                     // See if we should check memory conditions.
                     long memCheckInterval = Settings.Gservices.getLong(
                             mResolver, Settings.Gservices.MEMCHECK_INTERVAL,
@@ -287,7 +288,7 @@
                         if (localLOGV) Log.v(TAG, "Collecting memory usage.");
                         collectMemory();
                         mHavePss = true;
-                        
+
                         long memCheckRealtimeInterval = Settings.Gservices.getLong(
                                 mResolver, Settings.Gservices.MEMCHECK_LOG_REALTIME_INTERVAL,
                                 MEMCHECK_DEFAULT_LOG_REALTIME_INTERVAL) * 1000;
@@ -299,13 +300,13 @@
                             mHaveGlobalPss = true;
                         }
                     }
-                    
+
                     final int size = mMonitors.size();
                     for (int i = 0 ; i < size ; i++) {
                         mCurrentMonitor = mMonitors.get(i);
                         mCurrentMonitor.monitor();
                     }
-                    
+
                     synchronized (Watchdog.this) {
                         mCompleted = true;
                         mCurrentMonitor = null;
@@ -320,7 +321,7 @@
             mHandler.sendEmptyMessage(GLOBAL_PSS);
         }
     }
-    
+
     final class CheckupReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context c, Intent intent) {
@@ -328,7 +329,7 @@
             checkMemory();
         }
     }
-    
+
     final class RebootReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context c, Intent intent) {
@@ -336,7 +337,7 @@
             checkReboot(true);
         }
     }
-    
+
     final class RebootRequestReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context c, Intent intent) {
@@ -354,15 +355,15 @@
             checkReboot(true);
         }
     }
-    
+
     public interface Monitor {
         void monitor();
     }
-    
+
     public interface PssRequestor {
         void requestPss();
     }
-    
+
     public class PssStats {
         public int mEmptyPss;
         public int mEmptyCount;
@@ -374,20 +375,20 @@
         public int mVisibleCount;
         public int mForegroundPss;
         public int mForegroundCount;
-        
+
         public int mNoPssCount;
-        
+
         public int mProcDeaths[] = new int[10];
     }
-    
+
     public static Watchdog getInstance() {
         if (sWatchdog == null) {
             sWatchdog = new Watchdog();
         }
-        
+
         return sWatchdog;
     }
-    
+
     private Watchdog() {
         super("watchdog");
         mHandler = new HeartbeatHandler();
@@ -402,24 +403,24 @@
         mPower = power;
         mAlarm = alarm;
         mActivity = activity;
-        
+
         context.registerReceiver(new CheckupReceiver(),
                 new IntentFilter(CHECKUP_ACTION));
         mCheckupIntent = PendingIntent.getBroadcast(context,
                 0, new Intent(CHECKUP_ACTION), 0);
-        
+
         context.registerReceiver(new RebootReceiver(),
                 new IntentFilter(REBOOT_ACTION));
         mRebootIntent = PendingIntent.getBroadcast(context,
                 0, new Intent(REBOOT_ACTION), 0);
-        
+
         context.registerReceiver(new RebootRequestReceiver(),
                 new IntentFilter(Intent.ACTION_REBOOT),
                 android.Manifest.permission.REBOOT, null);
-        
+
         mBootTime = System.currentTimeMillis();
     }
-    
+
     public void processStarted(PssRequestor req, String name, int pid) {
         synchronized (this) {
             if ("com.android.phone".equals(name)) {
@@ -429,7 +430,7 @@
             }
         }
     }
-    
+
     public void reportPss(PssRequestor req, String name, int pss) {
         synchronized (this) {
             if (mPhoneReq == req) {
@@ -437,7 +438,7 @@
             }
         }
     }
-    
+
     public void addMonitor(Monitor monitor) {
         synchronized (this) {
             if (isAlive()) {
@@ -459,7 +460,7 @@
             }
         }
     }
-    
+
     /**
      * Retrieve memory usage over all application processes.  This is an
      * async operation, so must be done before doing memory checks.
@@ -467,7 +468,7 @@
     void collectGlobalMemory() {
         mActivity.requestPss(mGlobalPssCollected);
     }
-    
+
     /**
      * Check memory usage in the system, scheduling kills/reboots as needed.
      * This always runs on the mHandler thread.
@@ -476,11 +477,11 @@
         boolean needScheduledCheck;
         long curTime;
         long nextTime = 0;
-        
+
         long recheckInterval = Settings.Gservices.getLong(
                 mResolver, Settings.Gservices.MEMCHECK_RECHECK_INTERVAL,
                 MEMCHECK_DEFAULT_RECHECK_INTERVAL) * 1000;
-        
+
         mSystemMemMonitor.retrieveSettings(mResolver);
         mPhoneMemMonitor.retrieveSettings(mResolver);
         retrieveBrutalityAmount();
@@ -488,7 +489,7 @@
         synchronized (this) {
             curTime = System.currentTimeMillis();
             mNeedScheduledCheck = false;
-            
+
             // How is the system doing?
             if (mSystemMemMonitor.checkLocked(curTime, Process.myPid(),
                     (int)Process.getPss(Process.myPid()))) {
@@ -497,7 +498,7 @@
                 notifyAll();
                 return;
             }
-            
+
             // How is the phone process doing?
             if (mPhoneReq != null) {
                 if (mPhoneMemMonitor.checkLocked(curTime, mPhonePid,
@@ -508,7 +509,7 @@
             } else {
                 mPhoneMemMonitor.clear();
             }
-            
+
             needScheduledCheck = mNeedScheduledCheck;
             if (needScheduledCheck) {
                 // Something is going bad, but now is not a good time to
@@ -523,14 +524,14 @@
                     computeMemcheckTimesLocked(nextTime);
                     nextTime = mMemcheckExecStartTime;
                 }
-                
+
                 if (localLOGV) {
                     mCalendar.setTimeInMillis(nextTime);
                     Log.v(TAG, "Next Alarm Time: " + mCalendar);
                 }
             }
         }
-        
+
         if (needScheduledCheck) {
             if (localLOGV) Log.v(TAG, "Scheduling next memcheck alarm for "
                     + ((nextTime-curTime)/1000/60) + "m from now");
@@ -555,7 +556,7 @@
     final long[] mVMStatSizes = new long[mVMStatFields.length];
     final long[] mPrevVMStatSizes = new long[mVMStatFields.length];
     long mLastLogGlobalMemoryTime;
-    
+
     void logGlobalMemory() {
         PssStats stats = mPssStats;
         mActivity.collectPss(stats);
@@ -591,7 +592,7 @@
                 (int)mVMStatSizes[0], (int)mVMStatSizes[1], (int)mVMStatSizes[2],
                 (int)mVMStatSizes[3], (int)mVMStatSizes[4]);
     }
-    
+
     void checkReboot(boolean fromAlarm) {
         int rebootInterval = mReqRebootInterval >= 0 ? mReqRebootInterval
                 : Settings.Gservices.getInt(
@@ -604,7 +605,7 @@
             mAlarm.remove(mRebootIntent);
             return;
         }
-        
+
         long rebootStartTime = mReqRebootStartTime >= 0 ? mReqRebootStartTime
                 : Settings.Gservices.getLong(
                 mResolver, Settings.Gservices.REBOOT_START_TIME,
@@ -617,17 +618,17 @@
                 : Settings.Gservices.getLong(
                 mResolver, Settings.Gservices.MEMCHECK_RECHECK_INTERVAL,
                 MEMCHECK_DEFAULT_RECHECK_INTERVAL)) * 1000;
-        
+
         retrieveBrutalityAmount();
-        
+
         long realStartTime;
         long now;
-        
+
         synchronized (this) {
             now = System.currentTimeMillis();
             realStartTime = computeCalendarTime(mCalendar, now,
                     rebootStartTime);
-            
+
             long rebootIntervalMillis = rebootInterval*24*60*60*1000;
             if (DB || mReqRebootNoWait ||
                     (now-mBootTime) >= (rebootIntervalMillis-rebootWindowMillis)) {
@@ -639,7 +640,7 @@
                     rebootSystem("Checkin scheduled forced");
                     return;
                 }
-                
+
                 // Are we within the reboot window?
                 if (now < realStartTime) {
                     // Schedule alarm for next check interval.
@@ -654,7 +655,7 @@
                         rebootSystem("Checked scheduled range");
                         return;
                     }
-                    
+
                     // Schedule next alarm either within the window or in the
                     // next interval.
                     if ((now+recheckInterval) >= (realStartTime+rebootWindowMillis)) {
@@ -670,21 +671,25 @@
                 }
             }
         }
-        
+
         if (localLOGV) Log.v(TAG, "Scheduling next reboot alarm for "
                 + ((realStartTime-now)/1000/60) + "m from now");
         mAlarm.remove(mRebootIntent);
         mAlarm.set(AlarmManager.RTC_WAKEUP, realStartTime, mRebootIntent);
     }
-    
+
     /**
      * Perform a full reboot of the system.
      */
     void rebootSystem(String reason) {
         Log.i(TAG, "Rebooting system because: " + reason);
-        android.os.Power.reboot(reason);
+        try {
+            android.os.Power.reboot(reason);
+        } catch (IOException e) {
+            Log.e(TAG, "Reboot failed!", e);
+        }
     }
-    
+
     /**
      * Load the current Gservices settings for when
      * {@link #shouldWeBeBrutalLocked} will allow the brutality to happen.
@@ -700,12 +705,12 @@
                 mResolver, Settings.Gservices.MEMCHECK_MIN_ALARM,
                 MEMCHECK_DEFAULT_MIN_ALARM)) * 1000;
     }
-    
+
     /**
      * Determine whether it is a good time to kill, crash, or otherwise
      * plunder the current situation for the overall long-term benefit of
      * the world.
-     * 
+     *
      * @param curTime The current system time.
      * @return Returns null if this is a good time, else a String with the
      * text of why it is not a good time.
@@ -714,40 +719,40 @@
         if (mBattery == null || !mBattery.isPowered()) {
             return "battery";
         }
-        
+
         if (mMinScreenOff >= 0 && (mPower == null ||
                 mPower.timeSinceScreenOn() < mMinScreenOff)) {
             return "screen";
         }
-            
+
         if (mMinAlarm >= 0 && (mAlarm == null ||
                 mAlarm.timeToNextAlarm() < mMinAlarm)) {
             return "alarm";
         }
-            
+
         return null;
     }
-    
+
     /**
      * Compute the times during which we next would like to perform process
      * restarts.
-     * 
+     *
      * @param curTime The current system time.
      */
     void computeMemcheckTimesLocked(long curTime) {
         if (mMemcheckLastTime == curTime) {
             return;
         }
-        
+
         mMemcheckLastTime = curTime;
-        
+
         long memcheckExecStartTime = Settings.Gservices.getLong(
                 mResolver, Settings.Gservices.MEMCHECK_EXEC_START_TIME,
                 MEMCHECK_DEFAULT_EXEC_START_TIME);
         long memcheckExecEndTime = Settings.Gservices.getLong(
                 mResolver, Settings.Gservices.MEMCHECK_EXEC_END_TIME,
                 MEMCHECK_DEFAULT_EXEC_END_TIME);
-        
+
         mMemcheckExecEndTime = computeCalendarTime(mCalendar, curTime,
                 memcheckExecEndTime);
         if (mMemcheckExecEndTime < curTime) {
@@ -758,7 +763,7 @@
         }
         mMemcheckExecStartTime = computeCalendarTime(mCalendar, curTime,
                 memcheckExecStartTime);
-        
+
         if (localLOGV) {
             mCalendar.setTimeInMillis(curTime);
             Log.v(TAG, "Current Time: " + mCalendar);
@@ -768,7 +773,7 @@
             Log.v(TAG, "End Check Time: " + mCalendar);
         }
     }
-    
+
     static long computeCalendarTime(Calendar c, long curTime,
             long secondsSinceMidnight) {
 
@@ -782,7 +787,7 @@
         c.set(Calendar.MINUTE, val);
         c.set(Calendar.SECOND, (int)secondsSinceMidnight - (val*60));
         c.set(Calendar.MILLISECOND, 0);
-        
+
         long newTime = c.getTimeInMillis();
         if (newTime < curTime) {
             // The given time (in seconds since midnight) has already passed for today, so advance
@@ -790,19 +795,19 @@
             c.add(Calendar.DAY_OF_MONTH, 1);
             newTime = c.getTimeInMillis();
         }
-            
+
         return newTime;
     }
-    
+
     @Override
     public void run() {
         while (true) {
             mCompleted = false;
             mHandler.sendEmptyMessage(MONITOR);
-            
+
             synchronized (this) {
                 long timeout = TIME_TO_WAIT;
-                
+
                 // NOTE: We use uptimeMillis() here because we do not want to increment the time we
                 // wait while asleep. If the device is asleep then the thing that we are waiting
                 // to timeout on is asleep as well and won't have a chance to run. Causing a false
@@ -827,22 +832,22 @@
                     continue;
                 }
             }
-        
-            // If we got here, that means that the system is most likely hung. 
-            // First send a SIGQUIT so that we can see where it was hung. Then 
+
+            // If we got here, that means that the system is most likely hung.
+            // First send a SIGQUIT so that we can see where it was hung. Then
             // kill this process so that the system will restart.
             String name = (mCurrentMonitor != null) ? mCurrentMonitor.getClass().getName() : "null";
             EventLog.writeEvent(EVENT_LOG_TAG, name);
             Process.sendSignal(Process.myPid(), Process.SIGNAL_QUIT);
-            
+
             // Wait a bit longer before killing so we can make sure that the stacks are captured.
             try {
                 Thread.sleep(10*1000);
             } catch (InterruptedException e) {
             }
-            
+
             // Only kill the process if the debugger is not attached.
-            if (!Debug.isDebuggerConnected()) { 
+            if (!Debug.isDebuggerConnected()) {
                 Process.killProcess(Process.myPid());
             }
         }
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index 7a0deff..f2483ff 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -47,7 +47,6 @@
 import android.os.Message;
 import android.os.PowerManager;
 import android.os.RemoteException;
-import android.os.BatteryManager;
 import android.provider.Settings;
 import android.util.Log;
 import android.text.TextUtils;
@@ -67,7 +66,7 @@
  * the IWifiManager interface. It also creates a WifiMonitor to listen
  * for Wifi-related events.
  *
- * {@hide}
+ * @hide
  */
 public class WifiService extends IWifiManager.Stub {
     private static final String TAG = "WifiService";
@@ -106,9 +105,9 @@
     private static final int DEFAULT_WAKELOCK_TIMEOUT = 8000;
 
     // Wake lock used by driver-stop operation
-    private static PowerManager.WakeLock mDriverStopWakeLock;
+    private static PowerManager.WakeLock sDriverStopWakeLock;
     // Wake lock used by other operations
-    private static PowerManager.WakeLock mWakeLock;
+    private static PowerManager.WakeLock sWakeLock;
 
     private static final int MESSAGE_ENABLE_WIFI      = 0;
     private static final int MESSAGE_DISABLE_WIFI     = 1;
@@ -116,7 +115,7 @@
     private static final int MESSAGE_START_WIFI       = 3;
     private static final int MESSAGE_RELEASE_WAKELOCK = 4;
 
-    private WifiHandler mWifiHandler;
+    private final  WifiHandler mWifiHandler;
 
     /*
      * Map used to keep track of hidden networks presence, which
@@ -197,17 +196,17 @@
         mIdleIntent = PendingIntent.getBroadcast(mContext, IDLE_REQUEST, idleIntent, 0);
 
         PowerManager powerManager = (PowerManager)mContext.getSystemService(Context.POWER_SERVICE);
-        mWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG);
-        mDriverStopWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG);
+        sWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG);
+        sDriverStopWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKELOCK_TAG);
         mWifiStateTracker.setReleaseWakeLockCallback(
                 new Runnable() {
                     public void run() {
                         mWifiHandler.removeMessages(MESSAGE_RELEASE_WAKELOCK);
-                        synchronized (mDriverStopWakeLock) {
-                            if (mDriverStopWakeLock.isHeld()) {
+                        synchronized (sDriverStopWakeLock) {
+                            if (sDriverStopWakeLock.isHeld()) {
                                 if (DBG) Log.d(TAG, "Releasing driver-stop wakelock " +
-                                        mDriverStopWakeLock);
-                                mDriverStopWakeLock.release();
+                                        sDriverStopWakeLock);
+                                sDriverStopWakeLock.release();
                             }
                         }
                     }
@@ -435,7 +434,7 @@
          * before adding a new one
          */
         synchronized (mWifiHandler) {
-            mWakeLock.acquire();
+            sWakeLock.acquire();
             sendEnableMessage(enable, true);
         }
 
@@ -679,7 +678,7 @@
         if (!TextUtils.isEmpty(value)) {
             try {
                 config.priority = Integer.parseInt(value);
-            } catch (NumberFormatException e) {
+            } catch (NumberFormatException ignore) {
             }
         }
 
@@ -688,7 +687,7 @@
         if (!TextUtils.isEmpty(value)) {
             try {
                 config.hiddenSSID = Integer.parseInt(value) != 0;
-            } catch (NumberFormatException e) {
+            } catch (NumberFormatException ignore) {
             }
         }
 
@@ -697,7 +696,7 @@
         if (!TextUtils.isEmpty(value)) {
             try {
                 config.wepTxKeyIndex = Integer.parseInt(value);
-            } catch (NumberFormatException e) {
+            } catch (NumberFormatException ignore) {
             }
         }
 
@@ -823,7 +822,7 @@
             if (!TextUtils.isEmpty(priorityVal)) {
                 try {
                     currentPriority = Integer.parseInt(priorityVal);
-                } catch (NumberFormatException e) {
+                } catch (NumberFormatException ignore) {
                 }
             }
             doReconfig = currentPriority != config.priority;
@@ -1473,7 +1472,7 @@
                 /*
                  * Set a timer to put Wi-Fi to sleep, but only if the screen is off
                  * AND we are transitioning from a state in which the device was supposed
-                 * to stay awake and a state in which it is not supposed to stay awake.
+                 * to stay awake to a state in which it is not supposed to stay awake.
                  * If "stay awake" state is not changing, we do nothing, to avoid resetting
                  * the already-set timer.
                  */
@@ -1499,7 +1498,7 @@
          * of {@code 0} isn't really a plugged type, but rather an indication that the
          * device isn't plugged in at all, there is no bit value corresponding to a
          * {@code pluggedType} value of {@code 0}. That is why we shift by
-         * {@code pluggedType&nbsp;&mdash;&nbsp;1} instead of by {@code pluggedType}.
+         * {@code pluggedType&nbsp;&#8212;&nbsp;1} instead of by {@code pluggedType}.
          * @param stayAwakeConditions a bit string specifying which "plugged types" should
          * keep the device (and hence Wi-Fi) awake.
          * @param pluggedType the type of plug (USB, AC, or none) for which the check is
@@ -1519,33 +1518,44 @@
         msg.sendToTarget();
     }
 
+    private void sendStartMessage(boolean scanOnlyMode) {
+        if (DBG) Log.d(TAG, "sendStartMessage(" + scanOnlyMode + ")");
+        Message.obtain(mWifiHandler, MESSAGE_START_WIFI, scanOnlyMode ? 1 : 0, 0).sendToTarget();
+    }
+
     private void updateWifiState() {
         boolean wifiEnabled = getPersistedWifiEnabled();
         boolean airplaneMode = isAirplaneModeOn();
         boolean lockHeld = mLocks.hasLocks();
+        int strongestLockMode;
 
         boolean wifiShouldBeEnabled = wifiEnabled && !airplaneMode;
         boolean wifiShouldBeStarted = !mDeviceIdle || lockHeld;
+        if (mDeviceIdle && lockHeld) {
+            strongestLockMode = mLocks.getStrongestLockMode();
+        } else {
+            strongestLockMode = WifiManager.WIFI_MODE_FULL;
+        }
 
         synchronized (mWifiHandler) {
             if (wifiShouldBeEnabled) {
                 if (wifiShouldBeStarted) {
-                    mWakeLock.acquire();
+                    sWakeLock.acquire();
                     sendEnableMessage(true, false);
-                    mWakeLock.acquire();
-                    mWifiHandler.sendEmptyMessage(MESSAGE_START_WIFI);
+                    sWakeLock.acquire();
+                    sendStartMessage(strongestLockMode == WifiManager.WIFI_MODE_SCAN_ONLY);
                 } else {
                     int wakeLockTimeout =
                             Settings.Secure.getInt(
                                     mContext.getContentResolver(),
                                     Settings.Secure.WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS,
                                     DEFAULT_WAKELOCK_TIMEOUT);
-                    mDriverStopWakeLock.acquire();
+                    sDriverStopWakeLock.acquire();
                     mWifiHandler.sendEmptyMessage(MESSAGE_STOP_WIFI);
                     mWifiHandler.sendEmptyMessageDelayed(MESSAGE_RELEASE_WAKELOCK, wakeLockTimeout);
                 }
             } else {
-                mWakeLock.acquire();
+                sWakeLock.acquire();
                 sendEnableMessage(false, false);
             }
         }
@@ -1590,37 +1600,36 @@
         public void handleMessage(Message msg) {
             switch (msg.what) {
 
-                case MESSAGE_ENABLE_WIFI: {
+                case MESSAGE_ENABLE_WIFI:
                     setWifiEnabledBlocking(true, msg.arg1 == 1);
-                    /* fall through */
-                }
-
-                case MESSAGE_START_WIFI: {
-                    mWifiStateTracker.startDriver();
-                    mWakeLock.release();
+                    sWakeLock.release();
                     break;
-                }
 
-                case MESSAGE_DISABLE_WIFI: {
+                case MESSAGE_START_WIFI:
+                    mWifiStateTracker.setScanOnlyMode(msg.arg1 != 0);
+                    mWifiStateTracker.restart();
+                    sWakeLock.release();
+                    break;
+
+                case MESSAGE_DISABLE_WIFI:
+                    // a non-zero msg.arg1 value means the "enabled" setting
+                    // should be persisted
                     setWifiEnabledBlocking(false, msg.arg1 == 1);
-                    mWakeLock.release();
+                    sWakeLock.release();
                     break;
-                }
 
-                case MESSAGE_STOP_WIFI: {
-                    mWifiStateTracker.stopDriver();
+                case MESSAGE_STOP_WIFI:
+                    mWifiStateTracker.disconnectAndStop();
                     // don't release wakelock
                     break;
-                }
 
-                case MESSAGE_RELEASE_WAKELOCK: {
-                    synchronized (mDriverStopWakeLock) {
-                        if (mDriverStopWakeLock.isHeld()) {
-                            mDriverStopWakeLock.release();
+                case MESSAGE_RELEASE_WAKELOCK:
+                    synchronized (sDriverStopWakeLock) {
+                        if (sDriverStopWakeLock.isHeld()) {
+                            sDriverStopWakeLock.release();
                         }
                     }
                     break;
-                }
             }
         }
     }
@@ -1653,6 +1662,9 @@
                                          r.SSID == null ? "" : r.SSID);
             }
         }
+        pw.println();
+        pw.println("Locks held:");
+        mLocks.dump(pw);
     }
 
     private static String stateName(int wifiState) {
@@ -1674,11 +1686,13 @@
 
     private class WifiLock implements IBinder.DeathRecipient {
         String mTag;
+        int mLockMode;
         IBinder mBinder;
 
-        WifiLock(String tag, IBinder binder) {
+        WifiLock(int lockMode, String tag, IBinder binder) {
             super();
             mTag = tag;
+            mLockMode = lockMode;
             mBinder = binder;
             try {
                 mBinder.linkToDeath(this, 0);
@@ -1694,30 +1708,40 @@
         }
 
         public String toString() {
-            return "WifiLock{" + mTag + " binder=" + mBinder + "}";
+            return "WifiLock{" + mTag + " type=" + mLockMode + " binder=" + mBinder + "}";
         }
     }
 
     private class LockList {
-        private ArrayList<WifiLock> mList;
+        private List<WifiLock> mList;
 
-        public LockList() {
+        private LockList() {
             mList = new ArrayList<WifiLock>();
         }
 
-        public boolean hasLocks() {
+        private synchronized boolean hasLocks() {
             return !mList.isEmpty();
         }
 
-        public void addLock(WifiLock lock) {
-            int index = findLockByBinder(lock.mBinder);
-            if (index < 0) {
+        private synchronized int getStrongestLockMode() {
+            if (mList.isEmpty()) {
+                return WifiManager.WIFI_MODE_FULL;
+            }
+            for (WifiLock l : mList) {
+                if (l.mLockMode == WifiManager.WIFI_MODE_FULL) {
+                    return WifiManager.WIFI_MODE_FULL;
+                }
+            }
+            return WifiManager.WIFI_MODE_SCAN_ONLY;
+        }
+
+        private void addLock(WifiLock lock) {
+            if (findLockByBinder(lock.mBinder) < 0) {
                 mList.add(lock);
-            } else {
             }
         }
 
-        public WifiLock removeLock(IBinder binder) {
+        private WifiLock removeLock(IBinder binder) {
             int index = findLockByBinder(binder);
             if (index >= 0) {
                 return mList.remove(index);
@@ -1733,11 +1757,28 @@
                     return i;
             return -1;
         }
+
+        private synchronized void clear() {
+            if (!mList.isEmpty()) {
+                mList.clear();
+                updateWifiState();
+            }
+        }
+
+        private void dump(PrintWriter pw) {
+            for (WifiLock l : mList) {
+                pw.print("    ");
+                pw.println(l);
+            }
+        }
     }
 
-    public boolean acquireWifiLock(IBinder binder, String tag) {
+    public boolean acquireWifiLock(IBinder binder, int lockMode, String tag) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.WAKE_LOCK, null);
-        WifiLock wifiLock = new WifiLock(tag, binder);
+        if (lockMode != WifiManager.WIFI_MODE_FULL && lockMode != WifiManager.WIFI_MODE_SCAN_ONLY) {
+            return false;
+        }
+        WifiLock wifiLock = new WifiLock(lockMode, tag, binder);
         synchronized (mLocks) {
             return acquireWifiLockLocked(wifiLock);
         }
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 6c58997f..d2149f1 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -9659,7 +9659,10 @@
         if (DEBUG_BROADCAST) Log.v(
             TAG, (sticky ? "Broadcast sticky: ": "Broadcast: ") + intent
             + " ordered=" + ordered);
-
+        if ((resultTo != null) && !ordered) {
+            Log.w(TAG, "Broadcast " + intent + " not ordered but result callback requested!");
+        }
+        
         // Handle special intents: if this broadcast is from the package
         // manager about a package being removed, we need to remove all of
         // its activities from the history stack.
diff --git a/services/java/com/android/server/am/PendingIntentRecord.java b/services/java/com/android/server/am/PendingIntentRecord.java
index 5de1e4b..b18aaf7 100644
--- a/services/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/java/com/android/server/am/PendingIntentRecord.java
@@ -208,10 +208,12 @@
                         break;
                     case IActivityManager.INTENT_SENDER_BROADCAST:
                         try {
+                            // If a completion callback has been requested, require
+                            // that the broadcast be delivered synchronously
                             owner.broadcastIntentInPackage(key.packageName, uid,
                                     finalIntent, resolvedType,
                                     finishedReceiver, code, null, null, null,
-                                    false, false);
+                                    (finishedReceiver != null), false);
                             sendFinish = false;
                         } catch (RuntimeException e) {
                             Log.w(ActivityManagerService.TAG,