Merge "Remove http/wml from the DumpRenderTree skipped list, as this directory no longer exists."
diff --git a/api/current.xml b/api/current.xml
index ed3f696..d792a41 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -5971,6 +5971,28 @@
  visibility="public"
 >
 </field>
+<field name="overscrollFooter"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843456"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="overscrollHeader"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="16843455"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
 <field name="overscrollMode"
  type="int"
  transient="false"
@@ -44348,7 +44370,7 @@
  synchronized="false"
  static="false"
  final="false"
- deprecated="not deprecated"
+ deprecated="deprecated"
  visibility="public"
 >
 <parameter name="filter" type="android.content.IntentFilter">
@@ -174601,6 +174623,19 @@
  visibility="public"
 >
 </method>
+<method name="getXVelocity"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="id" type="int">
+</parameter>
+</method>
 <method name="getYVelocity"
  return="float"
  abstract="false"
@@ -174612,6 +174647,19 @@
  visibility="public"
 >
 </method>
+<method name="getYVelocity"
+ return="float"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="id" type="int">
+</parameter>
+</method>
 <method name="obtain"
  return="android.view.VelocityTracker"
  abstract="false"
@@ -179390,6 +179438,17 @@
  visibility="public"
 >
 </method>
+<method name="getScaledPagingTouchSlop"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="getScaledScrollBarSize"
  return="int"
  abstract="false"
@@ -204520,6 +204579,28 @@
  visibility="public"
 >
 </method>
+<method name="getOverscrollFooter"
+ return="android.graphics.drawable.Drawable"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getOverscrollHeader"
+ return="android.graphics.drawable.Drawable"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
 <method name="isItemChecked"
  return="boolean"
  abstract="false"
@@ -204665,6 +204746,32 @@
 <parameter name="itemsCanFocus" type="boolean">
 </parameter>
 </method>
+<method name="setOverscrollFooter"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="footer" type="android.graphics.drawable.Drawable">
+</parameter>
+</method>
+<method name="setOverscrollHeader"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="header" type="android.graphics.drawable.Drawable">
+</parameter>
+</method>
 <method name="setSelection"
  return="void"
  abstract="false"
diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c
index c8d1397..654ee68 100644
--- a/cmds/installd/commands.c
+++ b/cmds/installd/commands.c
@@ -404,6 +404,15 @@
         }
     }
 
+        /* count the source apk as code -- but only if it's not
+         * installed on the sdcard
+         */
+    if (strncmp(apkpath, SDCARD_DIR_PREFIX, 7) != 0) {
+        if (stat(apkpath, &s) == 0) {
+            codesize += stat_size(&s);
+        }
+    }
+
 
         /* count the cached dexfile as code */
     if (!create_cache_path(path, apkpath)) {
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index 942a303..5e2c61e 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -232,7 +232,7 @@
     fprintf(stderr, "       -m max-number-of-frames-to-decode in each pass\n");
     fprintf(stderr, "       -b bug to reproduce\n");
     fprintf(stderr, "       -p(rofiles) dump decoder profiles supported\n");
-    fprintf(stderr, "       -t(humbnail) extract video thumbnail\n");
+    fprintf(stderr, "       -t(humbnail) extract video thumbnail or album art\n");
     fprintf(stderr, "       -s(oftware) prefer software codec\n");
 }
 
@@ -334,12 +334,24 @@
             const char *filename = argv[k];
 
             CHECK_EQ(retriever->setDataSource(filename), OK);
-            CHECK_EQ(retriever->setMode(METADATA_MODE_FRAME_CAPTURE_ONLY), OK);
+            CHECK_EQ(retriever->setMode(
+                        METADATA_MODE_FRAME_CAPTURE_AND_METADATA_RETRIEVAL),
+                     OK);
 
             sp<IMemory> mem = retriever->captureFrame();
 
-            printf("captureFrame(%s) => %s\n",
-                   filename, mem != NULL ? "OK" : "FAILED");
+            if (mem != NULL) {
+                printf("captureFrame(%s) => OK\n", filename);
+            } else {
+                mem = retriever->extractAlbumArt();
+
+                if (mem != NULL) {
+                    printf("extractAlbumArt(%s) => OK\n", filename);
+                } else {
+                    printf("both captureFrame and extractAlbumArt "
+                           "failed on file '%s'.\n", filename);
+                }
+            }
         }
 
         return 0;
diff --git a/core/java/android/accounts/AccountManagerService.java b/core/java/android/accounts/AccountManagerService.java
index 2aaf5b0..6d0a266 100644
--- a/core/java/android/accounts/AccountManagerService.java
+++ b/core/java/android/accounts/AccountManagerService.java
@@ -1071,8 +1071,20 @@
                 return;
             }
 
+            final IAccountAuthenticator accountAuthenticator = mAuthenticator;
+            if (accountAuthenticator == null) {
+                // It is possible that the authenticator has died, which is indicated by
+                // mAuthenticator being set to null. If this happens then just abort.
+                // There is no need to send back a result or error in this case since
+                // that already happened when mAuthenticator was cleared.
+                if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                    Log.v(TAG, "checkAccount: aborting session since we are no longer"
+                            + " connected to the authenticator, " + toDebugString());
+                }
+                return;
+            }
             try {
-                mAuthenticator.hasFeatures(this, mAccountsOfType[mCurrentAccount], mFeatures);
+                accountAuthenticator.hasFeatures(this, mAccountsOfType[mCurrentAccount], mFeatures);
             } catch (RemoteException e) {
                 onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "remote exception");
             }
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index 3e426f5..bf9b021 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -668,7 +668,10 @@
                 // The user changed the query, remember it.
                 mUserQuery = s == null ? "" : s.toString();
             }
-            updateVoiceButton(mSearchAutoComplete.isEmpty());
+            // Always want to show the microphone if the context is voice.
+            updateVoiceButton(mSearchAutoComplete.isEmpty()
+                    || (mAppSearchData != null && mAppSearchData.getBoolean(
+                    SearchManager.CONTEXT_IS_VOICE)));
         }
 
         public void afterTextChanged(Editable s) {
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index 0ed572a..625b120 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -1544,6 +1544,15 @@
     public final static String INTENT_ACTION_NONE = "android.search.action.ZILCH";
 
     /**
+     * This means that context is voice, and therefore the SearchDialog should
+     * continue showing the microphone until the user indicates that he/she does
+     * not want to re-speak (e.g. by typing).
+     *
+     * @hide
+     */
+    public final static String CONTEXT_IS_VOICE = "android.search.CONTEXT_IS_VOICE";
+
+    /**
      * Reference to the shared system search service.
      */
     private static ISearchManager mService;
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index bcef75e..d3cc4df 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -689,7 +689,7 @@
      * @param uri The URI to modify.
      * @param values The new field values. The key is the column name for the field.
                      A null value will remove an existing field value.
-     * @param where A filter to apply to rows before deleting, formatted as an SQL WHERE clause
+     * @param where A filter to apply to rows before updating, formatted as an SQL WHERE clause
                     (excluding the WHERE itself).
      * @return The number of rows updated.
      * @throws NullPointerException if uri or values are null
diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java
index 211a2ae..85769a6 100644
--- a/core/java/android/content/SyncManager.java
+++ b/core/java/android/content/SyncManager.java
@@ -124,6 +124,8 @@
      */
     private static final long ERROR_NOTIFICATION_DELAY_MS = 1000 * 60 * 10; // 10 minutes
 
+    private static final int INITIALIZATION_UNBIND_DELAY_MS = 5000;
+
     private static final String SYNC_WAKE_LOCK = "SyncManagerSyncWakeLock";
     private static final String HANDLE_SYNC_ALARM_WAKE_LOCK = "SyncManagerHandleSyncAlarmWakeLock";
 
@@ -283,6 +285,7 @@
 
     private static final String ACTION_SYNC_ALARM = "android.content.syncmanager.SYNC_ALARM";
     private final SyncHandler mSyncHandler;
+    private final Handler mMainHandler;
 
     private volatile boolean mBootCompleted = false;
 
@@ -309,6 +312,7 @@
                 Process.THREAD_PRIORITY_BACKGROUND);
         syncThread.start();
         mSyncHandler = new SyncHandler(syncThread.getLooper());
+        mMainHandler = new Handler(mContext.getMainLooper());
 
         mSyncAdapters = new SyncAdaptersCache(mContext);
         mSyncAdapters.setListener(new RegisteredServicesCacheListener<SyncAdapterType>() {
@@ -423,32 +427,56 @@
         Intent intent = new Intent();
         intent.setAction("android.content.SyncAdapter");
         intent.setComponent(syncAdapterInfo.componentName);
-        mContext.bindService(intent, new InitializerServiceConnection(account, authority),
+        mContext.bindService(intent, new InitializerServiceConnection(account, authority, mContext,
+                mMainHandler),
                 Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND);
     }
 
-    private class InitializerServiceConnection implements ServiceConnection {
+    private static class InitializerServiceConnection implements ServiceConnection {
         private final Account mAccount;
         private final String mAuthority;
+        private final Handler mHandler;
+        private volatile Context mContext;
+        private volatile boolean mInitialized;
 
-        public InitializerServiceConnection(Account account, String authority) {
+        public InitializerServiceConnection(Account account, String authority, Context context,
+                Handler handler) {
             mAccount = account;
             mAuthority = authority;
+            mContext = context;
+            mHandler = handler;
+            mInitialized = false;
         }
 
         public void onServiceConnected(ComponentName name, IBinder service) {
             try {
-                ISyncAdapter.Stub.asInterface(service).initialize(mAccount, mAuthority);
+                if (!mInitialized) {
+                    mInitialized = true;
+                    ISyncAdapter.Stub.asInterface(service).initialize(mAccount, mAuthority);
+                }
             } catch (RemoteException e) {
                 // doesn't matter, we will retry again later
             } finally {
-                mContext.unbindService(this);
+                // give the sync adapter time to initialize before unbinding from it
+                // TODO: change this API to not rely on this timing, http://b/2500805
+                mHandler.postDelayed(new Runnable() {
+                    public void run() {
+                        if (mContext != null) {
+                            mContext.unbindService(InitializerServiceConnection.this);
+                            mContext = null;
+                        }
+                    }
+                }, INITIALIZATION_UNBIND_DELAY_MS);
             }
         }
 
         public void onServiceDisconnected(ComponentName name) {
-            mContext.unbindService(this);
+            if (mContext != null) {
+                mContext.unbindService(InitializerServiceConnection.this);
+                mContext = null;
+            }
         }
+
     }
 
     /**
@@ -841,6 +869,7 @@
         ISyncAdapter mSyncAdapter;
         final long mStartTime;
         long mTimeoutStartTime;
+        boolean mBound;
 
         public ActiveSyncContext(SyncOperation syncOperation,
                 long historyRowId) {
@@ -895,15 +924,23 @@
                     com.android.internal.R.string.sync_binding_label);
             intent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity(
                     mContext, 0, new Intent(Settings.ACTION_SYNC_SETTINGS), 0));
-            return mContext.bindService(intent, this,
+            mBound = true;
+            final boolean bindResult = mContext.bindService(intent, this,
                     Context.BIND_AUTO_CREATE | Context.BIND_NOT_FOREGROUND);
+            if (!bindResult) {
+                mBound = false;
+            }
+            return bindResult;
         }
 
-        void unBindFromSyncAdapter() {
+        protected void close() {
             if (Log.isLoggable(TAG, Log.VERBOSE)) {
                 Log.d(TAG, "unBindFromSyncAdapter: connection " + this);
             }
-            mContext.unbindService(this);
+            if (mBound) {
+                mBound = false;
+                mContext.unbindService(this);
+            }
         }
 
         @Override
@@ -1580,6 +1617,7 @@
             mSyncStorageEngine.setActiveSync(mActiveSyncContext);
             if (!activeSyncContext.bindToSyncAdapter(syncAdapterInfo)) {
                 Log.e(TAG, "Bind attempt failed to " + syncAdapterInfo);
+                mActiveSyncContext.close();
                 mActiveSyncContext = null;
                 mSyncStorageEngine.setActiveSync(mActiveSyncContext);
                 runStateIdle();
@@ -1669,13 +1707,13 @@
                         syncOperation.account, syncOperation.extras);
             } catch (RemoteException remoteExc) {
                 Log.d(TAG, "runStateIdle: caught a RemoteException, rescheduling", remoteExc);
-                mActiveSyncContext.unBindFromSyncAdapter();
+                mActiveSyncContext.close();
                 mActiveSyncContext = null;
                 mSyncStorageEngine.setActiveSync(mActiveSyncContext);
                 increaseBackoffSetting(syncOperation);
                 scheduleSyncOperation(new SyncOperation(syncOperation));
             } catch (RuntimeException exc) {
-                mActiveSyncContext.unBindFromSyncAdapter();
+                mActiveSyncContext.close();
                 mActiveSyncContext = null;
                 mSyncStorageEngine.setActiveSync(mActiveSyncContext);
                 Log.e(TAG, "Caught RuntimeException while starting the sync " + syncOperation, exc);
@@ -1741,7 +1779,7 @@
             stopSyncEvent(activeSyncContext.mHistoryRowId, syncOperation, historyMessage,
                     upstreamActivity, downstreamActivity, elapsedTime);
 
-            activeSyncContext.unBindFromSyncAdapter();
+            activeSyncContext.close();
 
             if (syncResult != null && syncResult.tooManyDeletions) {
                 installHandleTooManyDeletesNotification(syncOperation.account,
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index 8773f59..423f4bc 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -237,7 +237,7 @@
      *
      * {@hide}
      */
-    public static final int FLAG_ON_SDCARD = 1<<20;
+    public static final int FLAG_EXTERNAL_STORAGE = 1<<20;
 
     /**
      * Value for {@link #flags}: Set to true if the application is
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index efd7bbc..271f477 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1896,6 +1896,10 @@
     public abstract List<PackageInfo> getPreferredPackages(int flags);
 
     /**
+     * @deprecated This is a protected API that should not have been available
+     * to third party applications.  It is the platform's responsibility for
+     * assigning preferred activities and this can not be directly modified.
+     * 
      * Add a new preferred activity mapping to the system.  This will be used
      * to automatically select the given activity component when
      * {@link Context#startActivity(Intent) Context.startActivity()} finds
@@ -1910,10 +1914,15 @@
      * @param activity The component name of the activity that is to be
      * preferred.
      */
+    @Deprecated
     public abstract void addPreferredActivity(IntentFilter filter, int match,
             ComponentName[] set, ComponentName activity);
 
     /**
+     * @deprecated This is a protected API that should not have been available
+     * to third party applications.  It is the platform's responsibility for
+     * assigning preferred activities and this can not be directly modified.
+     * 
      * Replaces an existing preferred activity mapping to the system, and if that were not present
      * adds a new preferred activity.  This will be used
      * to automatically select the given activity component when
@@ -1930,6 +1939,7 @@
      * preferred.
      * @hide
      */
+    @Deprecated
     public abstract void replacePreferredActivity(IntentFilter filter, int match,
             ComponentName[] set, ComponentName activity);
 
@@ -1937,6 +1947,7 @@
      * Remove all preferred activity mappings, previously added with
      * {@link #addPreferredActivity}, from the
      * system whose activities are implemented in the given package name.
+     * An application can only clear its own package(s).
      *
      * @param packageName The name of the package whose preferred activity
      * mappings are to be removed.
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 663d9e6..9736b01 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -1503,7 +1503,7 @@
         }
 
         if ((flags & PARSE_ON_SDCARD) != 0) {
-            ai.flags |= ApplicationInfo.FLAG_ON_SDCARD;
+            ai.flags |= ApplicationInfo.FLAG_EXTERNAL_STORAGE;
         }
 
         if (sa.getBoolean(
diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java
index b59e279..17b0330 100644
--- a/core/java/android/net/MobileDataStateTracker.java
+++ b/core/java/android/net/MobileDataStateTracker.java
@@ -346,7 +346,7 @@
                         ACTION_ANY_DATA_CONNECTION_STATE_CHANGED);
                 intent.putExtra(Phone.STATE_KEY, Phone.DataState.CONNECTED.toString());
                 intent.putExtra(Phone.STATE_CHANGE_REASON_KEY, Phone.REASON_APN_CHANGED);
-                intent.putExtra(Phone.DATA_APN_TYPES_KEY, mApnType);
+                intent.putExtra(Phone.DATA_APN_TYPES_KEY, mApnTypeToWatchFor);
                 intent.putExtra(Phone.DATA_APN_KEY, mApnName);
                 intent.putExtra(Phone.DATA_IFACE_NAME_KEY, mInterfaceName);
                 intent.putExtra(Phone.NETWORK_UNAVAILABLE_KEY, false);
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index fdde591..4995cac 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -29,6 +29,7 @@
 import android.content.Context;
 import android.content.IContentProvider;
 import android.content.Intent;
+import android.content.pm.ActivityInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.res.Configuration;
@@ -989,6 +990,11 @@
             return Settings.System.putFloat(cr, FONT_SCALE, config.fontScale);
         }
 
+        /** @hide */
+        public static boolean hasInterestingConfigurationChanges(int changes) {
+            return (changes&ActivityInfo.CONFIG_FONT_SCALE) != 0;
+        }
+        
         public static boolean getShowGTalkServiceStatus(ContentResolver cr) {
             return getInt(cr, SHOW_GTALK_SERVICE_STATUS, 0) != 0;
         }
@@ -1708,6 +1714,7 @@
             VOLUME_ALARM + APPEND_FOR_LAST_AUDIBLE,
             VOLUME_NOTIFICATION + APPEND_FOR_LAST_AUDIBLE,
             VOLUME_BLUETOOTH_SCO + APPEND_FOR_LAST_AUDIBLE,
+            VIBRATE_IN_SILENT,
             TEXT_AUTO_REPLACE,
             TEXT_AUTO_CAPS,
             TEXT_AUTO_PUNCTUATE,
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 600ec7e..f02ad2a 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -233,25 +233,25 @@
                 }
             }
 
-            if (!easy) {
-                // Ensure that none of the underlying characters are treated
-                // as viable breakpoints, and that the entire run gets the
-                // same bidi direction.
+            // Ensure that none of the underlying characters are treated
+            // as viable breakpoints, and that the entire run gets the
+            // same bidi direction.
 
-                if (source instanceof Spanned) {
-                    Spanned sp = (Spanned) source;
-                    ReplacementSpan[] spans = sp.getSpans(start, end, ReplacementSpan.class);
+            if (source instanceof Spanned) {
+                Spanned sp = (Spanned) source;
+                ReplacementSpan[] spans = sp.getSpans(start, end, ReplacementSpan.class);
 
-                    for (int y = 0; y < spans.length; y++) {
-                        int a = sp.getSpanStart(spans[y]);
-                        int b = sp.getSpanEnd(spans[y]);
+                for (int y = 0; y < spans.length; y++) {
+                    int a = sp.getSpanStart(spans[y]);
+                    int b = sp.getSpanEnd(spans[y]);
 
-                        for (int x = a; x < b; x++) {
-                            chs[x - start] = '\uFFFC';
-                        }
+                    for (int x = a; x < b; x++) {
+                        chs[x - start] = '\uFFFC';
                     }
                 }
+            }
 
+            if (!easy) {
                 // XXX put override flags, etc. into chdirs
                 dir = bidi(dir, chs, chdirs, n, false);
 
diff --git a/core/java/android/text/util/Rfc822Tokenizer.java b/core/java/android/text/util/Rfc822Tokenizer.java
index 69d745d..952d833 100644
--- a/core/java/android/text/util/Rfc822Tokenizer.java
+++ b/core/java/android/text/util/Rfc822Tokenizer.java
@@ -74,7 +74,7 @@
 
                 name.setLength(0);
                 address.setLength(0);
-                address.setLength(0);
+                comment.setLength(0);
             } else if (c == '"') {
                 i++;
 
diff --git a/core/java/android/view/VelocityTracker.java b/core/java/android/view/VelocityTracker.java
index c17a724..aab76c4 100644
--- a/core/java/android/view/VelocityTracker.java
+++ b/core/java/android/view/VelocityTracker.java
@@ -259,8 +259,6 @@
      * 
      * @param id Which pointer's velocity to return.
      * @return The previously computed X velocity.
-     * 
-     * @hide Pending API approval
      */
     public float getXVelocity(int id) {
         return mXVelocity[id];
@@ -272,8 +270,6 @@
      * 
      * @param id Which pointer's velocity to return.
      * @return The previously computed Y velocity.
-     * 
-     * @hide Pending API approval
      */
     public float getYVelocity(int id) {
         return mYVelocity[id];
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index 2344c42..2b78d2d 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -102,6 +102,12 @@
     private static final int TOUCH_SLOP = 16;
     
     /**
+     * Distance a touch can wander before we think the user is attempting a paged scroll
+     * (in dips)
+     */
+    private static final int PAGING_TOUCH_SLOP = TOUCH_SLOP * 3;
+    
+    /**
      * Distance between the first touch and second touch to still be considered a double tap
      */
     private static final int DOUBLE_TAP_SLOP = 100;
@@ -140,6 +146,7 @@
     private final int mMaximumFlingVelocity;
     private final int mScrollbarSize;
     private final int mTouchSlop;
+    private final int mPagingTouchSlop;
     private final int mDoubleTapSlop;
     private final int mWindowTouchSlop;
     private final int mMaximumDrawingCacheSize;
@@ -158,6 +165,7 @@
         mMaximumFlingVelocity = MAXIMUM_FLING_VELOCITY;
         mScrollbarSize = SCROLL_BAR_SIZE;
         mTouchSlop = TOUCH_SLOP;
+        mPagingTouchSlop = PAGING_TOUCH_SLOP;
         mDoubleTapSlop = DOUBLE_TAP_SLOP;
         mWindowTouchSlop = WINDOW_TOUCH_SLOP;
         //noinspection deprecation
@@ -184,6 +192,7 @@
         mMaximumFlingVelocity = (int) (density * MAXIMUM_FLING_VELOCITY + 0.5f);
         mScrollbarSize = (int) (density * SCROLL_BAR_SIZE + 0.5f);
         mTouchSlop = (int) (density * TOUCH_SLOP + 0.5f);
+        mPagingTouchSlop = (int) (density * PAGING_TOUCH_SLOP + 0.5f);
         mDoubleTapSlop = (int) (density * DOUBLE_TAP_SLOP + 0.5f);
         mWindowTouchSlop = (int) (density * WINDOW_TOUCH_SLOP + 0.5f);
 
@@ -339,6 +348,14 @@
     public int getScaledTouchSlop() {
         return mTouchSlop;
     }
+    
+    /**
+     * @return Distance a touch can wander before we think the user is scrolling a full page
+     *         in dips
+     */
+    public int getScaledPagingTouchSlop() {
+        return mPagingTouchSlop;
+    }
 
     /**
      * @return Distance between the first touch and second touch to still be
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index ab3260e..b39cb9d 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -627,8 +627,9 @@
      * returned, all windows given to layoutWindow() <em>must</em> have had a
      * frame assigned.
      *  
-     * @return Return any bit set of {@link #FINISH_LAYOUT_REDO_LAYOUT}
-     * and {@link #FINISH_LAYOUT_REDO_CONFIG}.
+     * @return Return any bit set of {@link #FINISH_LAYOUT_REDO_LAYOUT},
+     * {@link #FINISH_LAYOUT_REDO_CONFIG}, {@link #FINISH_LAYOUT_REDO_WALLPAPER},
+     * or {@link #FINISH_LAYOUT_REDO_ANIM}.
      */
     public int finishLayoutLw();
 
@@ -638,6 +639,8 @@
     static final int FINISH_LAYOUT_REDO_CONFIG = 0x0002;
     /** Wallpaper may need to move */
     static final int FINISH_LAYOUT_REDO_WALLPAPER = 0x0004;
+    /** Need to recompute animations */
+    static final int FINISH_LAYOUT_REDO_ANIM = 0x0008;
     
     /**
      * Called when animation of the windows is about to start.
@@ -661,10 +664,11 @@
      * something that may have modified the animation state of another window, 
      * be sure to return true in order to perform another animation frame. 
      *  
-     * @return Return true if animation state may have changed (so that another 
-     *         frame of animation will be run).
+     * @return Return any bit set of {@link #FINISH_LAYOUT_REDO_LAYOUT},
+     * {@link #FINISH_LAYOUT_REDO_CONFIG}, {@link #FINISH_LAYOUT_REDO_WALLPAPER},
+     * or {@link #FINISH_LAYOUT_REDO_ANIM}.
      */
-    public boolean finishAnimationLw();
+    public int finishAnimationLw();
 
     /**
      * Return true if it is okay to perform animations for an app transition
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 6f6ee1d..6f2d070 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -2199,14 +2199,15 @@
     // Sets r to be our visible rectangle in content coordinates
     private void calcOurContentVisibleRect(Rect r) {
         calcOurVisibleRect(r);
-        r.left = viewToContentX(r.left);
+        // since we might overscroll, pin the rect to the bounds of the content
+        r.left = Math.max(viewToContentX(r.left), 0);
         // viewToContentY will remove the total height of the title bar.  Add
         // the visible height back in to account for the fact that if the title
         // bar is partially visible, the part of the visible rect which is
         // displaying our content is displaced by that amount.
-        r.top = viewToContentY(r.top + getVisibleTitleHeight());
-        r.right = viewToContentX(r.right);
-        r.bottom = viewToContentY(r.bottom);
+        r.top = Math.max(viewToContentY(r.top + getVisibleTitleHeight()), 0);
+        r.right = Math.min(viewToContentX(r.right), mContentWidth);
+        r.bottom = Math.min(viewToContentY(r.bottom), mContentHeight);
     }
 
     static class ViewSizeData {
diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java
index d4552e3..0594844 100644
--- a/core/java/android/widget/ListView.java
+++ b/core/java/android/widget/ListView.java
@@ -117,6 +117,9 @@
 
     Drawable mDivider;
     int mDividerHeight;
+    
+    Drawable mOverscrollHeader;
+    Drawable mOverscrollFooter;
 
     private boolean mIsCacheColorOpaque;
     private boolean mDividerIsOpaque;
@@ -171,6 +174,16 @@
             // If a divider is specified use its intrinsic height for divider height
             setDivider(d);
         }
+        
+        final Drawable osHeader = a.getDrawable(com.android.internal.R.styleable.ListView_overscrollHeader);
+        if (osHeader != null) {
+            setOverscrollHeader(osHeader);
+        }
+        
+        final Drawable osFooter = a.getDrawable(com.android.internal.R.styleable.ListView_overscrollFooter);
+        if (osFooter != null) {
+            setOverscrollFooter(osFooter);
+        }
 
         // Use the height specified, zero being the default
         final int dividerHeight = a.getDimensionPixelSize(
@@ -2934,12 +2947,51 @@
         super.setCacheColorHint(color);
     }
 
+    void drawOverscrollHeader(Canvas canvas, Drawable drawable, Rect bounds) {
+        final int height = drawable.getMinimumHeight();
+
+        canvas.save();
+        canvas.clipRect(bounds);
+
+        final int span = bounds.bottom - bounds.top;
+        if (span < height) {
+            bounds.top = bounds.bottom - height; 
+        }
+
+        drawable.setBounds(bounds);
+        drawable.draw(canvas);
+
+        canvas.restore();
+    }
+
+    void drawOverscrollFooter(Canvas canvas, Drawable drawable, Rect bounds) {
+        final int height = drawable.getMinimumHeight();
+
+        canvas.save();
+        canvas.clipRect(bounds);
+
+        final int span = bounds.bottom - bounds.top;
+        if (span < height) {
+            bounds.bottom = bounds.top + height;
+        }
+
+        drawable.setBounds(bounds);
+        drawable.draw(canvas);
+
+        canvas.restore();
+    }
+
     @Override
     protected void dispatchDraw(Canvas canvas) {
         // Draw the dividers
         final int dividerHeight = mDividerHeight;
+        final Drawable overscrollHeader = mOverscrollHeader;
+        final Drawable overscrollFooter = mOverscrollFooter;
+        final boolean drawOverscrollHeader = overscrollHeader != null;
+        final boolean drawOverscrollFooter = overscrollFooter != null;
+        final boolean drawDividers = dividerHeight > 0 && mDivider != null;
 
-        if (dividerHeight > 0 && mDivider != null) {
+        if (drawDividers || drawOverscrollHeader || drawOverscrollFooter) {
             // Only modify the top and bottom in the loop, we set the left and right here
             final Rect bounds = mTempRect;
             bounds.left = mPaddingLeft;
@@ -2947,7 +2999,8 @@
 
             final int count = getChildCount();
             final int headerCount = mHeaderViewInfos.size();
-            final int footerLimit = mItemCount - mFooterViewInfos.size() - 1;
+            final int itemCount = mItemCount;
+            final int footerLimit = itemCount - mFooterViewInfos.size() - 1;
             final boolean headerDividers = mHeaderDividersEnabled;
             final boolean footerDividers = mFooterDividersEnabled;
             final int first = mFirstPosition;
@@ -2957,7 +3010,7 @@
             // fill a rect where the dividers would be for non-selectable items
             // If the list is opaque and the background is also opaque, we don't
             // need to draw anything since the background will do it for us
-            final boolean fillForMissingDividers = isOpaque() && !super.isOpaque();
+            final boolean fillForMissingDividers = drawDividers && isOpaque() && !super.isOpaque();
 
             if (fillForMissingDividers && mDividerPaint == null && mIsCacheColorOpaque) {
                 mDividerPaint = new Paint();
@@ -2965,15 +3018,22 @@
             }
             final Paint paint = mDividerPaint;
 
+            final int listBottom = mBottom - mTop - mListPadding.bottom + mScrollY;
             if (!mStackFromBottom) {
-                int bottom;
-                int listBottom = mBottom - mTop - mListPadding.bottom + mScrollY;
+                int bottom = 0;
                 
-                // Draw top divider for overscroll
-                if (count > 0 && mScrollY < 0) {
-                    bounds.bottom = 0;
-                    bounds.top = -dividerHeight;
-                    drawDivider(canvas, bounds, -1);
+                // Draw top divider or header for overscroll
+                final int scrollY = mScrollY;
+                if (count > 0 && scrollY < 0) {
+                    if (drawOverscrollHeader) {
+                        bounds.bottom = 0;
+                        bounds.top = scrollY;
+                        drawOverscrollHeader(canvas, overscrollHeader, bounds);
+                    } else if (drawDividers) {
+                        bounds.bottom = 0;
+                        bounds.top = -dividerHeight;
+                        drawDivider(canvas, bounds, -1);
+                    }
                 }
 
                 for (int i = 0; i < count; i++) {
@@ -2982,7 +3042,8 @@
                         View child = getChildAt(i);
                         bottom = child.getBottom();
                         // Don't draw dividers next to items that are not enabled
-                        if (bottom < listBottom) {
+                        if (drawDividers &&
+                                (bottom < listBottom && !(drawOverscrollFooter && i == count - 1))) {
                             if ((areAllItemsSelectable ||
                                     (adapter.isEnabled(first + i) && (i == count - 1 ||
                                             adapter.isEnabled(first + i + 1))))) {
@@ -2997,17 +3058,34 @@
                         }
                     }
                 }
+                
+                final int overFooterBottom = mBottom + mScrollY;
+                if (drawOverscrollFooter && first + count == itemCount &&
+                        overFooterBottom > bottom) {
+                    bounds.top = bottom;
+                    bounds.bottom = overFooterBottom;
+                    drawOverscrollFooter(canvas, overscrollFooter, bounds);
+                }
             } else {
                 int top;
                 int listTop = mListPadding.top;
 
-                for (int i = 0; i < count; i++) {
+                final int scrollY = mScrollY;
+                
+                if (count > 0 && drawOverscrollHeader) {
+                    bounds.top = scrollY;
+                    bounds.bottom = getChildAt(0).getTop();
+                    drawOverscrollHeader(canvas, overscrollHeader, bounds);
+                }
+
+                final int start = drawOverscrollHeader ? 1 : 0;
+                for (int i = start; i < count; i++) {
                     if ((headerDividers || first + i >= headerCount) &&
                             (footerDividers || first + i < footerLimit)) {
                         View child = getChildAt(i);
                         top = child.getTop();
                         // Don't draw dividers next to items that are not enabled
-                        if (top > listTop) {
+                        if (drawDividers && top > listTop) {
                             if ((areAllItemsSelectable ||
                                     (adapter.isEnabled(first + i) && (i == count - 1 ||
                                             adapter.isEnabled(first + i + 1))))) {
@@ -3026,6 +3104,19 @@
                         }
                     }
                 }
+                
+                if (count > 0 && scrollY > 0) {
+                    if (drawOverscrollFooter) {
+                        final int absListBottom = mBottom;
+                        bounds.top = absListBottom;
+                        bounds.bottom = absListBottom + scrollY;
+                        drawOverscrollFooter(canvas, overscrollFooter, bounds);
+                    } else if (drawDividers) {
+                        bounds.top = listBottom;
+                        bounds.bottom = listBottom + dividerHeight;
+                        drawDivider(canvas, bounds, -1);
+                    }
+                }
             }
         }
 
@@ -3132,6 +3223,45 @@
         mFooterDividersEnabled = footerDividersEnabled;
         invalidate();
     }
+    
+    /**
+     * Sets the drawable that will be drawn above all other list content.
+     * This area can become visible when the user overscrolls the list.
+     * 
+     * @param header The drawable to use
+     */
+    public void setOverscrollHeader(Drawable header) {
+        mOverscrollHeader = header;
+        if (mScrollY < 0) {
+            invalidate();
+        }
+    }
+    
+    /**
+     * @return The drawable that will be drawn above all other list content
+     */
+    public Drawable getOverscrollHeader() {
+        return mOverscrollHeader;
+    }
+    
+    /**
+     * Sets the drawable that will be drawn below all other list content.
+     * This area can become visible when the user overscrolls the list,
+     * or when the list's content does not fully fill the container area.
+     * 
+     * @param footer The drawable to use
+     */
+    public void setOverscrollFooter(Drawable footer) {
+        mOverscrollFooter = footer;
+        invalidate();
+    }
+    
+    /**
+     * @return The drawable that will be drawn below all other list content
+     */
+    public Drawable getOverscrollFooter() {
+        return mOverscrollFooter;
+    }
 
     @Override
     protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) {
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 7b21be5..64c9c99 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -6989,6 +6989,10 @@
 
     @Override
     public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+        if (!isShown()) {
+            return false;
+        }
+
         final boolean isPassword = isPasswordInputType(mInputType);
 
         if (!isPassword) {
diff --git a/core/java/com/android/internal/content/PackageHelper.java b/core/java/com/android/internal/content/PackageHelper.java
index de6a175..80efca4 100644
--- a/core/java/com/android/internal/content/PackageHelper.java
+++ b/core/java/com/android/internal/content/PackageHelper.java
@@ -40,6 +40,10 @@
     public static final int RECOMMEND_FAILED_ALREADY_EXISTS = -4;
     private static final boolean localLOGV = true;
     private static final String TAG = "PackageHelper";
+    // App installation location settings values
+    public static final int APP_INSTALL_AUTO = 0;
+    public static final int APP_INSTALL_INTERNAL = 1;
+    public static final int APP_INSTALL_EXTERNAL = 2;
 
     public static IMountService getMountService() {
         IBinder service = ServiceManager.getService("mount");
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 9965fe5..b6f3997 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -331,12 +331,14 @@
 // i.e. dynamically allocated, since its lifetime may exceed the current stack
 // frame.
 static jobject doDecode(JNIEnv* env, SkStream* stream, jobject padding,
-                        jobject options, bool allowPurgeable) {
+                        jobject options, bool allowPurgeable,
+                        bool forcePurgeable = false) {
     int sampleSize = 1;
     SkImageDecoder::Mode mode = SkImageDecoder::kDecodePixels_Mode;
     SkBitmap::Config prefConfig = SkBitmap::kNo_Config;
     bool doDither = true;
-    bool isPurgeable = allowPurgeable && optionsPurgeable(env, options);
+    bool isPurgeable = forcePurgeable ||
+                        (allowPurgeable && optionsPurgeable(env, options));
     bool reportSizeToVM = optionsReportSizeToVM(env, options);
     
     if (NULL != options) {
@@ -568,8 +570,10 @@
                                  jobject options) { // BitmapFactory$Options
     SkStream* stream;
     Asset* asset = reinterpret_cast<Asset*>(native_asset);
+    // assets can always be rebuilt, so force this
+    bool forcePurgeable = true;
 
-    if (optionsPurgeable(env, options)) {
+    if (forcePurgeable || optionsPurgeable(env, options)) {
         // if we could "ref/reopen" the asset, we may not need to copy it here
         // and we could assume optionsShareable, since assets are always RO
         stream = copyAssetToStream(asset);
@@ -582,7 +586,7 @@
         stream = new AssetStreamAdaptor(asset);
     }
     SkAutoUnref aur(stream);
-    return doDecode(env, stream, padding, options, true);
+    return doDecode(env, stream, padding, options, true, forcePurgeable);
 }
 
 static jobject nativeDecodeByteArray(JNIEnv* env, jobject, jbyteArray byteArray,
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index f1e614b..4e2caa0 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -648,7 +648,7 @@
          for details. -->
     <permission android:name="android.permission.SET_PREFERRED_APPLICATIONS"
         android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
-        android:protectionLevel="dangerous"
+        android:protectionLevel="signature"
         android:label="@string/permlab_setPreferredApplications"
         android:description="@string/permdesc_setPreferredApplications" />
 
diff --git a/core/res/res/drawable-hdpi/stat_notify_car_mode.png b/core/res/res/drawable-hdpi/stat_notify_car_mode.png
index 6c51b32..03499a4 100644
--- a/core/res/res/drawable-hdpi/stat_notify_car_mode.png
+++ b/core/res/res/drawable-hdpi/stat_notify_car_mode.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_notify_car_mode.png b/core/res/res/drawable-mdpi/stat_notify_car_mode.png
index c664244..0272e6b 100644
--- a/core/res/res/drawable-mdpi/stat_notify_car_mode.png
+++ b/core/res/res/drawable-mdpi/stat_notify_car_mode.png
Binary files differ
diff --git a/core/res/res/layout/status_bar_expanded.xml b/core/res/res/layout/status_bar_expanded.xml
index 30138a7..d443247 100644
--- a/core/res/res/layout/status_bar_expanded.xml
+++ b/core/res/res/layout/status_bar_expanded.xml
@@ -86,6 +86,7 @@
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             android:fadingEdge="none"
+            android:overscrollMode="ifContentScrolls"
             >
             <com.android.server.status.NotificationLinearLayout
                 android:id="@+id/notificationLinearLayout"
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 1ced121..f5e2f1d 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -1747,6 +1747,10 @@
         <!-- When set to false, the ListView will not draw the divider before each footer view.
              The default value is true. -->
         <attr name="footerDividersEnabled" format="boolean" />
+        <!-- Drawable to draw above list content. -->
+        <attr name="overscrollHeader" format="reference" />
+        <!-- Drawable to draw below list content. -->
+        <attr name="overscrollFooter" format="reference" />
     </declare-styleable>
     <declare-styleable name="MenuView">
         <!-- Default appearance of menu item text. -->
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 36a8f5b..8c00884 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1235,6 +1235,8 @@
   <public type="attr" name="stripLeft" id="0x010102bc" />
   <public type="attr" name="stripRight" id="0x010102bd" />
   <public type="attr" name="stripEnabled" id="0x010102be" />
+  <public type="attr" name="overscrollHeader" id="0x010102bf" />
+  <public type="attr" name="overscrollFooter" id="0x010102c0" />
 
   <public type="anim" name="cycle_interpolator" id="0x010a000c" />
     
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index 6bc6f2e..6a7c6ec 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -70,9 +70,6 @@
     <uses-permission android:name="android.permission.ACCESS_MOCK_LOCATION"/>
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
     <uses-permission android:name="android.permission.HARDWARE_TEST" />
-    <uses-permission android:name="android.permission.ACCESSIBILITY_EVENT_VIEW_TYPES" />
-    <uses-permission android:name="android.permission.ACCESSIBILITY_EVENT_TRANSITION_TYPES" />
-    <uses-permission android:name="android.permission.ACCESSIBILITY_EVENT_NOTIFICATION_TYPES" />
 
     <!-- package manager test permissions -->
     <uses-permission android:name="android.permission.INSTALL_PACKAGES" />
@@ -1002,7 +999,7 @@
             </intent-filter>
         </activity>
 
-        <service android:name="android.accessibility.AccessibilityTestService">
+        <service android:name="android.accessibilityservice.AccessibilityTestService">
             <intent-filter>
                 <action android:name="android.accessibilityservice.AccessibilityService" />
             </intent-filter>
diff --git a/graphics/java/android/renderscript/RSSurfaceView.java b/graphics/java/android/renderscript/RSSurfaceView.java
index 1d3f82d..f05e84c 100644
--- a/graphics/java/android/renderscript/RSSurfaceView.java
+++ b/graphics/java/android/renderscript/RSSurfaceView.java
@@ -161,5 +161,9 @@
         mRS.destroy();
         mRS = null;
     }
+    
+    public void createRenderScript(RenderScriptGL rs) {
+        mRS = rs;
+    }
 }
 
diff --git a/include/media/stagefright/StagefrightMediaScanner.h b/include/media/stagefright/StagefrightMediaScanner.h
index af125dc..4437eee 100644
--- a/include/media/stagefright/StagefrightMediaScanner.h
+++ b/include/media/stagefright/StagefrightMediaScanner.h
@@ -22,7 +22,7 @@
 
 namespace android {
 
-struct StagefrightMetadataRetriever;
+struct MediaMetadataRetriever;
 
 struct StagefrightMediaScanner : public MediaScanner {
     StagefrightMediaScanner();
@@ -35,7 +35,7 @@
     virtual char *extractAlbumArt(int fd);
 
 private:
-    sp<StagefrightMetadataRetriever> mRetriever;
+    sp<MediaMetadataRetriever> mRetriever;
 
     StagefrightMediaScanner(const StagefrightMediaScanner &);
     StagefrightMediaScanner &operator=(const StagefrightMediaScanner &);
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index 6041b83..4614b53 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -22,6 +22,7 @@
 import java.io.InputStream;
 import java.io.IOException;
 import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
 import java.util.ArrayList;
 
 /**
@@ -57,12 +58,12 @@
 
     public byte[] get(byte[] key) {
         ArrayList<byte[]> values = execute('g', key);
-        return (values == null || values.size() == 0) ? null : values.get(0);
+        return (values == null || values.isEmpty()) ? null : values.get(0);
     }
 
     public String get(String key) {
-        byte[] value = get(key.getBytes());
-        return (value == null) ? null : new String(value);
+        byte[] value = get(getBytes(key));
+        return (value == null) ? null : toString(value);
     }
 
     public boolean put(byte[] key, byte[] value) {
@@ -71,7 +72,7 @@
     }
 
     public boolean put(String key, String value) {
-        return put(key.getBytes(), value.getBytes());
+        return put(getBytes(key), getBytes(value));
     }
 
     public boolean delete(byte[] key) {
@@ -80,7 +81,7 @@
     }
 
     public boolean delete(String key) {
-        return delete(key.getBytes());
+        return delete(getBytes(key));
     }
 
     public boolean contains(byte[] key) {
@@ -89,7 +90,7 @@
     }
 
     public boolean contains(String key) {
-        return contains(key.getBytes());
+        return contains(getBytes(key));
     }
 
     public byte[][] saw(byte[] prefix) {
@@ -98,13 +99,13 @@
     }
 
     public String[] saw(String prefix) {
-        byte[][] values = saw(prefix.getBytes());
+        byte[][] values = saw(getBytes(prefix));
         if (values == null) {
             return null;
         }
         String[] strings = new String[values.length];
         for (int i = 0; i < values.length; ++i) {
-            strings[i] = new String(values[i]);
+            strings[i] = toString(values[i]);
         }
         return strings;
     }
@@ -120,7 +121,7 @@
     }
 
     public boolean password(String oldPassword, String newPassword) {
-        return password(oldPassword.getBytes(), newPassword.getBytes());
+        return password(getBytes(oldPassword), getBytes(newPassword));
     }
 
     public boolean password(byte[] password) {
@@ -128,7 +129,7 @@
     }
 
     public boolean password(String password) {
-        return password(password.getBytes());
+        return password(getBytes(password));
     }
 
     public boolean lock() {
@@ -142,7 +143,7 @@
     }
 
     public boolean unlock(String password) {
-        return unlock(password.getBytes());
+        return unlock(getBytes(password));
     }
 
     public int getLastError() {
@@ -208,4 +209,22 @@
         }
         return null;
     }
+
+    private static byte[] getBytes(String string) {
+        try {
+            return string.getBytes("UTF-8");
+        } catch (UnsupportedEncodingException e) {
+            // will never happen
+            throw new RuntimeException(e);
+        }
+    }
+
+    private static String toString(byte[] bytes) {
+        try {
+            return new String(bytes, "UTF-8");
+        } catch (UnsupportedEncodingException e) {
+            // will never happen
+            throw new RuntimeException(e);
+        }
+    }
 }
diff --git a/keystore/tests/src/android/security/KeyStoreTest.java b/keystore/tests/src/android/security/KeyStoreTest.java
index 569d8da..6630a4f 100755
--- a/keystore/tests/src/android/security/KeyStoreTest.java
+++ b/keystore/tests/src/android/security/KeyStoreTest.java
@@ -39,6 +39,9 @@
     private static final String TEST_KEYNAME2 = "testkey2";
     private static final String TEST_KEYVALUE = "test value";
 
+    // "Hello, World" in Chinese
+    private static final String TEST_I18N = "\u4F60\u597D, \u4E16\u754C";
+
     private KeyStore mKeyStore = null;
 
     public KeyStoreTest() {
@@ -83,6 +86,14 @@
         assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE));
     }
 
+    public void testI18n() throws Exception {
+        assertFalse(mKeyStore.put(TEST_I18N, TEST_I18N));
+        assertFalse(mKeyStore.contains(TEST_I18N));
+        mKeyStore.password(TEST_I18N);
+        assertTrue(mKeyStore.put(TEST_I18N, TEST_I18N));
+        assertTrue(mKeyStore.contains(TEST_I18N));
+    }
+
     public void testDelete() throws Exception {
         assertTrue(mKeyStore.delete(TEST_KEYNAME));
         mKeyStore.password(TEST_PASSWD);
diff --git a/media/libmedia/mediaplayer.cpp b/media/libmedia/mediaplayer.cpp
index d2cec0c..f623295b 100644
--- a/media/libmedia/mediaplayer.cpp
+++ b/media/libmedia/mediaplayer.cpp
@@ -104,7 +104,8 @@
     { // scope for the lock
         Mutex::Autolock _l(mLock);
 
-        if ( !( mCurrentState & ( MEDIA_PLAYER_IDLE | MEDIA_PLAYER_STATE_ERROR ) ) ) {
+        if ( !( (mCurrentState & MEDIA_PLAYER_IDLE) ||
+                (mCurrentState == MEDIA_PLAYER_STATE_ERROR ) ) ) {
             LOGE("setDataSource called in state %d", mCurrentState);
             return INVALID_OPERATION;
         }
diff --git a/media/libstagefright/StagefrightMediaScanner.cpp b/media/libstagefright/StagefrightMediaScanner.cpp
index b1eca2b..34fb2bc 100644
--- a/media/libstagefright/StagefrightMediaScanner.cpp
+++ b/media/libstagefright/StagefrightMediaScanner.cpp
@@ -20,7 +20,8 @@
 
 #include <media/stagefright/StagefrightMediaScanner.h>
 
-#include "include/StagefrightMetadataRetriever.h"
+#include <media/mediametadataretriever.h>
+#include <private/media/VideoFrame.h>
 
 // Sonivox includes
 #include <libsonivox/eas.h>
@@ -32,7 +33,7 @@
 namespace android {
 
 StagefrightMediaScanner::StagefrightMediaScanner()
-    : mRetriever(new StagefrightMetadataRetriever) {
+    : mRetriever(new MediaMetadataRetriever) {
 }
 
 StagefrightMediaScanner::~StagefrightMediaScanner() {}
@@ -146,6 +147,8 @@
 status_t StagefrightMediaScanner::processFile(
         const char *path, const char *mimeType,
         MediaScannerClient &client) {
+    LOGV("processFile '%s'.", path);
+
     client.setLocale(locale());
     client.beginFile();
 
@@ -218,6 +221,8 @@
 }
 
 char *StagefrightMediaScanner::extractAlbumArt(int fd) {
+    LOGV("extractAlbumArt %d", fd);
+
     off_t size = lseek(fd, 0, SEEK_END);
     if (size < 0) {
         return NULL;
@@ -227,15 +232,14 @@
     if (mRetriever->setDataSource(fd, 0, size) == OK
             && mRetriever->setMode(
                 METADATA_MODE_FRAME_CAPTURE_ONLY) == OK) {
-        MediaAlbumArt *art = mRetriever->extractAlbumArt();
+        sp<IMemory> mem = mRetriever->extractAlbumArt();
 
-        if (art != NULL) {
+        if (mem != NULL) {
+            MediaAlbumArt *art = static_cast<MediaAlbumArt *>(mem->pointer());
+
             char *data = (char *)malloc(art->mSize + 4);
             *(int32_t *)data = art->mSize;
-            memcpy(&data[4], art->mData, art->mSize);
-
-            delete art;
-            art = NULL;
+            memcpy(&data[4], &art[1], art->mSize);
 
             return data;
         }
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java
index 0e883e6..9a48c92 100755
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaNames.java
@@ -394,7 +394,7 @@
            "ID3V2.3 Artist", "ID3V2.3 Lyricist", "ID3V2.3 Composer", null,
            "Blues", "ID3V2.3 Title", "1234", "295", "1", null},
       {"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V2_TRCK_2.mp3", "01", "ID3V2.3 Album", 
-           "ID3V2.3 Artist", null, null, null, "255", "ID3V2.3 Title", "1234", "295", "1", null},
+           "ID3V2.3 Artist", null, null, null, null, "ID3V2.3 Title", null, "295", "1", null},
       {"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V2_TYER.mp3", "01", "ID3V2.3 Album",
            "ID3V2.3 Artist", null, null, null, null, "ID3V2.3 Title", "9999", "295", "1", null},
       {"/sdcard/media_api/metaDataTestMedias/MP3/Corrupted_ID3V2_TYER_2.mp3", "01", "ID3V2.3 Album",
@@ -416,7 +416,7 @@
           null, null, "231180", "1", null},
       {"/sdcard/media_api/metaDataTestMedias/M4A/Jaws Of Life_ver1.m4a", "1/8", "Suspended Animation",
           "John Petrucci", null, null, "20070510T125223.000Z", 
-          "13", "Jaws Of Life", "2005", "449329", "1", "m4a composer"},
+          "12", "Jaws Of Life", "2005", "449329", "1", "m4a composer"},
       {"/sdcard/media_api/metaDataTestMedias/M4V/sample_iPod.m4v", null, null, 
           null, null, null, "20051220T202015.000Z", 
           null, null, null, "85500", "2", null},
@@ -425,7 +425,7 @@
           null, null, "2005", "231180", "1", null},
       {"/sdcard/media_api/metaDataTestMedias/MP4/kung_fu_panda_h264.mp4", "2/0", "mp4 album Kung Fu Panda",
           "mp4 artist Kung Fu Panda", null, null, "20080517T091451.000Z", 
-          "41", "Kung Fu Panda", "2008", "128521", "2", "mp4 composer"},
+          "40", "Kung Fu Panda", "2008", "128521", "2", "mp4 composer"},
       {"/sdcard/media_api/metaDataTestMedias/OGG/Ring_Classic_02.ogg", null, "Suspended Animation", 
           "John Petrucci", null, null, "20070510T125223.000Z", 
           null, null, "2005", "231180", "1", null},
diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
index 4635f48..7714911 100644
--- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
+++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
@@ -349,11 +349,11 @@
                 int installPreference = Settings.System.getInt(getApplicationContext()
                         .getContentResolver(),
                         Settings.System.DEFAULT_INSTALL_LOCATION,
-                        PackageInfo.INSTALL_LOCATION_AUTO);
-                if (installPreference == 1) {
+                        PackageHelper.APP_INSTALL_AUTO);
+                if (installPreference == PackageHelper.APP_INSTALL_INTERNAL) {
                     installOnlyInternal = true;
                     auto = false;
-                } else if (installPreference == 2) {
+                } else if (installPreference == PackageHelper.APP_INSTALL_EXTERNAL) {
                     installOnlyOnSd = true;
                     auto = false;
                 }
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index bd131e0..34302c4 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -56,7 +56,10 @@
     <bool name="def_mount_ums_autostart">false</bool>
     <bool name="def_mount_ums_prompt">true</bool>
     <bool name="def_mount_ums_notify_enabled">true</bool>
+    <!-- Enable User preference for setting install location -->
     <bool name="set_install_location">true</bool>
+    <!-- Default install location if user preference for setting install location is turned on. -->
+    <integer name="def_install_location">2</integer>
 
     <!-- user interface sound effects -->
     <integer name="def_power_sounds_enabled">1</integer>
@@ -70,4 +73,6 @@
     <string name="def_lock_sound" translatable="false">/system/media/audio/ui/Lock.ogg</string>
     <string name="def_unlock_sound" translatable="false">/system/media/audio/ui/Unlock.ogg</string>
 
+    <!-- Default for Settings.System.VIBRATE_IN_SILENT -->
+    <bool name="def_vibrate_in_silent">true</bool>
 </resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index b05f1b3..ba66dc5 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -61,7 +61,7 @@
     // database gets upgraded properly. At a minimum, please confirm that 'upgradeVersion'
     // is properly propagated through your change.  Not doing so will result in a loss of user
     // settings.
-    private static final int DATABASE_VERSION = 52;
+    private static final int DATABASE_VERSION = 54;
 
     private Context mContext;
 
@@ -634,7 +634,45 @@
            upgradeVersion = 52;
        }
 
-       if (upgradeVersion != currentVersion) {
+        if (upgradeVersion == 52) {
+            // new vibration/silent mode settings
+            db.beginTransaction();
+            try {
+                SQLiteStatement stmt = db.compileStatement("INSERT INTO system(name,value)"
+                        + " VALUES(?,?);");
+                loadBooleanSetting(stmt, Settings.System.VIBRATE_IN_SILENT,
+                        R.bool.def_vibrate_in_silent);
+                stmt.close();
+                db.setTransactionSuccessful();
+            } finally {
+                db.endTransaction();
+            }
+
+            upgradeVersion = 53;
+        }
+        
+        if (upgradeVersion == 53) {
+            /*
+             * New settings for set install location UI.
+             */
+            db.beginTransaction();
+            try {
+                 SQLiteStatement stmt = db.compileStatement("INSERT INTO system(name,value)"
+                         + " VALUES(?,?);");
+                 loadIntegerSetting(stmt, Settings.System.DEFAULT_INSTALL_LOCATION,
+                         R.integer.def_install_location);
+                 stmt.close();
+                 db.setTransactionSuccessful();
+             } finally {
+                 db.endTransaction();
+             }
+
+            upgradeVersion = 54;
+        }
+
+        // *** Remember to update DATABASE_VERSION above!
+
+        if (upgradeVersion != currentVersion) {
             Log.w(TAG, "Got stuck trying to upgrade from version " + upgradeVersion
                     + ", must wipe the settings provider");
             db.execSQL("DROP TABLE IF EXISTS system");
@@ -924,12 +962,16 @@
 
         loadBooleanSetting(stmt, Settings.System.NOTIFICATION_LIGHT_PULSE,
                 R.bool.def_notification_pulse);
-        loadBooleanSetting(stmt, Settings.System.SET_INSTALL_LOCATION, R.bool.set_install_location);
-        loadSetting(stmt, Settings.System.DEFAULT_INSTALL_LOCATION,
-                PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY);
+        loadBooleanSetting(stmt, Settings.System.SET_INSTALL_LOCATION,
+                R.bool.set_install_location);
+        loadIntegerSetting(stmt, Settings.System.DEFAULT_INSTALL_LOCATION,
+                R.integer.def_install_location);
 
         loadUISoundEffectsSettings(stmt);
 
+        loadBooleanSetting(stmt, Settings.System.VIBRATE_IN_SILENT,
+                R.bool.def_vibrate_in_silent);
+
         stmt.close();
     }
 
diff --git a/services/java/com/android/server/AlarmManagerService.java b/services/java/com/android/server/AlarmManagerService.java
index 43fe6ab..1ffb427 100644
--- a/services/java/com/android/server/AlarmManagerService.java
+++ b/services/java/com/android/server/AlarmManagerService.java
@@ -821,6 +821,11 @@
                 } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
                     pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
                 } else {
+                    if (Intent.ACTION_PACKAGE_REMOVED.equals(action)
+                            && intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
+                        // This package is being updated; don't kill its alarms.
+                        return;
+                    }
                     Uri data = intent.getData();
                     if (data != null) {
                         String pkg = data.getSchemeSpecificPart();
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 70deb3e..fa06244 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -668,6 +668,7 @@
         synchronized(this) {
             // check if this process still has an outstanding start request
             if (!mFeatureUsers.contains(u)) {
+                if (DBG) Slog.d(TAG, "ignoring - this process has no outstanding requests");
                 return 1;
             }
             u.unlinkDeathRecipient();
@@ -706,6 +707,7 @@
             }
             tracker =  mNetTrackers[usedNetworkType];
             if (tracker == null) {
+                if (DBG) Slog.d(TAG, "ignoring - no known tracker for net type " + usedNetworkType);
                 return -1;
             }
             if (usedNetworkType != networkType) {
@@ -720,7 +722,7 @@
                 callTeardown = true;
             }
         }
-
+        if (DBG) Slog.d(TAG, "Doing network teardown");
         if (callTeardown) {
             tracker.teardown();
             return 1;
diff --git a/services/java/com/android/server/DropBoxManagerService.java b/services/java/com/android/server/DropBoxManagerService.java
index 667953c..b38f1d2 100644
--- a/services/java/com/android/server/DropBoxManagerService.java
+++ b/services/java/com/android/server/DropBoxManagerService.java
@@ -603,7 +603,9 @@
             for (EntryFile late : future) {
                 mAllFiles.blocks -= late.blocks;
                 FileList tagFiles = mFilesByTag.get(late.tag);
-                if (tagFiles.contents.remove(late)) tagFiles.blocks -= late.blocks;
+                if (tagFiles != null && tagFiles.contents.remove(late)) {
+                    tagFiles.blocks -= late.blocks;
+                }
                 if ((late.flags & DropBoxManager.IS_EMPTY) == 0) {
                     enrollEntry(new EntryFile(
                             late.file, mDropBoxDir, late.tag, t++, late.flags, mBlockSize));
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index 371fa37..63afabc 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -4589,7 +4589,7 @@
                         } else {
                             // When replacing apps make sure we honour
                             // the existing app location if not overwritten by other options
-                            boolean prevOnSd = (pkg.applicationInfo.flags & ApplicationInfo.FLAG_ON_SDCARD) != 0;
+                            boolean prevOnSd = (pkg.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0;
                             if (onSd) {
                                 // Install flag overrides everything.
                                 return PackageHelper.RECOMMEND_INSTALL_EXTERNAL;
@@ -5995,7 +5995,7 @@
         // Delete application code and resources
         if (deleteCodeAndResources) {
             // TODO can pick up from PackageSettings as well
-            int installFlags = ((p.applicationInfo.flags & ApplicationInfo.FLAG_ON_SDCARD)!=0) ?
+            int installFlags = ((p.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE)!=0) ?
                     PackageManager.INSTALL_EXTERNAL : 0;
             installFlags |= ((p.applicationInfo.flags & ApplicationInfo.FLAG_FORWARD_LOCK)!=0) ?
                     PackageManager.INSTALL_FORWARD_LOCK : 0;
@@ -6321,10 +6321,14 @@
     }
 
     public void clearPackagePreferredActivities(String packageName) {
-        mContext.enforceCallingOrSelfPermission(
-                android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
-
         synchronized (mPackages) {
+            int uid = Binder.getCallingUid();
+            PackageParser.Package pkg = mPackages.get(packageName);
+            if (pkg.applicationInfo.uid != uid) {
+                mContext.enforceCallingOrSelfPermission(
+                        android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
+            }
+
             if (clearPackagePreferredActivitiesLP(packageName)) {
                 mSettings.writeLP();
             }
@@ -7214,7 +7218,7 @@
         void setFlags(int pkgFlags) {
             this.pkgFlags = (pkgFlags & ApplicationInfo.FLAG_SYSTEM) |
             (pkgFlags & ApplicationInfo.FLAG_FORWARD_LOCK) |
-            (pkgFlags & ApplicationInfo.FLAG_ON_SDCARD) |
+            (pkgFlags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) |
             (pkgFlags & ApplicationInfo.FLAG_NEVER_ENCRYPT);
         }
     }
@@ -9058,7 +9062,7 @@
                return false;
            }
            mMediaMounted = mediaStatus;
-           Set<String> appList = mSettings.findPackagesWithFlag(ApplicationInfo.FLAG_ON_SDCARD);
+           Set<String> appList = mSettings.findPackagesWithFlag(ApplicationInfo.FLAG_EXTERNAL_STORAGE);
            ret = appList != null && appList.size() > 0;
        }
        // Queue up an async operation since the package installation may take a little while.
@@ -9107,7 +9111,7 @@
                    if (DEBUG_SD_INSTALL) Log.i(TAG, "Looking for pkg : " + pkgName);
                    PackageSetting ps = mSettings.mPackages.get(pkgName);
                    if (ps != null && ps.codePathString != null &&
-                           (ps.pkgFlags & ApplicationInfo.FLAG_ON_SDCARD) != 0) {
+                           (ps.pkgFlags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0) {
                        if (DEBUG_SD_INSTALL) Log.i(TAG, "Container : " + cid +
                                " corresponds to pkg : " + pkgName +
                                " at code path: " + ps.codePathString);
@@ -9333,7 +9337,7 @@
                } else {
                    newFlags = (flags & PackageManager.MOVE_EXTERNAL_MEDIA) != 0 ?
                            PackageManager.INSTALL_EXTERNAL : 0;
-                   currFlags = (pkg.applicationInfo.flags & ApplicationInfo.FLAG_ON_SDCARD) != 0 ?
+                   currFlags = (pkg.applicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0 ?
                            PackageManager.INSTALL_EXTERNAL : 0;
                    if (newFlags == currFlags) {
                        Log.w(TAG, "No move required. Trying to move to same location");
@@ -9400,9 +9404,9 @@
                                ps.resourcePathString = ps.resourcePath.getPath();
                                // Set the application info flag correctly.
                                if ((mp.flags & PackageManager.INSTALL_EXTERNAL) != 0) {
-                                   pkg.applicationInfo.flags |= ApplicationInfo.FLAG_ON_SDCARD;
+                                   pkg.applicationInfo.flags |= ApplicationInfo.FLAG_EXTERNAL_STORAGE;
                                } else {
-                                   pkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_ON_SDCARD;
+                                   pkg.applicationInfo.flags &= ~ApplicationInfo.FLAG_EXTERNAL_STORAGE;
                                }
                                ps.setFlags(pkg.applicationInfo.flags);
                                mAppDirs.remove(oldCodePath);
diff --git a/services/java/com/android/server/UiModeManagerService.java b/services/java/com/android/server/UiModeManagerService.java
index 5f23a90..8103d7c 100644
--- a/services/java/com/android/server/UiModeManagerService.java
+++ b/services/java/com/android/server/UiModeManagerService.java
@@ -88,7 +88,9 @@
 
     private boolean mComputedNightMode;
     private int mCurUiMode = 0;
+    private int mSetUiMode = 0;
     
+    private boolean mHoldingConfiguration = false;
     private Configuration mConfiguration = new Configuration();
     
     private boolean mSystemReady;
@@ -114,25 +116,32 @@
                 return;
             }
 
-            // Launch a dock activity
-            String category;
-            if (UiModeManager.ACTION_ENTER_CAR_MODE.equals(intent.getAction())) {
-                // Only launch car home when car mode is enabled.
-                category = Intent.CATEGORY_CAR_DOCK;
-            } else if (UiModeManager.ACTION_ENTER_DESK_MODE.equals(intent.getAction())) {
-                category = Intent.CATEGORY_DESK_DOCK;
-            } else {
-                category = null;
-            }
-            if (category != null) {
-                intent = new Intent(Intent.ACTION_MAIN);
-                intent.addCategory(category);
-                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
-                        | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
-                try {
-                    mContext.startActivity(intent);
-                } catch (ActivityNotFoundException e) {
-                    Slog.w(TAG, e.getCause());
+            synchronized (mLock) {
+                // Launch a dock activity
+                String category;
+                if (UiModeManager.ACTION_ENTER_CAR_MODE.equals(intent.getAction())) {
+                    // Only launch car home when car mode is enabled.
+                    category = Intent.CATEGORY_CAR_DOCK;
+                } else if (UiModeManager.ACTION_ENTER_DESK_MODE.equals(intent.getAction())) {
+                    category = Intent.CATEGORY_DESK_DOCK;
+                } else {
+                    category = null;
+                }
+                if (category != null) {
+                    intent = new Intent(Intent.ACTION_MAIN);
+                    intent.addCategory(category);
+                    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                            | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
+                    try {
+                        mContext.startActivity(intent);
+                    } catch (ActivityNotFoundException e) {
+                        Slog.w(TAG, e.getCause());
+                    }
+                }
+                
+                if (mHoldingConfiguration) {
+                    mHoldingConfiguration = false;
+                    updateConfigurationLocked();
                 }
             }
         }
@@ -370,42 +379,46 @@
         }
     }
 
+    final void updateConfigurationLocked() {
+        int uiMode = 0;
+        if (mCarModeEnabled) {
+            uiMode = Configuration.UI_MODE_TYPE_CAR;
+        } else if (mDockState == Intent.EXTRA_DOCK_STATE_DESK) {
+            uiMode = Configuration.UI_MODE_TYPE_DESK;
+        }
+        if (uiMode != 0) {
+            if (mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
+                updateTwilightLocked();
+                uiMode |= mComputedNightMode ? Configuration.UI_MODE_NIGHT_YES
+                        : Configuration.UI_MODE_NIGHT_NO;
+            } else {
+                uiMode |= mNightMode << 4;
+            }
+        } else {
+            // Disabling the car mode clears the night mode.
+            uiMode = Configuration.UI_MODE_TYPE_NORMAL |
+                    Configuration.UI_MODE_NIGHT_NO;
+        }
+        
+        mCurUiMode = uiMode;
+        
+        if (!mHoldingConfiguration && uiMode != mSetUiMode) {
+            mSetUiMode = uiMode;
+            
+            try {
+                final IActivityManager am = ActivityManagerNative.getDefault();
+                mConfiguration.uiMode = uiMode;
+                am.updateConfiguration(mConfiguration);
+            } catch (RemoteException e) {
+                Slog.w(TAG, "Failure communicating with activity manager", e);
+            }
+        }
+    }
+    
     final void updateLocked() {
         long ident = Binder.clearCallingIdentity();
         
         try {
-            int uiMode = 0;
-            if (mCarModeEnabled) {
-                uiMode = Configuration.UI_MODE_TYPE_CAR;
-            } else if (mDockState == Intent.EXTRA_DOCK_STATE_DESK) {
-                uiMode = Configuration.UI_MODE_TYPE_DESK;
-            }
-            if (uiMode != 0) {
-                if (mNightMode == UiModeManager.MODE_NIGHT_AUTO) {
-                    updateTwilightLocked();
-                    uiMode |= mComputedNightMode ? Configuration.UI_MODE_NIGHT_YES
-                            : Configuration.UI_MODE_NIGHT_NO;
-                } else {
-                    uiMode |= mNightMode << 4;
-                }
-            } else {
-                // Disabling the car mode clears the night mode.
-                uiMode = Configuration.UI_MODE_TYPE_NORMAL |
-                        Configuration.UI_MODE_NIGHT_NO;
-            }
-            
-            if (uiMode != mCurUiMode) {
-                mCurUiMode = uiMode;
-                
-                try {
-                    final IActivityManager am = ActivityManagerNative.getDefault();
-                    mConfiguration.uiMode = uiMode;
-                    am.updateConfiguration(mConfiguration);
-                } catch (RemoteException e) {
-                    Slog.w(TAG, "Failure communicating with activity manager", e);
-                }
-            }
-            
             String action = null;
             String oldAction = null;
             if (mLastBroadcastState == Intent.EXTRA_DOCK_STATE_CAR) {
@@ -450,7 +463,13 @@
                 // placed into a dock.
                 mContext.sendOrderedBroadcast(new Intent(action), null,
                         mResultReceiver, null, Activity.RESULT_OK, null, null);
+                // Attempting to make this transition a little more clean, we are going
+                // to hold off on doing a configuration change until we have finished
+                // the broacast and started the home activity.
+                mHoldingConfiguration = true;
             }
+            
+            updateConfigurationLocked();
 
             // keep screen on when charging and in car mode
             boolean keepScreenOn = mCharging &&
@@ -685,6 +704,8 @@
                     pw.print(" mCarModeEnabled="); pw.print(mCarModeEnabled);
                     pw.print(" mComputedNightMode="); pw.println(mComputedNightMode);
             pw.print("  mCurUiMode=0x"); pw.print(Integer.toHexString(mCurUiMode));
+                    pw.print(" mSetUiMode=0x"); pw.println(Integer.toHexString(mSetUiMode));
+            pw.print("  mHoldingConfiguration="); pw.print(mHoldingConfiguration);
                     pw.print(" mSystemReady="); pw.println(mSystemReady);
             if (mLocation != null) {
                 pw.print("  mLocation="); pw.println(mLocation);
diff --git a/services/java/com/android/server/WifiService.java b/services/java/com/android/server/WifiService.java
index 62263a6..248f579 100644
--- a/services/java/com/android/server/WifiService.java
+++ b/services/java/com/android/server/WifiService.java
@@ -96,7 +96,6 @@
     private final WifiStateTracker mWifiStateTracker;
 
     private Context mContext;
-    private int mWifiState;
     private int mWifiApState;
 
     private AlarmManager mAlarmManager;
@@ -216,7 +215,7 @@
         wifiThread.start();
         mWifiHandler = new WifiHandler(wifiThread.getLooper());
 
-        mWifiState = WIFI_STATE_DISABLED;
+        mWifiStateTracker.setWifiState(WIFI_STATE_DISABLED);
         mWifiApState = WIFI_AP_STATE_DISABLED;
         boolean wifiEnabled = getPersistedWifiEnabled();
         boolean wifiAPEnabled = wifiEnabled ? false : getPersistedWifiApEnabled();
@@ -406,8 +405,9 @@
      */
     private boolean setWifiEnabledBlocking(boolean enable, boolean persist, int uid) {
         final int eventualWifiState = enable ? WIFI_STATE_ENABLED : WIFI_STATE_DISABLED;
+        final int wifiState = mWifiStateTracker.getWifiState();
 
-        if (mWifiState == eventualWifiState) {
+        if (wifiState == eventualWifiState) {
             return true;
         }
         if (enable && isAirplaneModeOn() && !mAirplaneModeOverwridden) {
@@ -421,7 +421,7 @@
          * Avoid doing a disable when the current Wifi state is UNKNOWN
          * TODO: Handle driver load fail and supplicant lost as seperate states
          */
-        if ((mWifiState == WIFI_STATE_UNKNOWN) && !enable) {
+        if ((wifiState == WIFI_STATE_UNKNOWN) && !enable) {
             return false;
         }
 
@@ -489,7 +489,7 @@
     }
 
     private void setWifiEnabledState(int wifiState, int uid) {
-        final int previousWifiState = mWifiState;
+        final int previousWifiState = mWifiStateTracker.getWifiState();
 
         long ident = Binder.clearCallingIdentity();
         try {
@@ -504,7 +504,7 @@
         }
 
         // Update state
-        mWifiState = wifiState;
+        mWifiStateTracker.setWifiState(wifiState);
 
         // Broadcast
         final Intent intent = new Intent(WifiManager.WIFI_STATE_CHANGED_ACTION);
@@ -541,7 +541,7 @@
      */
     public int getWifiEnabledState() {
         enforceAccessPermission();
-        return mWifiState;
+        return mWifiStateTracker.getWifiState();
     }
 
     /**
@@ -639,7 +639,7 @@
 
         setWifiApEnabledState(enable ? WIFI_AP_STATE_ENABLING : WIFI_AP_STATE_DISABLING, uid);
 
-        if (enable && (mWifiState == WIFI_STATE_ENABLED)) {
+        if (enable && (mWifiStateTracker.getWifiState() == WIFI_STATE_ENABLED)) {
             setWifiEnabledBlocking(false, true, Process.myUid());
         }
 
@@ -1721,7 +1721,7 @@
         }
 
         synchronized (mWifiHandler) {
-            if (mWifiState == WIFI_STATE_ENABLING && !airplaneMode) {
+            if ((mWifiStateTracker.getWifiState() == WIFI_STATE_ENABLING) && !airplaneMode) {
                 return;
             }
             if (wifiShouldBeEnabled) {
@@ -1864,7 +1864,7 @@
                     + ", uid=" + Binder.getCallingUid());
             return;
         }
-        pw.println("Wi-Fi is " + stateName(mWifiState));
+        pw.println("Wi-Fi is " + stateName(mWifiStateTracker.getWifiState()));
         pw.println("Stay-awake conditions: " +
                 Settings.System.getInt(mContext.getContentResolver(),
                                        Settings.System.STAY_ON_WHILE_PLUGGED_IN, 0));
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 34a7fc0..989fe2a 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -43,6 +43,7 @@
 
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.policy.PolicyManager;
+import com.android.internal.policy.impl.PhoneWindowManager;
 import com.android.internal.view.IInputContext;
 import com.android.internal.view.IInputMethodClient;
 import com.android.internal.view.IInputMethodManager;
@@ -984,10 +985,15 @@
         //Slog.i(TAG, "Placing input method @" + (i+1));
         if (w != null) {
             if (willMove) {
-                RuntimeException e = new RuntimeException();
-                if (!HIDE_STACK_CRAWLS) e.fillInStackTrace();
-                if (DEBUG_INPUT_METHOD) Slog.w(TAG, "Moving IM target from "
-                        + mInputMethodTarget + " to " + w, e);
+                if (DEBUG_INPUT_METHOD) {
+                    RuntimeException e = null;
+                    if (!HIDE_STACK_CRAWLS) {
+                        e = new RuntimeException();
+                        e.fillInStackTrace();
+                    }
+                    Slog.w(TAG, "Moving IM target from "
+                            + mInputMethodTarget + " to " + w, e);
+                }
                 mInputMethodTarget = w;
                 if (w.mAppToken != null) {
                     setInputMethodAnimLayerAdjustment(w.mAppToken.animLayerAdjustment);
@@ -998,10 +1004,15 @@
             return i+1;
         }
         if (willMove) {
-            RuntimeException e = new RuntimeException();
-            if (!HIDE_STACK_CRAWLS) e.fillInStackTrace();
-            if (DEBUG_INPUT_METHOD) Slog.w(TAG, "Moving IM target from "
-                    + mInputMethodTarget + " to null", e);
+            if (DEBUG_INPUT_METHOD) {
+                RuntimeException e = null;
+                if (!HIDE_STACK_CRAWLS) {
+                    e = new RuntimeException();
+                    e.fillInStackTrace();
+                }
+                Slog.w(TAG, "Moving IM target from "
+                        + mInputMethodTarget + " to null", e);
+            }
             mInputMethodTarget = null;
             setInputMethodAnimLayerAdjustment(0);
         }
@@ -2178,6 +2189,16 @@
         }
     }
 
+    private static void logSurface(WindowState w, String msg, RuntimeException where) {
+        String str = "  SURFACE " + Integer.toHexString(w.hashCode())
+                + ": " + msg + " / " + w.mAttrs.getTitle();
+        if (where != null) {
+            Slog.i(TAG, str, where);
+        } else {
+            Slog.i(TAG, str);
+        }
+    }
+    
     private void setTransparentRegionWindow(Session session, IWindow client, Region region) {
         long origId = Binder.clearCallingIdentity();
         try {
@@ -2187,9 +2208,8 @@
                     if (SHOW_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION");
                     Surface.openTransaction();
                     try {
-                        if (SHOW_TRANSACTIONS) Slog.i(
-                                TAG, "  SURFACE " + w.mSurface
-                                + ": transparentRegionHint=" + region);
+                        if (SHOW_TRANSACTIONS) logSurface(w,
+                                "transparentRegionHint=" + region, null);
                         w.mSurface.setTransparentRegionHint(region);
                     } finally {
                         if (SHOW_TRANSACTIONS) Slog.i(TAG, "<<< CLOSE TRANSACTION");
@@ -2654,8 +2674,11 @@
                     + " isEntrance=" + isEntrance);
             if (a != null) {
                 if (DEBUG_ANIM) {
-                    RuntimeException e = new RuntimeException();
-                    if (!HIDE_STACK_CRAWLS) e.fillInStackTrace();
+                    RuntimeException e = null;
+                    if (!HIDE_STACK_CRAWLS) {
+                        e = new RuntimeException();
+                        e.fillInStackTrace();
+                    }
                     Slog.v(TAG, "Loaded animation " + a + " for " + win, e);
                 }
                 win.setAnimation(a);
@@ -2777,8 +2800,11 @@
             }
             if (a != null) {
                 if (DEBUG_ANIM) {
-                    RuntimeException e = new RuntimeException();
-                    if (!HIDE_STACK_CRAWLS) e.fillInStackTrace();
+                    RuntimeException e = null;
+                    if (!HIDE_STACK_CRAWLS) {
+                        e = new RuntimeException();
+                        e.fillInStackTrace();
+                    }
                     Slog.v(TAG, "Loaded animation " + a + " for " + wtoken, e);
                 }
                 wtoken.setAnimation(a);
@@ -3569,8 +3595,11 @@
             }
 
             if (DEBUG_APP_TRANSITIONS || DEBUG_ORIENTATION) {
-                RuntimeException e = new RuntimeException();
-                if (!HIDE_STACK_CRAWLS) e.fillInStackTrace();
+                RuntimeException e = null;
+                if (!HIDE_STACK_CRAWLS) {
+                    e = new RuntimeException();
+                    e.fillInStackTrace();
+                }
                 Slog.v(TAG, "setAppVisibility(" + token + ", " + visible
                         + "): mNextAppTransition=" + mNextAppTransition
                         + " hidden=" + wtoken.hidden
@@ -3671,8 +3700,11 @@
     public void startAppFreezingScreenLocked(AppWindowToken wtoken,
             int configChanges) {
         if (DEBUG_ORIENTATION) {
-            RuntimeException e = new RuntimeException();
-            if (!HIDE_STACK_CRAWLS) e.fillInStackTrace();
+            RuntimeException e = null;
+            if (!HIDE_STACK_CRAWLS) {
+                e = new RuntimeException();
+                e.fillInStackTrace();
+            }
             Slog.i(TAG, "Set freezing of " + wtoken.appToken
                     + ": hidden=" + wtoken.hidden + " freezing="
                     + wtoken.freezingScreen, e);
@@ -7305,7 +7337,8 @@
                             + mSession.mSurfaceSession
                             + ": pid=" + mSession.mPid + " format="
                             + mAttrs.format + " flags=0x"
-                            + Integer.toHexString(flags));
+                            + Integer.toHexString(flags)
+                            + " / " + this);
                 } catch (Surface.OutOfResourcesException e) {
                     Slog.w(TAG, "OutOfResourcesException creating surface");
                     reclaimSomeSurfaceMemoryLocked(this, "create");
@@ -7321,11 +7354,10 @@
                     + ", animLayer=" + mAnimLayer);
                 if (SHOW_TRANSACTIONS) {
                     Slog.i(TAG, ">>> OPEN TRANSACTION");
-                    Slog.i(TAG, "  SURFACE " + mSurface + ": CREATE ("
-                            + mAttrs.getTitle() + ") pos=(" +
-                          mFrame.left + "," + mFrame.top + ") (" +
-                          mFrame.width() + "x" + mFrame.height() + "), layer=" +
-                          mAnimLayer + " HIDE");
+                    if (SHOW_TRANSACTIONS) logSurface(this,
+                            "CREATE pos=(" + mFrame.left + "," + mFrame.top + ") (" +
+                            mFrame.width() + "x" + mFrame.height() + "), layer=" +
+                            mAnimLayer + " HIDE", null);
                 }
                 Surface.openTransaction();
                 try {
@@ -7335,8 +7367,7 @@
                         mSurface.setLayer(mAnimLayer);
                         mSurface.hide();
                         if ((mAttrs.flags&WindowManager.LayoutParams.FLAG_DITHER) != 0) {
-                            if (SHOW_TRANSACTIONS) Slog.i(TAG, "  SURFACE "
-                                    + mSurface + ": DITHER");
+                            if (SHOW_TRANSACTIONS) logSurface(this, "DITHER", null);
                             mSurface.setFlags(Surface.SURFACE_DITHER,
                                     Surface.SURFACE_DITHER);
                         }
@@ -7393,16 +7424,21 @@
 
                 try {
                     if (DEBUG_VISIBILITY) {
-                        RuntimeException e = new RuntimeException();
-                        if (!HIDE_STACK_CRAWLS) e.fillInStackTrace();
+                        RuntimeException e = null;
+                        if (!HIDE_STACK_CRAWLS) {
+                            e = new RuntimeException();
+                            e.fillInStackTrace();
+                        }
                         Slog.w(TAG, "Window " + this + " destroying surface "
                                 + mSurface + ", session " + mSession, e);
                     }
                     if (SHOW_TRANSACTIONS) {
-                        RuntimeException ex = new RuntimeException();
-                        if (!HIDE_STACK_CRAWLS) ex.fillInStackTrace();
-                        Slog.i(TAG, "  SURFACE " + mSurface + ": DESTROY ("
-                                + mAttrs.getTitle() + ")", ex);
+                        RuntimeException e = null;
+                        if (!HIDE_STACK_CRAWLS) {
+                            e = new RuntimeException();
+                            e.fillInStackTrace();
+                        }
+                        if (SHOW_TRANSACTIONS) logSurface(this, "DESTROY", e);
                     }
                     mSurface.destroy();
                 } catch (RuntimeException e) {
@@ -7445,15 +7481,18 @@
         // This must be called while inside a transaction.
         boolean performShowLocked() {
             if (DEBUG_VISIBILITY) {
-                RuntimeException e = new RuntimeException();
-                if (!HIDE_STACK_CRAWLS) e.fillInStackTrace();
+                RuntimeException e = null;
+                if (!HIDE_STACK_CRAWLS) {
+                    e = new RuntimeException();
+                    e.fillInStackTrace();
+                }
                 Slog.v(TAG, "performShow on " + this
                         + ": readyToShow=" + mReadyToShow + " readyForDisplay=" + isReadyForDisplay()
                         + " starting=" + (mAttrs.type == TYPE_APPLICATION_STARTING), e);
             }
             if (mReadyToShow && isReadyForDisplay()) {
-                if (SHOW_TRANSACTIONS || DEBUG_ORIENTATION) Slog.i(
-                        TAG, "  SURFACE " + mSurface + ": SHOW (performShowLocked)");
+                if (SHOW_TRANSACTIONS || DEBUG_ORIENTATION) logSurface(this,
+                        "SHOW (performShowLocked)", null);
                 if (DEBUG_VISIBILITY) Slog.v(TAG, "Showing " + this
                         + " during animation: policyVis=" + mPolicyVisibility
                         + " attHidden=" + mAttachedHidden
@@ -7666,8 +7705,7 @@
             if (mSurface != null) {
                 mDestroySurface.add(this);
                 mDestroying = true;
-                if (SHOW_TRANSACTIONS) Slog.i(
-                        TAG, "  SURFACE " + mSurface + ": HIDE (finishExit)");
+                if (SHOW_TRANSACTIONS) logSurface(this, "HIDE (finishExit)", null);
                 try {
                     mSurface.hide();
                 } catch (RuntimeException e) {
@@ -7826,6 +7864,7 @@
             final AppWindowToken atoken = mAppToken;
             return mSurface != null && !mAttachedHidden
                     && (atoken == null ? mPolicyVisibility : !atoken.hiddenRequested)
+                    && !mDrawPending && !mCommitDrawPending
                     && !mExiting && !mDestroying;
         }
 
@@ -8045,6 +8084,18 @@
                 return false;
             }
             if (DEBUG_VISIBILITY) Slog.v(TAG, "Policy visibility true: " + this);
+            if (doAnimation) {
+                if (DEBUG_VISIBILITY) Slog.v(TAG, "doAnimation: mPolicyVisibility="
+                        + mPolicyVisibility + " mAnimation=" + mAnimation);
+                if (mDisplayFrozen || !mPolicy.isScreenOn()) {
+                    doAnimation = false;
+                } else if (mPolicyVisibility && mAnimation == null) {
+                    // Check for the case where we are currently visible and
+                    // not animating; we do not want to do animation at such a
+                    // point to become visible when we already are.
+                    doAnimation = false;
+                }
+            }
             mPolicyVisibility = true;
             mPolicyVisibilityAfterAnim = true;
             if (doAnimation) {
@@ -8061,6 +8112,11 @@
         }
 
         boolean hideLw(boolean doAnimation, boolean requestAnim) {
+            if (doAnimation) {
+                if (mDisplayFrozen || !mPolicy.isScreenOn()) {
+                    doAnimation = false;
+                }
+            }
             boolean current = doAnimation ? mPolicyVisibilityAfterAnim
                     : mPolicyVisibility;
             if (!current) {
@@ -8082,6 +8138,9 @@
                 // for it to be displayed before enabling the display, that
                 // we allow the display to be enabled now.
                 enableScreenIfNeededLocked();
+                if (mCurrentFocus == this) {
+                    mFocusMayChange = true;
+                }
             }
             if (requestAnim) {
                 requestAnimationLocked(0);
@@ -9283,131 +9342,106 @@
         }
     }
 
-    private final void performLayoutLockedInner() {
+    private final int performLayoutLockedInner() {
+        if (!mLayoutNeeded) {
+            return 0;
+        }
+        
+        mLayoutNeeded = false;
+        
         final int dw = mDisplay.getWidth();
         final int dh = mDisplay.getHeight();
 
         final int N = mWindows.size();
-        int repeats = 0;
         int i;
 
         if (DEBUG_LAYOUT) Slog.v(TAG, "performLayout: needed="
                 + mLayoutNeeded + " dw=" + dw + " dh=" + dh);
         
-        // FIRST LOOP: Perform a layout, if needed.
+        mPolicy.beginLayoutLw(dw, dh);
 
-        while (mLayoutNeeded) {
-            mPolicy.beginLayoutLw(dw, dh);
+        int seq = mLayoutSeq+1;
+        if (seq < 0) seq = 0;
+        mLayoutSeq = seq;
+        
+        // First perform layout of any root windows (not attached
+        // to another window).
+        int topAttached = -1;
+        for (i = N-1; i >= 0; i--) {
+            WindowState win = (WindowState) mWindows.get(i);
 
-            int seq = mLayoutSeq+1;
-            if (seq < 0) seq = 0;
-            mLayoutSeq = seq;
+            // Don't do layout of a window if it is not visible, or
+            // soon won't be visible, to avoid wasting time and funky
+            // changes while a window is animating away.
+            final AppWindowToken atoken = win.mAppToken;
+            final boolean gone = win.mViewVisibility == View.GONE
+                    || !win.mRelayoutCalled
+                    || win.mRootToken.hidden
+                    || (atoken != null && atoken.hiddenRequested)
+                    || win.mAttachedHidden
+                    || win.mExiting || win.mDestroying;
+
+            if (!win.mLayoutAttached) {
+                if (DEBUG_LAYOUT) Slog.v(TAG, "First pass " + win
+                        + ": gone=" + gone + " mHaveFrame=" + win.mHaveFrame
+                        + " mLayoutAttached=" + win.mLayoutAttached);
+                if (DEBUG_LAYOUT && gone) Slog.v(TAG, "  (mViewVisibility="
+                        + win.mViewVisibility + " mRelayoutCalled="
+                        + win.mRelayoutCalled + " hidden="
+                        + win.mRootToken.hidden + " hiddenRequested="
+                        + (atoken != null && atoken.hiddenRequested)
+                        + " mAttachedHidden=" + win.mAttachedHidden);
+            }
             
-            // First perform layout of any root windows (not attached
-            // to another window).
-            int topAttached = -1;
-            for (i = N-1; i >= 0; i--) {
-                WindowState win = (WindowState) mWindows.get(i);
-
-                // Don't do layout of a window if it is not visible, or
-                // soon won't be visible, to avoid wasting time and funky
-                // changes while a window is animating away.
-                final AppWindowToken atoken = win.mAppToken;
-                final boolean gone = win.mViewVisibility == View.GONE
-                        || !win.mRelayoutCalled
-                        || win.mRootToken.hidden
-                        || (atoken != null && atoken.hiddenRequested)
-                        || win.mAttachedHidden
-                        || win.mExiting || win.mDestroying;
-
+            // If this view is GONE, then skip it -- keep the current
+            // frame, and let the caller know so they can ignore it
+            // if they want.  (We do the normal layout for INVISIBLE
+            // windows, since that means "perform layout as normal,
+            // just don't display").
+            if (!gone || !win.mHaveFrame) {
                 if (!win.mLayoutAttached) {
-                    if (DEBUG_LAYOUT) Slog.v(TAG, "First pass " + win
-                            + ": gone=" + gone + " mHaveFrame=" + win.mHaveFrame
-                            + " mLayoutAttached=" + win.mLayoutAttached);
-                    if (DEBUG_LAYOUT && gone) Slog.v(TAG, "  (mViewVisibility="
-                            + win.mViewVisibility + " mRelayoutCalled="
-                            + win.mRelayoutCalled + " hidden="
-                            + win.mRootToken.hidden + " hiddenRequested="
-                            + (atoken != null && atoken.hiddenRequested)
-                            + " mAttachedHidden=" + win.mAttachedHidden);
-                }
-                
-                // If this view is GONE, then skip it -- keep the current
-                // frame, and let the caller know so they can ignore it
-                // if they want.  (We do the normal layout for INVISIBLE
-                // windows, since that means "perform layout as normal,
-                // just don't display").
-                if (!gone || !win.mHaveFrame) {
-                    if (!win.mLayoutAttached) {
-                        mPolicy.layoutWindowLw(win, win.mAttrs, null);
-                        win.mLayoutSeq = seq;
-                        if (DEBUG_LAYOUT) Slog.v(TAG, "-> mFrame="
-                                + win.mFrame + " mContainingFrame="
-                                + win.mContainingFrame + " mDisplayFrame="
-                                + win.mDisplayFrame);
-                    } else {
-                        if (topAttached < 0) topAttached = i;
-                    }
-                }
-            }
-
-            // Now perform layout of attached windows, which usually
-            // depend on the position of the window they are attached to.
-            // XXX does not deal with windows that are attached to windows
-            // that are themselves attached.
-            for (i = topAttached; i >= 0; i--) {
-                WindowState win = (WindowState) mWindows.get(i);
-
-                // If this view is GONE, then skip it -- keep the current
-                // frame, and let the caller know so they can ignore it
-                // if they want.  (We do the normal layout for INVISIBLE
-                // windows, since that means "perform layout as normal,
-                // just don't display").
-                if (win.mLayoutAttached) {
-                    if (DEBUG_LAYOUT) Slog.v(TAG, "Second pass " + win
-                            + " mHaveFrame=" + win.mHaveFrame
-                            + " mViewVisibility=" + win.mViewVisibility
-                            + " mRelayoutCalled=" + win.mRelayoutCalled);
-                    if ((win.mViewVisibility != View.GONE && win.mRelayoutCalled)
-                            || !win.mHaveFrame) {
-                        mPolicy.layoutWindowLw(win, win.mAttrs, win.mAttachedWindow);
-                        win.mLayoutSeq = seq;
-                        if (DEBUG_LAYOUT) Slog.v(TAG, "-> mFrame="
-                                + win.mFrame + " mContainingFrame="
-                                + win.mContainingFrame + " mDisplayFrame="
-                                + win.mDisplayFrame);
-                    }
-                }
-            }
-
-            int changes = mPolicy.finishLayoutLw();
-            if ((changes&WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
-                if ((adjustWallpaperWindowsLocked()&ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) {
-                    assignLayersLocked();
-                }
-            }
-            if (changes == 0) {
-                mLayoutNeeded = false;
-            } else if (repeats > 2) {
-                Slog.w(TAG, "Layout repeat aborted after too many iterations");
-                mLayoutNeeded = false;
-                if ((changes&WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG) != 0) {
-                    if (updateOrientationFromAppTokensLocked()) {
-                        mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
-                    }
-                }
-            } else {
-                if (DEBUG_LAYOUT) Slog.v(TAG, "Repeating layout because changes=0x"
-                        + Integer.toHexString(changes));
-                repeats++;
-                if ((changes&WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG) != 0) {
-                    if (DEBUG_LAYOUT) Slog.v(TAG, "Computing new config from layout");
-                    if (updateOrientationFromAppTokensLocked()) {
-                        mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
-                    }
+                    mPolicy.layoutWindowLw(win, win.mAttrs, null);
+                    win.mLayoutSeq = seq;
+                    if (DEBUG_LAYOUT) Slog.v(TAG, "-> mFrame="
+                            + win.mFrame + " mContainingFrame="
+                            + win.mContainingFrame + " mDisplayFrame="
+                            + win.mDisplayFrame);
+                } else {
+                    if (topAttached < 0) topAttached = i;
                 }
             }
         }
+
+        // Now perform layout of attached windows, which usually
+        // depend on the position of the window they are attached to.
+        // XXX does not deal with windows that are attached to windows
+        // that are themselves attached.
+        for (i = topAttached; i >= 0; i--) {
+            WindowState win = (WindowState) mWindows.get(i);
+
+            // If this view is GONE, then skip it -- keep the current
+            // frame, and let the caller know so they can ignore it
+            // if they want.  (We do the normal layout for INVISIBLE
+            // windows, since that means "perform layout as normal,
+            // just don't display").
+            if (win.mLayoutAttached) {
+                if (DEBUG_LAYOUT) Slog.v(TAG, "Second pass " + win
+                        + " mHaveFrame=" + win.mHaveFrame
+                        + " mViewVisibility=" + win.mViewVisibility
+                        + " mRelayoutCalled=" + win.mRelayoutCalled);
+                if ((win.mViewVisibility != View.GONE && win.mRelayoutCalled)
+                        || !win.mHaveFrame) {
+                    mPolicy.layoutWindowLw(win, win.mAttrs, win.mAttachedWindow);
+                    win.mLayoutSeq = seq;
+                    if (DEBUG_LAYOUT) Slog.v(TAG, "-> mFrame="
+                            + win.mFrame + " mContainingFrame="
+                            + win.mContainingFrame + " mDisplayFrame="
+                            + win.mDisplayFrame);
+                }
+            }
+        }
+
+        return mPolicy.finishLayoutLw();
     }
 
     private final void performLayoutAndPlaceSurfacesLockedInner(
@@ -9423,9 +9457,6 @@
             updateFocusedWindowLocked(UPDATE_FOCUS_WILL_PLACE_SURFACES);
         }
         
-        // FIRST LOOP: Perform a layout, if needed.
-        performLayoutLockedInner();
-
         if (mFxSession == null) {
             mFxSession = new SurfaceSession();
         }
@@ -9442,7 +9473,6 @@
             mExitingAppTokens.get(i).hasVisible = false;
         }
 
-        // SECOND LOOP: Execute animations and update visibility of windows.
         boolean orientationChangeComplete = true;
         Session holdScreen = null;
         float screenBrightness = -1;
@@ -9452,11 +9482,50 @@
 
         Surface.openTransaction();
         try {
-            boolean restart;
-            boolean forceHiding = false;
             boolean wallpaperForceHidingChanged = false;
-
+            int repeats = 0;
+            int changes = 0;
+            
             do {
+                repeats++;
+                if (repeats > 6) {
+                    Slog.w(TAG, "Animation repeat aborted after too many iterations");
+                    mLayoutNeeded = false;
+                    break;
+                }
+                
+                if ((changes&(WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER
+                        | WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG
+                        | WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT)) != 0) {
+                    if ((changes&WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER) != 0) {
+                        if ((adjustWallpaperWindowsLocked()&ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) {
+                            assignLayersLocked();
+                            mLayoutNeeded = true;
+                        }
+                    }
+                    if ((changes&WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG) != 0) {
+                        if (DEBUG_LAYOUT) Slog.v(TAG, "Computing new config from layout");
+                        if (updateOrientationFromAppTokensLocked()) {
+                            mLayoutNeeded = true;
+                            mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
+                        }
+                    }
+                    if ((changes&WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT) != 0) {
+                        mLayoutNeeded = true;
+                    }
+                }
+                
+                // FIRST LOOP: Perform a layout, if needed.
+                if (repeats < 4) {
+                    changes = performLayoutLockedInner();
+                    if (changes != 0) {
+                        continue;
+                    }
+                } else {
+                    Slog.w(TAG, "Layout repeat skipped after too many iterations");
+                    changes = 0;
+                }
+                
                 final int transactionSequence = ++mTransactionSequence;
 
                 // Update animations of all applications, including those
@@ -9475,15 +9544,17 @@
                     }
                 }
 
+                // SECOND LOOP: Execute animations and update visibility of windows.
+                
                 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "*** ANIM STEP: seq="
                         + transactionSequence + " tokensAnimating="
                         + tokensAnimating);
                         
                 animating = tokensAnimating;
-                restart = false;
 
                 boolean tokenMayBeDrawn = false;
                 boolean wallpaperMayChange = false;
+                boolean forceHiding = false;
 
                 mPolicy.beginAnimationLw(dw, dh);
 
@@ -9536,7 +9607,7 @@
                                         "Now policy shown: " + w);
                                 if (changed) {
                                     if (wallpaperForceHidingChanged
-                                            && w.isReadyForDisplay()) {
+                                            && w.isVisibleNow() /*w.isReadyForDisplay()*/) {
                                         // Assume we will need to animate.  If
                                         // we don't (because the wallpaper will
                                         // stay with the lock screen), then we will
@@ -9609,9 +9680,7 @@
                     }
                 }
 
-                if (mPolicy.finishAnimationLw()) {
-                    restart = true;
-                }
+                changes |= mPolicy.finishAnimationLw();
 
                 if (tokenMayBeDrawn) {
                     // See if any windows have been drawn, so they (and others
@@ -9641,7 +9710,7 @@
                                         + " interesting=" + numInteresting
                                         + " drawn=" + wtoken.numDrawnWindows);
                                 wtoken.allDrawn = true;
-                                restart = true;
+                                changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_ANIM;
 
                                 // We can now show all of the drawn windows!
                                 if (!mOpeningApps.contains(wtoken)) {
@@ -9856,15 +9925,13 @@
 
                         // This has changed the visibility of windows, so perform
                         // a new layout to get them all up-to-date.
+                        changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
                         mLayoutNeeded = true;
                         if (!moveInputMethodWindowsIfNeededLocked(true)) {
                             assignLayersLocked();
                         }
-                        performLayoutLockedInner();
                         updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES);
                         mFocusMayChange = false;
-
-                        restart = true;
                     }
                 }
 
@@ -9880,10 +9947,9 @@
                     mToBottomApps.clear();
 
                     rebuildAppWindowListLocked();
-                    restart = true;
+                    changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
                     moveInputMethodWindowsIfNeededLocked(false);
                     wallpaperMayChange = true;
-                    mLayoutNeeded = true;
                     // Since the window list has been rebuilt, focus might
                     // have to be recomputed since the actual order of windows
                     // might have changed again.
@@ -9892,7 +9958,7 @@
 
                 int adjResult = 0;
 
-                if (wallpaperForceHidingChanged && !restart && !mAppTransitionReady) {
+                if (wallpaperForceHidingChanged && changes == 0 && !mAppTransitionReady) {
                     // At this point, there was a window with a wallpaper that
                     // was force hiding other windows behind it, but now it
                     // is going away.  This may be simple -- just animate
@@ -9913,7 +9979,7 @@
                             // actually started the animation...  let's completely
                             // re-evaluate everything.
                             mLowerWallpaperTarget = mUpperWallpaperTarget = null;
-                            restart = true;
+                            changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_ANIM;
                         }
                     }
                     adjResult = adjustWallpaperWindowsLocked();
@@ -9954,33 +10020,30 @@
                 if ((adjResult&ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) {
                     if (DEBUG_WALLPAPER) Slog.v(TAG,
                             "Wallpaper layer changed: assigning layers + relayout");
-                    restart = true;
-                    mLayoutNeeded = true;
+                    changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
                     assignLayersLocked();
                 } else if ((adjResult&ADJUST_WALLPAPER_VISIBILITY_CHANGED) != 0) {
                     if (DEBUG_WALLPAPER) Slog.v(TAG,
                             "Wallpaper visibility changed: relayout");
-                    restart = true;
-                    mLayoutNeeded = true;
+                    changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
                 }
 
                 if (mFocusMayChange) {
                     mFocusMayChange = false;
                     if (updateFocusedWindowLocked(UPDATE_FOCUS_PLACING_SURFACES)) {
-                        restart = true;
+                        changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_ANIM;
                         adjResult = 0;
                     }
                 }
 
                 if (mLayoutNeeded) {
-                    restart = true;
-                    performLayoutLockedInner();
+                    changes |= PhoneWindowManager.FINISH_LAYOUT_REDO_LAYOUT;
                 }
 
-                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "*** ANIM STEP: restart="
-                        + restart);
+                if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "*** ANIM STEP: changes=0x"
+                        + Integer.toHexString(changes));
                 
-            } while (restart);
+            } while (changes != 0);
 
             // THIRD LOOP: Update the surfaces of all windows.
 
@@ -10022,10 +10085,9 @@
                         w.mLastRequestedHeight = height;
                         w.mLastShownFrame.set(w.mShownFrame);
                         try {
-                            if (SHOW_TRANSACTIONS) Slog.i(
-                                    TAG, "  SURFACE " + w.mSurface
-                                    + ": POS " + w.mShownFrame.left
-                                    + ", " + w.mShownFrame.top);
+                            if (SHOW_TRANSACTIONS) logSurface(w,
+                                    "POS " + w.mShownFrame.left
+                                    + ", " + w.mShownFrame.top, null);
                             w.mSurface.setPosition(w.mShownFrame.left, w.mShownFrame.top);
                         } catch (RuntimeException e) {
                             Slog.w(TAG, "Error positioning surface in " + w, e);
@@ -10045,12 +10107,11 @@
                         if (height < 1) height = 1;
                         if (w.mSurface != null) {
                             try {
-                                if (SHOW_TRANSACTIONS) Slog.i(
-                                        TAG, "  SURFACE " + w.mSurface + ": POS "
-                                        + w.mShownFrame.left + ","
+                                if (SHOW_TRANSACTIONS) logSurface(w,
+                                        "POS " + w.mShownFrame.left + ","
                                         + w.mShownFrame.top + " SIZE "
                                         + w.mShownFrame.width() + "x"
-                                        + w.mShownFrame.height());
+                                        + w.mShownFrame.height(), null);
                                 w.mSurface.setSize(width, height);
                                 w.mSurface.setPosition(w.mShownFrame.left,
                                         w.mShownFrame.top);
@@ -10136,8 +10197,8 @@
                         if (!w.mLastHidden) {
                             //dump();
                             w.mLastHidden = true;
-                            if (SHOW_TRANSACTIONS) Slog.i(
-                                    TAG, "  SURFACE " + w.mSurface + ": HIDE (performLayout)");
+                            if (SHOW_TRANSACTIONS) logSurface(w,
+                                    "HIDE (performLayout)", null);
                             if (w.mSurface != null) {
                                 try {
                                     w.mSurface.hide();
@@ -10176,13 +10237,12 @@
                         w.mLastDtDy = w.mDtDy;
                         w.mLastHScale = w.mHScale;
                         w.mLastVScale = w.mVScale;
-                        if (SHOW_TRANSACTIONS) Slog.i(
-                                TAG, "  SURFACE " + w.mSurface + ": alpha="
-                                + w.mShownAlpha + " layer=" + w.mAnimLayer
+                        if (SHOW_TRANSACTIONS) logSurface(w,
+                                "alpha=" + w.mShownAlpha + " layer=" + w.mAnimLayer
                                 + " matrix=[" + (w.mDsDx*w.mHScale)
                                 + "," + (w.mDtDx*w.mVScale)
                                 + "][" + (w.mDsDy*w.mHScale)
-                                + "," + (w.mDtDy*w.mVScale) + "]");
+                                + "," + (w.mDtDy*w.mVScale) + "]", null);
                         if (w.mSurface != null) {
                             try {
                                 w.mSurface.setAlpha(w.mShownAlpha);
@@ -10201,8 +10261,8 @@
                         if (w.mLastHidden && !w.mDrawPending
                                 && !w.mCommitDrawPending
                                 && !w.mReadyToShow) {
-                            if (SHOW_TRANSACTIONS) Slog.i(
-                                    TAG, "  SURFACE " + w.mSurface + ": SHOW (performLayout)");
+                            if (SHOW_TRANSACTIONS) logSurface(w,
+                                    "SHOW (performLayout)", null);
                             if (DEBUG_VISIBILITY) Slog.v(TAG, "Showing " + w
                                     + " during relayout");
                             if (showSurfaceRobustlyLocked(w)) {
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index b53100f..f6289ae 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -13226,9 +13226,11 @@
                     ac.updateConfiguration(mConfiguration);
                 }
 
-                Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
-                msg.obj = new Configuration(mConfiguration);
-                mHandler.sendMessage(msg);
+                if (Settings.System.hasInterestingConfigurationChanges(changes)) {
+                    Message msg = mHandler.obtainMessage(UPDATE_CONFIGURATION_MSG);
+                    msg.obj = new Configuration(mConfiguration);
+                    mHandler.sendMessage(msg);
+                }
         
                 for (int i=mLruProcesses.size()-1; i>=0; i--) {
                     ProcessRecord app = mLruProcesses.get(i);
diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java
index e52cd47..ebd3314 100644
--- a/services/java/com/android/server/connectivity/Tethering.java
+++ b/services/java/com/android/server/connectivity/Tethering.java
@@ -33,6 +33,7 @@
 import android.net.NetworkInfo;
 import android.os.BatteryManager;
 import android.os.Binder;
+import android.os.Environment;
 import android.os.IBinder;
 import android.os.INetworkManagementService;
 import android.os.Message;
@@ -72,7 +73,7 @@
     private String[] mTetherableWifiRegexs;
     private String[] mUpstreamIfaceRegexs;
 
-    private HashMap<String, TetherInterfaceSM> mIfaces;
+    private HashMap<String, TetherInterfaceSM> mIfaces; // all tethered/tetherable ifaces
 
     private BroadcastReceiver mStateReceiver;
 
@@ -86,14 +87,20 @@
     private static final String DNS_DEFAULT_SERVER1 = "8.8.8.8";
     private static final String DNS_DEFAULT_SERVER2 = "4.2.2.2";
 
-    private boolean mDunRequired;
+    private boolean mDunRequired;  // configuration info - must use DUN apn on 3g
     private boolean mUseHiPri;
+
     private String mUpstreamIfaceName;
 
     private HierarchicalStateMachine mTetherMasterSM;
 
     private Notification mTetheredNotification;
 
+    // whether we can tether is the && of these two - they come in as separate
+    // broadcasts so track them so we can decide what to do when either changes
+    private boolean mUsbMassStorageOff;  // track the status of USB Mass Storage
+    private boolean mUsbConnected;       // track the status of USB connection
+
     public Tethering(Context context) {
         Log.d(TAG, "Tethering starting");
         mContext = context;
@@ -117,6 +124,10 @@
         filter.addAction(Intent.ACTION_BATTERY_CHANGED);
         filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
         filter.addAction(Intent.ACTION_BOOT_COMPLETED);
+        filter.addAction(Intent.ACTION_MEDIA_SHARED);
+        filter.addAction(Intent.ACTION_MEDIA_UNSHARED);
+        mUsbMassStorageOff = !Environment.MEDIA_SHARED.equals(
+                Environment.getExternalStorageState());
         mStateReceiver = new StateReceiver();
         mContext.registerReceiver(mStateReceiver, filter);
 
@@ -381,17 +392,28 @@
         }
     }
 
+    private void updateUsbStatus() {
+        boolean enable = mUsbConnected && mUsbMassStorageOff;
+
+        if (mBooted) {
+            enableUsbIfaces(enable);
+        }
+    }
+
     private class StateReceiver extends BroadcastReceiver {
         public void onReceive(Context content, Intent intent) {
             String action = intent.getAction();
             if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
-                boolean usbConnected = (intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1)
+                mUsbConnected = (intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1)
                         == BatteryManager.BATTERY_PLUGGED_USB);
-                if (mBooted) {
-                    Tethering.this.enableUsbIfaces(usbConnected); // add or remove them
-                } else {
-                    mDeferedUsbConnection = usbConnected;
-                }
+                Tethering.this.updateUsbStatus();
+            } else if (action.equals(Intent.ACTION_MEDIA_SHARED)) {
+                mUsbMassStorageOff = false;
+                updateUsbStatus();
+            }
+            else if (action.equals(Intent.ACTION_MEDIA_UNSHARED)) {
+                mUsbMassStorageOff = true;
+                updateUsbStatus();
             } else if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
                 IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
                 IConnectivityManager service = IConnectivityManager.Stub.asInterface(b);
@@ -409,9 +431,7 @@
                 } catch (RemoteException e) {}
             } else if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
                 mBooted = true;
-                if (mDeferedUsbConnection) {
-                    Tethering.this.enableUsbIfaces(true);
-                }
+                updateUsbStatus();
             }
         }
     }
diff --git a/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java b/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java
index 0b69020..8c8b00c 100755
--- a/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java
+++ b/tests/AndroidTests/src/com/android/unit_tests/PackageManagerTests.java
@@ -16,6 +16,8 @@
 
 package com.android.unit_tests;
 
+import com.android.internal.content.PackageHelper;
+
 import android.os.storage.IMountService.Stub;
 
 import android.net.Uri;
@@ -73,9 +75,9 @@
     public final long MAX_WAIT_TIME=120*1000;
     public final long WAIT_TIME_INCR=20*1000;
     private static final String SECURE_CONTAINERS_PREFIX = "/mnt/asec";
-    private static final int APP_INSTALL_AUTO = 0;
-    private static final int APP_INSTALL_DEVICE = 1;
-    private static final int APP_INSTALL_SDCARD = 2;
+    private static final int APP_INSTALL_AUTO = PackageHelper.APP_INSTALL_AUTO;
+    private static final int APP_INSTALL_DEVICE = PackageHelper.APP_INSTALL_INTERNAL;
+    private static final int APP_INSTALL_SDCARD = PackageHelper.APP_INSTALL_EXTERNAL;
 
     void failStr(String errMsg) {
         Log.w(TAG, "errMsg="+errMsg);
@@ -315,9 +317,9 @@
             if (!getInstallLoc(flags, expInstallLocation)) {
                 assertEquals(srcPath, appInstallPath);
                 assertEquals(publicSrcPath, appInstallPath);
-                assertFalse((info.flags & ApplicationInfo.FLAG_ON_SDCARD) != 0);
+                assertFalse((info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0);
             } else {
-                assertTrue((info.flags & ApplicationInfo.FLAG_ON_SDCARD) != 0);
+                assertTrue((info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0);
                 assertTrue(srcPath.startsWith(SECURE_CONTAINERS_PREFIX));
                 assertTrue(publicSrcPath.startsWith(SECURE_CONTAINERS_PREFIX));
             }
@@ -1172,9 +1174,9 @@
                 ApplicationInfo info = getPm().getApplicationInfo(ip.pkg.packageName, 0);
                 assertNotNull(info);
                 if ((moveFlags & PackageManager.MOVE_INTERNAL) != 0) {
-                    assertTrue((info.flags & ApplicationInfo.FLAG_ON_SDCARD) == 0);
+                    assertTrue((info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) == 0);
                 } else if ((moveFlags & PackageManager.MOVE_EXTERNAL_MEDIA) != 0){
-                    assertTrue((info.flags & ApplicationInfo.FLAG_ON_SDCARD) != 0);
+                    assertTrue((info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0);
                 }
             } else {
                 assertFalse(retCode);
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index 85665e0..ab5e937 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -13,7 +13,6 @@
 #include <stdarg.h>
 
 #define NOISY(x) //x
-#define NOISY_REF(x) //x
 
 status_t compileXmlFile(const sp<AaptAssets>& assets,
                         const sp<AaptFile>& target,
@@ -1934,7 +1933,7 @@
         // information we have already processed that string!
         outValue->size = sizeof(Res_value);
         outValue->res0 = 0;
-        outValue->dataType = Res_value::TYPE_STRING;
+        outValue->dataType = outValue->TYPE_STRING;
         outValue->data = 0;
         finalStr = str;
     }
@@ -1943,7 +1942,7 @@
         return false;
     }
 
-    if (outValue->dataType == Res_value::TYPE_STRING) {
+    if (outValue->dataType == outValue->TYPE_STRING) {
         // Should do better merging styles.
         if (pool) {
             if (style != NULL && style->size() > 0) {
@@ -2531,7 +2530,6 @@
     // Iterate through all data, collecting all values (strings,
     // references, etc).
     StringPool valueStrings = StringPool(false, bundle->getUTF8());
-    ResourceConfigReferences configRefs;
     for (pi=0; pi<N; pi++) {
         sp<Package> p = mOrderedPackages.itemAt(pi);
         if (p->getTypes().size() == 0) {
@@ -2572,13 +2570,6 @@
                     if (err != NO_ERROR) {
                         return err;
                     }
-                    if (e->getType() == Entry::TYPE_ITEM) {
-                        const Item* item = e->getItem();
-                        if (item != NULL) {
-                            uint32_t poolIndex = item->parsedValue.data;
-                            configRefs.add(poolIndex, config);
-                        }
-                    }
                 }
             }
         }
@@ -2587,70 +2578,6 @@
         p->setKeyStrings(keyStrings.createStringBlock());
     }
 
-    NOISY_REF(configRefs.dump();)
-
-    // Trim all entries in config tables that are not roots for that string.
-    // i.e., rely on the resource system to grab the string from the more
-    // generic pool during runtime to save space.
-    for (pi=0; pi<N; pi++) {
-        sp<Package> p = mOrderedPackages.itemAt(pi);
-        if (p->getTypes().size() == 0) {
-            // Empty, skip!
-            continue;
-        }
-        const size_t TN = p->getOrderedTypes().size();
-        for (size_t ti=0; ti<TN; ti++) {
-            sp<Type> t = p->getOrderedTypes().itemAt(ti);
-            if (t == NULL) {
-                continue;
-            }
-            size_t CN = t->getOrderedConfigs().size();
-            for (size_t ci=0; ci<CN; ci++) {
-                sp<ConfigList> c = t->getOrderedConfigs().itemAt(ci);
-                if (c == NULL) {
-                    continue;
-                }
-                DefaultKeyedVector<ConfigDescription, sp<Entry> > newEntries;
-                size_t EN = c->getEntries().size();
-                for (size_t ei=0; ei<EN; ++ei) {
-                    ConfigDescription config = c->getEntries().keyAt(ei);
-                    if (!filter.match(config)) {
-                        continue;
-                    }
-                    sp<Entry> e = c->getEntries().valueAt(ei);
-                    if (e == NULL) {
-                        continue;
-                    }
-                    if (e->getType() == Entry::TYPE_ITEM) {
-                        const Item* item = e->getItem();
-                        if (item != NULL) {
-                            uint32_t poolIndex = item->parsedValue.data;
-                            if (!configRefs.isRoot(poolIndex, config)) {
-                                NOISY_REF(
-                                    printf("  ConfigRef %d: removing ", poolIndex);
-                                    DEBUG_LANG(config)
-                                    printf("\n");
-                                )
-                                c->removeEntryAt(ei);
-                                t->removeUniqueConfig(config);
-                                --ei; --EN;
-                            }
-                        }
-                    }
-                }
-                if (EN == 0) {
-                    // We removed all the entries from a config, so remove the
-                    // config itself.
-                    NOISY_REF(
-                        printf("  ConfigRef REMOVED ENTIRE CONFIG\n");
-                    )
-                    t->removeOrderedConfigAt(ci);
-                    --ci; --CN;
-                }
-            }
-        }
-    }
-
     ssize_t strAmt = 0;
     
     // Now build the array of package chunks.
@@ -3805,95 +3732,3 @@
     }
     return res;
 }
-
-#define DEBUG_LANG(x) printf("lang=%c%c cnt=%c%c ", \
-        (x).language[0] ? (x).language[0] : '-', \
-        (x).language[1] ? (x).language[1] : '-', \
-        (x).country[0] ? (x).country[0] : '-', \
-        (x).country[1] ? (x).country[1] : '-');
-
-status_t ResourceConfigReferences::add(uint32_t id, const ResTable_config& config)
-{
-    ssize_t index = mRoots.indexOfKey(id);
-    if (index < 0) {
-        index = mRoots.add(id, Vector<const ResTable_config*>());
-    }
-    Vector<const ResTable_config*>& configRoots = mRoots.editValueFor(id);
-
-    if (!configRoots.isEmpty()) {
-        ssize_t NR = configRoots.size();
-        for (int ri=0; ri<NR; ++ri) {
-            const ResTable_config* current = configRoots[ri];
-
-            if (config.match(*current)) {
-                // We already have something more generic than our incoming string.
-                NOISY_REF(
-                    printf("  ConfigRef %d: ignoring ", id);
-                    DEBUG_LANG(config)
-                    printf("\n");
-                )
-                return NO_ERROR;
-            } else if (current->match(config)) {
-                // more generic
-                NOISY_REF(
-                    printf("  ConfigRef %d: remove ", id);
-                    DEBUG_LANG(current)
-                    printf("\n");
-                )
-                configRoots.removeItemsAt(ri);
-                --ri; --NR;
-            }
-        }
-    }
-    NOISY_REF(
-        printf("  ConfigRef %d: add ", id);
-        DEBUG_LANG(config)
-        printf("\n");
-    )
-    ResTable_config *configCopy = (ResTable_config*)malloc(sizeof(ResTable_config));
-    memcpy(configCopy, &config, sizeof(ResTable_config));
-    configRoots.add(configCopy);
-
-    return NO_ERROR;
-}
-
-void ResourceConfigReferences::dump()
-{
-    printf("ResourceConfigReferences\n");
-    const ssize_t NR = mRoots.size();
-    for (int ri=0; ri<NR; ++ri) {
-        const Vector<const ResTable_config*>& configRoots = mRoots.valueAt(ri);
-        printf("  String %d\n", mRoots.keyAt(ri));
-        const ssize_t NC = configRoots.size();
-        for (int ci=0; ci<NC; ++ci) {
-            printf("    ");
-            DEBUG_LANG(*configRoots[ci])
-            printf("\n");
-        }
-    }
-}
-
-bool ResourceConfigReferences::isRoot(uint32_t id, const ResTable_config& config)
-{
-    const Vector<const ResTable_config*>& configRoots = mRoots.editValueFor(id);
-    const ssize_t NR = configRoots.size();
-    for (int ri = 0; ri<NR; ++ri) {
-        if (configRoots[ri]->match(config)) {
-            return true;
-        }
-    }
-    return false;
-}
-
-ResourceConfigReferences::~ResourceConfigReferences()
-{
-    const ssize_t NR = mRoots.size();
-    for (int ri=0; ri<NR; ++ri) {
-        Vector<const ResTable_config*> configRoots = mRoots.editValueAt(ri);
-        const ssize_t NC = configRoots.size();
-        for (int ci=0; ci<NC; ++ci) {
-            ResTable_config* config = const_cast<ResTable_config*>(configRoots[ci]);
-            free(config);
-        }
-    }
-}
diff --git a/tools/aapt/ResourceTable.h b/tools/aapt/ResourceTable.h
index cc2a429..186c7ca 100644
--- a/tools/aapt/ResourceTable.h
+++ b/tools/aapt/ResourceTable.h
@@ -376,10 +376,6 @@
         void addEntry(const ResTable_config& config, const sp<Entry>& entry) {
             mEntries.add(config, entry);
         }
-
-        void removeEntryAt(int32_t index) {
-            mEntries.removeItemsAt(index);
-        }
         
         const DefaultKeyedVector<ConfigDescription, sp<Entry> >& getEntries() const { return mEntries; }
     private:
@@ -452,9 +448,6 @@
         const DefaultKeyedVector<String16, sp<ConfigList> >& getConfigs() const { return mConfigs; }
         const Vector<sp<ConfigList> >& getOrderedConfigs() const { return mOrderedConfigs; }
 
-        void removeUniqueConfig(ConfigDescription& config) { mUniqueConfigs.remove(config); }
-        void removeOrderedConfigAt(uint32_t index) { mOrderedConfigs.removeItemsAt(index); }
-
         const SortedVector<String16>& getCanAddEntries() const { return mCanAddEntries; }
         
         const SourcePos& getPos() const { return mPos; }
@@ -565,17 +558,5 @@
     bool mContainsPseudo;
 };
 
-class ResourceConfigReferences
-{
-public:
-    ResourceConfigReferences() : mRoots() {}
-    ~ResourceConfigReferences();
-    status_t add(uint32_t id, const ResTable_config& config);
-    bool isRoot(uint32_t id, const ResTable_config& config);
-    void dump();
-
-private:
-    KeyedVector<uint32_t, Vector<const ResTable_config*> > mRoots;
-};
 
 #endif
diff --git a/wifi/java/android/net/wifi/WifiStateTracker.java b/wifi/java/android/net/wifi/WifiStateTracker.java
index cc47d08..9339428 100644
--- a/wifi/java/android/net/wifi/WifiStateTracker.java
+++ b/wifi/java/android/net/wifi/WifiStateTracker.java
@@ -16,6 +16,12 @@
 
 package android.net.wifi;
 
+import static android.net.wifi.WifiManager.WIFI_STATE_DISABLED;
+import static android.net.wifi.WifiManager.WIFI_STATE_DISABLING;
+import static android.net.wifi.WifiManager.WIFI_STATE_ENABLED;
+import static android.net.wifi.WifiManager.WIFI_STATE_ENABLING;
+import static android.net.wifi.WifiManager.WIFI_STATE_UNKNOWN;
+
 import android.app.ActivityManagerNative;
 import android.net.NetworkInfo;
 import android.net.NetworkStateTracker;
@@ -270,6 +276,14 @@
     private boolean mIsScanModeActive;
     private boolean mEnableRssiPolling;
 
+    /**
+     * One of  {@link WifiManager#WIFI_STATE_DISABLED},
+     *         {@link WifiManager#WIFI_STATE_DISABLING},
+     *         {@link WifiManager#WIFI_STATE_ENABLED},
+     *         {@link WifiManager#WIFI_STATE_ENABLING},
+     *         {@link WifiManager#WIFI_STATE_UNKNOWN}
+     */
+    private int mWifiState;
     // Wi-Fi run states:
     private static final int RUN_STATE_STARTING = 1;
     private static final int RUN_STATE_RUNNING  = 2;
@@ -771,9 +785,8 @@
             case EVENT_SUPPLICANT_DISCONNECT:
                 mRunState = RUN_STATE_STOPPED;
                 noteRunState();
-                int wifiState = mWM.getWifiState();
-                boolean died = wifiState != WifiManager.WIFI_STATE_DISABLED &&
-                        wifiState != WifiManager.WIFI_STATE_DISABLING;
+                boolean died = mWifiState != WIFI_STATE_DISABLED &&
+                               mWifiState != WIFI_STATE_DISABLING;
                 if (died) {
                     if (LOCAL_LOGD) Log.v(TAG, "Supplicant died unexpectedly");
                 } else {
@@ -1487,143 +1500,436 @@
         return true;
     }
 
-    /**
-     * TODO: add documentation to all the native calls
-     * along with conditional checks to make sure
-     * native calls dont happen when wifi is not enabled
+    public synchronized int getWifiState() {
+        return mWifiState;
+    }
+
+    public synchronized void setWifiState(int wifiState) {
+        mWifiState = wifiState;
+    }
+
+   /**
+     * The WifiNative interface functions are listed below.
+     * The only native call that is not synchronized on
+     * WifiStateTracker is waitForEvent() which waits on a
+     * seperate monitor channel.
+     *
+     * All supplicant commands need the wifi to be in an
+     * enabled state. This can be done by checking the
+     * mWifiState to be WIFI_STATE_ENABLED.
+     *
+     * All commands that can cause commands to driver
+     * initiated need the driver state to be started.
+     * This is done by checking isDriverStopped() to
+     * be false.
      */
 
+    /**
+     * Load the driver and firmware
+     *
+     * @return {@code true} if the operation succeeds, {@code false} otherwise
+     */
     public synchronized boolean loadDriver() {
         return WifiNative.loadDriver();
     }
 
+    /**
+     * Unload the driver and firmware
+     *
+     * @return {@code true} if the operation succeeds, {@code false} otherwise
+     */
     public synchronized boolean unloadDriver() {
         return WifiNative.unloadDriver();
     }
 
+    /**
+     * Check the supplicant config and
+     * start the supplicant daemon
+     *
+     * @return {@code true} if the operation succeeds, {@code false} otherwise
+     */
     public synchronized boolean startSupplicant() {
         return WifiNative.startSupplicant();
     }
 
+    /**
+     * Stop the supplicant daemon
+     *
+     * @return {@code true} if the operation succeeds, {@code false} otherwise
+     */
     public synchronized boolean stopSupplicant() {
         return WifiNative.stopSupplicant();
     }
 
+    /**
+     * Establishes two channels - control channel for commands
+     * and monitor channel for notifying WifiMonitor
+     *
+     * @return {@code true} if the operation succeeds, {@code false} otherwise
+     */
     public synchronized boolean connectToSupplicant() {
         return WifiNative.connectToSupplicant();
     }
 
+    /**
+     * Close the control/monitor channels to supplicant
+     */
     public synchronized void closeSupplicantConnection() {
         WifiNative.closeSupplicantConnection();
     }
 
+    /**
+     * Check if the supplicant is alive
+     *
+     * @return {@code true} if the operation succeeds, {@code false} otherwise
+     */
     public synchronized boolean ping() {
+        if (mWifiState != WIFI_STATE_ENABLED) {
+            return false;
+        }
         return WifiNative.pingCommand();
     }
 
+    /**
+     * initiate an active or passive scan
+     *
+     * @param forceActive true if it is a active scan
+     * @return {@code true} if the operation succeeds, {@code false} otherwise
+     */
     public synchronized boolean scan(boolean forceActive) {
+        if (mWifiState != WIFI_STATE_ENABLED && !isDriverStopped()) {
+            return false;
+        }
         return WifiNative.scanCommand(forceActive);
     }
 
+    /**
+     * Specifies whether the supplicant or driver
+     * take care of initiating scan and doing AP selection
+     *
+     * @param mode
+     *    SUPPL_SCAN_HANDLING_NORMAL
+     *    SUPPL_SCAN_HANDLING_LIST_ONLY
+     * @return {@code true} if the operation succeeds, {@code false} otherwise
+     */
     public synchronized boolean setScanResultHandling(int mode) {
+        if (mWifiState != WIFI_STATE_ENABLED && !isDriverStopped()) {
+            return false;
+        }
         return WifiNative.setScanResultHandlingCommand(mode);
     }
 
+    /**
+     * Fetch the scan results from the supplicant
+     *
+     * @return example result string
+     * 00:bb:cc:dd:cc:ee       2427    166     [WPA-EAP-TKIP][WPA2-EAP-CCMP]   Net1
+     * 00:bb:cc:dd:cc:ff       2412    165     [WPA-EAP-TKIP][WPA2-EAP-CCMP]   Net2
+     */
     public synchronized String scanResults() {
+        if (mWifiState != WIFI_STATE_ENABLED && !isDriverStopped()) {
+            return null;
+        }
         return WifiNative.scanResultsCommand();
     }
 
-    public synchronized void setScanMode(boolean isScanModeActive) {
-        if (mIsScanModeActive != isScanModeActive) {
-            WifiNative.setScanModeCommand(mIsScanModeActive = isScanModeActive);
+    /**
+     * Set the scan mode - active or passive
+     *
+     * @return {@code true} if the operation succeeds, {@code false} otherwise
+     */
+    public synchronized boolean setScanMode(boolean isScanModeActive) {
+        if (mWifiState != WIFI_STATE_ENABLED && !isDriverStopped()) {
+            return false;
         }
+        if (mIsScanModeActive != isScanModeActive) {
+            return WifiNative.setScanModeCommand(mIsScanModeActive = isScanModeActive);
+        }
+        return true;
     }
 
+    /**
+     * Disconnect from Access Point
+     *
+     * @return {@code true} if the operation succeeds, {@code false} otherwise
+     */
     public synchronized boolean disconnect() {
+        if (mWifiState != WIFI_STATE_ENABLED && !isDriverStopped()) {
+            return false;
+        }
         return WifiNative.disconnectCommand();
     }
 
+    /**
+     * Initiate a reconnection to AP
+     *
+     * @return {@code true} if the operation succeeds, {@code false} otherwise
+     */
     public synchronized boolean reconnectCommand() {
+        if (mWifiState != WIFI_STATE_ENABLED && !isDriverStopped()) {
+            return false;
+        }
         return WifiNative.reconnectCommand();
     }
 
+    /**
+     * Add a network
+     *
+     * @return network id of the new network
+     */
     public synchronized int addNetwork() {
+        if (mWifiState != WIFI_STATE_ENABLED) {
+            return -1;
+        }
         return WifiNative.addNetworkCommand();
     }
 
+    /**
+     * Delete a network
+     *
+     * @param networkId id of the network to be removed
+     * @return {@code true} if the operation succeeds, {@code false} otherwise
+     */
     public synchronized boolean removeNetwork(int networkId) {
+        if (mWifiState != WIFI_STATE_ENABLED) {
+            return false;
+        }
         return mDisconnectExpected = WifiNative.removeNetworkCommand(networkId);
     }
 
+    /**
+     * Enable a network
+     *
+     * @param netId network id of the network
+     * @param disableOthers true, if all other networks have to be disabled
+     * @return {@code true} if the operation succeeds, {@code false} otherwise
+     */
     public synchronized boolean enableNetwork(int netId, boolean disableOthers) {
+        if (mWifiState != WIFI_STATE_ENABLED) {
+            return false;
+        }
         return WifiNative.enableNetworkCommand(netId, disableOthers);
     }
 
+    /**
+     * Disable a network
+     *
+     * @param netId network id of the network
+     * @return {@code true} if the operation succeeds, {@code false} otherwise
+     */
     public synchronized boolean disableNetwork(int netId) {
+        if (mWifiState != WIFI_STATE_ENABLED) {
+            return false;
+        }
         return WifiNative.disableNetworkCommand(netId);
     }
 
+    /**
+     * Initiate a re-association in supplicant
+     *
+     * @return {@code true} if the operation succeeds, {@code false} otherwise
+     */
     public synchronized boolean reassociate() {
+        if (mWifiState != WIFI_STATE_ENABLED && !isDriverStopped()) {
+            return false;
+        }
         return WifiNative.reassociateCommand();
     }
 
+    /**
+     * Blacklist a BSSID. This will avoid the AP if there are
+     * alternate APs to connect
+     *
+     * @param bssid BSSID of the network
+     * @return {@code true} if the operation succeeds, {@code false} otherwise
+     */
     public synchronized boolean addToBlacklist(String bssid) {
+        if (mWifiState != WIFI_STATE_ENABLED) {
+            return false;
+        }
         return WifiNative.addToBlacklistCommand(bssid);
     }
 
+    /**
+     * Clear the blacklist list
+     *
+     * @return {@code true} if the operation succeeds, {@code false} otherwise
+     */
     public synchronized boolean clearBlacklist() {
+        if (mWifiState != WIFI_STATE_ENABLED) {
+            return false;
+        }
         return WifiNative.clearBlacklistCommand();
     }
 
+    /**
+     * List all configured networks
+     *
+     * @return list of networks or null on failure
+     */
     public synchronized String listNetworks() {
+        if (mWifiState != WIFI_STATE_ENABLED) {
+            return null;
+        }
         return WifiNative.listNetworksCommand();
     }
 
+    /**
+     * Get network setting by name
+     *
+     * @param netId network id of the network
+     * @param name network variable key
+     * @return value corresponding to key
+     */
     public synchronized String getNetworkVariable(int netId, String name) {
+        if (mWifiState != WIFI_STATE_ENABLED) {
+            return null;
+        }
         return WifiNative.getNetworkVariableCommand(netId, name);
     }
 
+    /**
+     * Set network setting by name
+     *
+     * @param netId network id of the network
+     * @param name network variable key
+     * @param value network variable value
+     * @return {@code true} if the operation succeeds, {@code false} otherwise
+     */
     public synchronized boolean setNetworkVariable(int netId, String name, String value) {
+        if (mWifiState != WIFI_STATE_ENABLED) {
+            return false;
+        }
         return WifiNative.setNetworkVariableCommand(netId, name, value);
     }
 
+    /**
+     * Get detailed status of the connection
+     *
+     * @return Example status result
+     *  bssid=aa:bb:cc:dd:ee:ff
+     *  ssid=TestNet
+     *  id=3
+     *  pairwise_cipher=NONE
+     *  group_cipher=NONE
+     *  key_mgmt=NONE
+     *  wpa_state=COMPLETED
+     *  ip_address=X.X.X.X
+     */
     public synchronized String status() {
+        if (mWifiState != WIFI_STATE_ENABLED) {
+            return null;
+        }
         return WifiNative.statusCommand();
     }
 
+    /**
+     * Get RSSI to currently connected network
+     *
+     * @return RSSI value, -1 on failure
+     */
     public synchronized int getRssi() {
+        if (mWifiState != WIFI_STATE_ENABLED && !isDriverStopped()) {
+            return -1;
+        }
         return WifiNative.getRssiApproxCommand();
     }
 
+    /**
+     * Get approx RSSI to currently connected network
+     *
+     * @return RSSI value, -1 on failure
+     */
     public synchronized int getRssiApprox() {
+        if (mWifiState != WIFI_STATE_ENABLED && !isDriverStopped()) {
+            return -1;
+        }
         return WifiNative.getRssiApproxCommand();
     }
 
+    /**
+     * Get link speed to currently connected network
+     *
+     * @return link speed, -1 on failure
+     */
     public synchronized int getLinkSpeed() {
+        if (mWifiState != WIFI_STATE_ENABLED && !isDriverStopped()) {
+            return -1;
+        }
         return WifiNative.getLinkSpeedCommand();
     }
 
+    /**
+     * Get MAC address of radio
+     *
+     * @return MAC address, null on failure
+     */
     public synchronized String getMacAddress() {
+        if (mWifiState != WIFI_STATE_ENABLED && !isDriverStopped()) {
+            return null;
+        }
         return WifiNative.getMacAddressCommand();
     }
 
+    /**
+     * Start driver
+     *
+     * @return {@code true} if the operation succeeds, {@code false} otherwise
+     */
     public synchronized boolean startDriver() {
+        if (mWifiState != WIFI_STATE_ENABLED) {
+            return false;
+        }
         return WifiNative.startDriverCommand();
     }
 
+    /**
+     * Stop driver
+     *
+     * @return {@code true} if the operation succeeds, {@code false} otherwise
+     */
     public synchronized boolean stopDriver() {
+        if (mWifiState != WIFI_STATE_ENABLED) {
+            return false;
+        }
         return WifiNative.stopDriverCommand();
     }
 
+    /**
+     * Start packet filtering
+     *
+     * @return {@code true} if the operation succeeds, {@code false} otherwise
+     */
     public synchronized boolean startPacketFiltering() {
+        if (mWifiState != WIFI_STATE_ENABLED && !isDriverStopped()) {
+            return false;
+        }
         return WifiNative.startPacketFiltering();
     }
 
+    /**
+     * Stop packet filtering
+     *
+     * @return {@code true} if the operation succeeds, {@code false} otherwise
+     */
     public synchronized boolean stopPacketFiltering() {
+        if (mWifiState != WIFI_STATE_ENABLED && !isDriverStopped()) {
+            return false;
+        }
         return WifiNative.stopPacketFiltering();
     }
 
+    /**
+     * Set power mode
+     * @param mode
+     *     DRIVER_POWER_MODE_AUTO
+     *     DRIVER_POWER_MODE_ACTIVE
+     * @return {@code true} if the operation succeeds, {@code false} otherwise
+     */
     public synchronized boolean setPowerMode(int mode) {
+        if (mWifiState != WIFI_STATE_ENABLED && !isDriverStopped()) {
+            return false;
+        }
         return WifiNative.setPowerModeCommand(mode);
     }
 
@@ -1634,6 +1940,9 @@
      * the number of channels is invalid.
      */
     public synchronized boolean setNumAllowedChannels() {
+        if (mWifiState != WIFI_STATE_ENABLED && !isDriverStopped()) {
+            return false;
+        }
         try {
             return setNumAllowedChannels(
                     Settings.Secure.getInt(mContext.getContentResolver(),
@@ -1656,15 +1965,38 @@
      * {@code numChannels} is outside the valid range.
      */
     public synchronized boolean setNumAllowedChannels(int numChannels) {
+        if (mWifiState != WIFI_STATE_ENABLED && !isDriverStopped()) {
+            return false;
+        }
         mNumAllowedChannels = numChannels;
         return WifiNative.setNumAllowedChannelsCommand(numChannels);
     }
 
+    /**
+     * Get number of allowed channels
+     *
+     * @return channel count, -1 on failure
+     */
     public synchronized int getNumAllowedChannels() {
+        if (mWifiState != WIFI_STATE_ENABLED && !isDriverStopped()) {
+            return -1;
+        }
         return WifiNative.getNumAllowedChannelsCommand();
     }
 
+    /**
+     * Set bluetooth coex mode:
+     *
+     * @param mode
+     *  BLUETOOTH_COEXISTENCE_MODE_ENABLED
+     *  BLUETOOTH_COEXISTENCE_MODE_DISABLED
+     *  BLUETOOTH_COEXISTENCE_MODE_SENSE
+     * @return {@code true} if the operation succeeds, {@code false} otherwise
+     */
     public synchronized boolean setBluetoothCoexistenceMode(int mode) {
+        if (mWifiState != WIFI_STATE_ENABLED && !isDriverStopped()) {
+            return false;
+        }
         return WifiNative.setBluetoothCoexistenceModeCommand(mode);
     }
 
@@ -1676,14 +2008,33 @@
      * @param isBluetoothPlaying whether to enable or disable this mode
      */
     public synchronized void setBluetoothScanMode(boolean isBluetoothPlaying) {
+        if (mWifiState != WIFI_STATE_ENABLED && !isDriverStopped()) {
+            return;
+        }
         WifiNative.setBluetoothCoexistenceScanModeCommand(isBluetoothPlaying);
     }
 
+    /**
+     * Save configuration on supplicant
+     *
+     * @return {@code true} if the operation succeeds, {@code false} otherwise
+     */
     public synchronized boolean saveConfig() {
+        if (mWifiState != WIFI_STATE_ENABLED) {
+            return false;
+        }
         return WifiNative.saveConfigCommand();
     }
 
+    /**
+     * Reload the configuration from file
+     *
+     * @return {@code true} if the operation succeeds, {@code false} otherwise
+     */
     public synchronized boolean reloadConfig() {
+        if (mWifiState != WIFI_STATE_ENABLED) {
+            return false;
+        }
         return WifiNative.reloadConfigCommand();
     }
 
@@ -1713,11 +2064,11 @@
 
     @Override
     public void interpretScanResultsAvailable() {
-        
+
         // If we shouldn't place a notification on available networks, then
         // don't bother doing any of the following
         if (!mNotificationEnabled) return;
-        
+
         NetworkInfo networkInfo = getNetworkInfo();
 
         State state = networkInfo.getState();