Merge "Remove copyBitmap from ImageProcessing."
diff --git a/api/17.txt b/api/17.txt
index ee9a973..84c2a93 100644
--- a/api/17.txt
+++ b/api/17.txt
@@ -28617,7 +28617,6 @@
     method public void setHeight(int);
     method public void setHorizontalOffset(int);
     method public void setInputMethodMode(int);
-    method public void setLayoutDirection(int);
     method public void setListSelector(android.graphics.drawable.Drawable);
     method public void setModal(boolean);
     method public void setOnDismissListener(android.widget.PopupWindow.OnDismissListener);
diff --git a/api/current.txt b/api/current.txt
index f8e31cb..e1aa9ef 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -7094,7 +7094,7 @@
     method public int getIndexCount();
     method public int getInt(int, int);
     method public int getInteger(int, int);
-    method public deprecated int getLayoutDimension(int, java.lang.String);
+    method public int getLayoutDimension(int, java.lang.String);
     method public int getLayoutDimension(int, int);
     method public java.lang.String getNonResourceString(int);
     method public java.lang.String getPositionDescription();
@@ -8263,6 +8263,7 @@
     method public int getScaledWidth(int);
     method public final int getWidth();
     method public final boolean hasAlpha();
+    method public final boolean hasMipMap();
     method public final boolean isMutable();
     method public final boolean isPremultiplied();
     method public final boolean isRecycled();
@@ -8271,6 +8272,7 @@
     method public boolean sameAs(android.graphics.Bitmap);
     method public void setDensity(int);
     method public void setHasAlpha(boolean);
+    method public final void setHasMipMap(boolean);
     method public void setPixel(int, int, int);
     method public void setPixels(int[], int, int, int, int, int, int);
     method public void writeToParcel(android.os.Parcel, int);
@@ -16149,7 +16151,7 @@
 
   public class Looper {
     method public void dump(android.util.Printer, java.lang.String);
-    method public static android.os.Looper getMainLooper();
+    method public static synchronized android.os.Looper getMainLooper();
     method public java.lang.Thread getThread();
     method public static void loop();
     method public static android.os.Looper myLooper();
@@ -28647,7 +28649,6 @@
     method public void setHeight(int);
     method public void setHorizontalOffset(int);
     method public void setInputMethodMode(int);
-    method public void setLayoutDirection(int);
     method public void setListSelector(android.graphics.drawable.Drawable);
     method public void setModal(boolean);
     method public void setOnDismissListener(android.widget.PopupWindow.OnDismissListener);
diff --git a/cmds/installd/Android.mk b/cmds/installd/Android.mk
index 3e722ea..1dd4ee5 100644
--- a/cmds/installd/Android.mk
+++ b/cmds/installd/Android.mk
@@ -29,17 +29,12 @@
     $(common_src_files)
 
 LOCAL_SHARED_LIBRARIES := \
-    libcutils
+    libcutils \
+    libselinux
 
 LOCAL_STATIC_LIBRARIES := \
     libdiskusage
 
-ifeq ($(HAVE_SELINUX),true)
-LOCAL_C_INCLUDES += external/libselinux/include
-LOCAL_SHARED_LIBRARIES += libselinux
-LOCAL_CFLAGS := -DHAVE_SELINUX
-endif # HAVE_SELINUX
-
 LOCAL_MODULE := installd
 
 LOCAL_MODULE_TAGS := optional
diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c
index a276225..4da772a 100644
--- a/cmds/installd/commands.c
+++ b/cmds/installd/commands.c
@@ -17,10 +17,7 @@
 #include <linux/capability.h>
 #include "installd.h"
 #include <diskusage/dirsize.h>
-
-#ifdef HAVE_SELINUX
 #include <selinux/android.h>
-#endif
 
 /* Directory records that are used in execution of commands. */
 dir_rec_t android_data_dir;
@@ -74,14 +71,19 @@
         return -1;
     }
 
-#ifdef HAVE_SELINUX
-    if (selinux_android_setfilecon(pkgdir, pkgname, uid) < 0) {
-        ALOGE("cannot setfilecon dir '%s': %s\n", pkgdir, strerror(errno));
+    if (selinux_android_setfilecon(libsymlink, pkgname, AID_SYSTEM) < 0) {
+        ALOGE("cannot setfilecon dir '%s': %s\n", libsymlink, strerror(errno));
         unlink(libsymlink);
         unlink(pkgdir);
         return -1;
     }
-#endif
+
+    if (selinux_android_setfilecon(pkgdir, pkgname, uid) < 0) {
+        ALOGE("cannot setfilecon dir '%s': %s\n", pkgdir, strerror(errno));
+        unlink(libsymlink);
+        unlink(pkgdir);
+        return -errno;
+    }
 
     if (chown(pkgdir, uid, gid) < 0) {
         ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno));
@@ -186,19 +188,16 @@
         unlink(pkgdir);
         return -errno;
     }
-    if (chown(pkgdir, uid, uid) < 0) {
-        ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno));
-        unlink(pkgdir);
-        return -errno;
-    }
-
-#ifdef HAVE_SELINUX
     if (selinux_android_setfilecon(pkgdir, pkgname, uid) < 0) {
         ALOGE("cannot setfilecon dir '%s': %s\n", pkgdir, strerror(errno));
         unlink(pkgdir);
         return -errno;
     }
-#endif
+    if (chown(pkgdir, uid, uid) < 0) {
+        ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno));
+        unlink(pkgdir);
+        return -errno;
+    }
 
     return 0;
 }
diff --git a/core/java/android/accounts/AccountManagerService.java b/core/java/android/accounts/AccountManagerService.java
index 5cde65c..03e0c0f 100644
--- a/core/java/android/accounts/AccountManagerService.java
+++ b/core/java/android/accounts/AccountManagerService.java
@@ -247,7 +247,6 @@
     }
 
     public void systemReady() {
-        initUser(UserHandle.USER_OWNER);
     }
 
     private UserManager getUserManager() {
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 7492629..67d3930 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -2809,6 +2809,15 @@
         return success;
     }
 
+    public void clearPendingBackup() throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        mRemote.transact(CLEAR_PENDING_BACKUP_TRANSACTION, data, reply, 0);
+        reply.recycle();
+        data.recycle();
+    }
+
     public void backupAgentCreated(String packageName, IBinder agent) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 5f65f08..456d757 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -29,6 +29,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
 import android.content.pm.InstrumentationInfo;
+import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ProviderInfo;
@@ -2396,12 +2397,31 @@
     private void handleCreateBackupAgent(CreateBackupAgentData data) {
         if (DEBUG_BACKUP) Slog.v(TAG, "handleCreateBackupAgent: " + data);
 
+        // Sanity check the requested target package's uid against ours
+        try {
+            PackageInfo requestedPackage = getPackageManager().getPackageInfo(
+                    data.appInfo.packageName, 0, UserHandle.myUserId());
+            if (requestedPackage.applicationInfo.uid != Process.myUid()) {
+                Slog.w(TAG, "Asked to instantiate non-matching package "
+                        + data.appInfo.packageName);
+                return;
+            }
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Can't reach package manager", e);
+            return;
+        }
+
         // no longer idle; we have backup work to do
         unscheduleGcIdler();
 
         // instantiate the BackupAgent class named in the manifest
         LoadedApk packageInfo = getPackageInfoNoCheck(data.appInfo, data.compatInfo);
         String packageName = packageInfo.mPackageName;
+        if (packageName == null) {
+            Slog.d(TAG, "Asked to create backup agent for nonexistent package");
+            return;
+        }
+
         if (mBackupAgents.get(packageName) != null) {
             Slog.d(TAG, "BackupAgent " + "  for " + packageName
                     + " already exists");
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 97250e9..8fc1c86 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -152,6 +152,7 @@
     
     public boolean bindBackupAgent(ApplicationInfo appInfo, int backupRestoreMode)
             throws RemoteException;
+    public void clearPendingBackup() throws RemoteException;
     public void backupAgentCreated(String packageName, IBinder agent) throws RemoteException;
     public void unbindBackupAgent(ApplicationInfo appInfo) throws RemoteException;
     public void killApplicationProcess(String processName, int uid) throws RemoteException;
@@ -619,4 +620,5 @@
     int GET_RUNNING_USER_IDS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+156;
     int REQUEST_BUG_REPORT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+157;
     int INPUT_DISPATCHING_TIMED_OUT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+158;
+    int CLEAR_PENDING_BACKUP_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+159;
 }
diff --git a/core/java/android/app/SharedPreferencesImpl.java b/core/java/android/app/SharedPreferencesImpl.java
index 201d7b2..86fd7b9 100644
--- a/core/java/android/app/SharedPreferencesImpl.java
+++ b/core/java/android/app/SharedPreferencesImpl.java
@@ -312,7 +312,8 @@
         }
         public Editor putStringSet(String key, Set<String> values) {
             synchronized (this) {
-                mModified.put(key, values);
+                mModified.put(key,
+                        (values == null) ? null : new HashSet<String>(values));
                 return this;
             }
         }
diff --git a/core/java/android/bluetooth/BluetoothSocket.java b/core/java/android/bluetooth/BluetoothSocket.java
index aba8710..8cbf5b1 100644
--- a/core/java/android/bluetooth/BluetoothSocket.java
+++ b/core/java/android/bluetooth/BluetoothSocket.java
@@ -19,6 +19,7 @@
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.util.List;
+import java.util.UUID;
 import android.net.LocalSocket;
 import java.nio.ByteOrder;
 import java.nio.ByteBuffer;
@@ -140,7 +141,9 @@
                 throw new IOException("Invalid RFCOMM channel: " + port);
             }
         }
-        mUuid = uuid;
+        if(uuid != null)
+            mUuid = uuid;
+        else mUuid = new ParcelUuid(new UUID(0, 0));
         mType = type;
         mAuth = auth;
         mEncrypt = encrypt;
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 9e406d4..b20cf88 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -169,6 +169,25 @@
     /** @hide */
     public static final int SYNC_ERROR_INTERNAL = 8;
 
+    private static final String[] SYNC_ERROR_NAMES = new String[] {
+          "already-in-progress",
+          "authentication-error",
+          "io-error",
+          "parse-error",
+          "conflict",
+          "too-many-deletions",
+          "too-many-retries",
+          "internal-error",
+    };
+
+    /** @hide */
+    static String syncErrorToString(int error) {
+        if (error < 1 || error > SYNC_ERROR_NAMES.length) {
+            return String.valueOf(error);
+        }
+        return SYNC_ERROR_NAMES[error - 1];
+    }
+
     public static final int SYNC_OBSERVER_TYPE_SETTINGS = 1<<0;
     public static final int SYNC_OBSERVER_TYPE_PENDING = 1<<1;
     public static final int SYNC_OBSERVER_TYPE_ACTIVE = 1<<2;
diff --git a/core/java/android/content/ContentService.java b/core/java/android/content/ContentService.java
index 4512e82..8bac888 100644
--- a/core/java/android/content/ContentService.java
+++ b/core/java/android/content/ContentService.java
@@ -226,6 +226,7 @@
             }
         }
 
+        final int uid = Binder.getCallingUid();
         // This makes it so that future permission checks will be in the context of this
         // process rather than the caller's process. We will restore this before returning.
         long identityToken = clearCallingIdentity();
@@ -264,7 +265,7 @@
             if (syncToNetwork) {
                 SyncManager syncManager = getSyncManager();
                 if (syncManager != null) {
-                    syncManager.scheduleLocalSync(null /* all accounts */, callingUserHandle,
+                    syncManager.scheduleLocalSync(null /* all accounts */, callingUserHandle, uid,
                             uri.getAuthority());
                 }
             }
@@ -300,6 +301,7 @@
     public void requestSync(Account account, String authority, Bundle extras) {
         ContentResolver.validateSyncExtrasBundle(extras);
         int userId = UserHandle.getCallingUserId();
+        int uId = Binder.getCallingUid();
 
         // This makes it so that future permission checks will be in the context of this
         // process rather than the caller's process. We will restore this before returning.
@@ -307,7 +309,7 @@
         try {
             SyncManager syncManager = getSyncManager();
             if (syncManager != null) {
-                syncManager.scheduleSync(account, userId, authority, extras, 0 /* no delay */,
+                syncManager.scheduleSync(account, userId, uId, authority, extras, 0 /* no delay */,
                         false /* onlyThoseWithUnkownSyncableState */);
             }
         } finally {
diff --git a/core/java/android/content/SharedPreferences.java b/core/java/android/content/SharedPreferences.java
index bdc38d6..da5480e 100644
--- a/core/java/android/content/SharedPreferences.java
+++ b/core/java/android/content/SharedPreferences.java
@@ -25,7 +25,8 @@
  * there is a single instance of this class that all clients share.
  * Modifications to the preferences must go through an {@link Editor} object
  * to ensure the preference values remain in a consistent state and control
- * when they are committed to storage.
+ * when they are committed to storage.  Objects that are returned from the
+ * various <code>get</code> methods must be treated as immutable by the application.
  *
  * <p><em>Note: currently this class does not support use across multiple
  * processes.  This will be added later.</em>
@@ -226,6 +227,10 @@
     /**
      * Retrieve all values from the preferences.
      *
+     * <p>Note that you <em>must not</em> modify the collection returned
+     * by this method, or alter any of its contents.  The consistency of your
+     * stored data is not guaranteed if you do.
+     *
      * @return Returns a map containing a list of pairs key/value representing
      * the preferences.
      *
@@ -250,6 +255,10 @@
     /**
      * Retrieve a set of String values from the preferences.
      * 
+     * <p>Note that you <em>must not</em> modify the set instance returned
+     * by this call.  The consistency of the stored data is not guaranteed
+     * if you do, nor is your ability to modify the instance at all.
+     *
      * @param key The name of the preference to retrieve.
      * @param defValues Values to return if this preference does not exist.
      * 
diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java
index 1e4ad76..0b734d8 100644
--- a/core/java/android/content/SyncManager.java
+++ b/core/java/android/content/SyncManager.java
@@ -21,7 +21,6 @@
 import android.accounts.AccountManager;
 import android.accounts.AccountManagerService;
 import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
 import android.app.AlarmManager;
 import android.app.Notification;
 import android.app.NotificationManager;
@@ -56,6 +55,7 @@
 import android.util.EventLog;
 import android.util.Log;
 import android.util.Pair;
+import android.util.Slog;
 
 import com.android.internal.R;
 import com.android.internal.util.IndentingPrintWriter;
@@ -64,6 +64,7 @@
 import com.google.android.collect.Sets;
 
 import java.io.FileDescriptor;
+import java.io.PrintStream;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -154,7 +155,9 @@
     private AlarmManager mAlarmService = null;
 
     private SyncStorageEngine mSyncStorageEngine;
-    final public SyncQueue mSyncQueue;
+
+    // @GuardedBy("mSyncQueue")
+    private final SyncQueue mSyncQueue;
 
     protected final ArrayList<ActiveSyncContext> mActiveSyncContexts = Lists.newArrayList();
 
@@ -198,7 +201,9 @@
     private BroadcastReceiver mBackgroundDataSettingChanged = new BroadcastReceiver() {
         public void onReceive(Context context, Intent intent) {
             if (getConnectivityManager().getBackgroundDataSetting()) {
-                scheduleSync(null /* account */, UserHandle.USER_ALL, null /* authority */,
+                scheduleSync(null /* account */, UserHandle.USER_ALL,
+                        SyncOperation.REASON_BACKGROUND_DATA_SETTINGS_CHANGED,
+                        null /* authority */,
                         new Bundle(), 0 /* delay */,
                         false /* onlyThoseWithUnknownSyncableState */);
             }
@@ -210,7 +215,8 @@
             updateRunningAccounts();
 
             // Kick off sync for everyone, since this was a radical account change
-            scheduleSync(null, UserHandle.USER_ALL, null, null, 0 /* no delay */, false);
+            scheduleSync(null, UserHandle.USER_ALL, SyncOperation.REASON_ACCOUNTS_UPDATED, null,
+                    null, 0 /* no delay */, false);
         }
     };
 
@@ -310,13 +316,10 @@
             if (userId == UserHandle.USER_NULL) return;
 
             if (Intent.ACTION_USER_REMOVED.equals(action)) {
-                Log.i(TAG, "User removed: u" + userId);
                 onUserRemoved(userId);
             } else if (Intent.ACTION_USER_STARTING.equals(action)) {
-                Log.i(TAG, "User starting: u" + userId);
                 onUserStarting(userId);
             } else if (Intent.ACTION_USER_STOPPING.equals(action)) {
-                Log.i(TAG, "User stopping: u" + userId);
                 onUserStopping(userId);
             }
         }
@@ -337,6 +340,10 @@
         }
     }
 
+    /**
+     * Should only be created after {@link ContentService#systemReady()} so that
+     * {@link PackageManager} is ready to query.
+     */
     public SyncManager(Context context, boolean factoryTest) {
         // Initialize the SyncStorageEngine first, before registering observers
         // and creating threads and so on; it may fail if the disk is full.
@@ -345,14 +352,14 @@
         SyncStorageEngine.init(context);
         mSyncStorageEngine = SyncStorageEngine.getSingleton();
         mSyncStorageEngine.setOnSyncRequestListener(new OnSyncRequestListener() {
-            public void onSyncRequest(Account account, int userId, String authority,
+            public void onSyncRequest(Account account, int userId, int reason, String authority,
                     Bundle extras) {
-                scheduleSync(account, userId, authority, extras, 0, false);
+                scheduleSync(account, userId, reason, authority, extras, 0, false);
             }
         });
 
         mSyncAdapters = new SyncAdaptersCache(mContext);
-        mSyncQueue = new SyncQueue(mSyncStorageEngine, mSyncAdapters);
+        mSyncQueue = new SyncQueue(mContext.getPackageManager(), mSyncStorageEngine, mSyncAdapters);
 
         HandlerThread syncThread = new HandlerThread("SyncHandlerThread",
                 Process.THREAD_PRIORITY_BACKGROUND);
@@ -363,7 +370,9 @@
             @Override
             public void onServiceChanged(SyncAdapterType type, int userId, boolean removed) {
                 if (!removed) {
-                    scheduleSync(null, UserHandle.USER_ALL, type.authority, null, 0 /* no delay */,
+                    scheduleSync(null, UserHandle.USER_ALL,
+                            SyncOperation.REASON_SERVICE_CHANGED,
+                            type.authority, null, 0 /* no delay */,
                             false /* onlyThoseWithUnkownSyncableState */);
                 }
             }
@@ -440,9 +449,6 @@
                     UserHandle.ALL,
                     new IntentFilter(AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION),
                     null, null);
-
-            // do this synchronously to ensure we have the accounts before this call returns
-            onUserStarting(UserHandle.USER_OWNER);
         }
 
         // Pick a random second in a day to seed all periodic syncs
@@ -495,6 +501,17 @@
      * @param requestedAccount the account to sync, may be null to signify all accounts
      * @param userId the id of the user whose accounts are to be synced. If userId is USER_ALL,
      *          then all users' accounts are considered.
+     * @param reason for sync request. If this is a positive integer, it is the Linux uid
+     * assigned to the process that requested the sync. If it's negative, the sync was requested by
+     * the SyncManager itself and could be one of the following:
+     *      {@link SyncOperation#REASON_BACKGROUND_DATA_SETTINGS_CHANGED}
+     *      {@link SyncOperation#REASON_ACCOUNTS_UPDATED}
+     *      {@link SyncOperation#REASON_SERVICE_CHANGED}
+     *      {@link SyncOperation#REASON_PERIODIC}
+     *      {@link SyncOperation#REASON_IS_SYNCABLE}
+     *      {@link SyncOperation#REASON_SYNC_AUTO}
+     *      {@link SyncOperation#REASON_MASTER_SYNC_AUTO}
+     *      {@link SyncOperation#REASON_USER_START}
      * @param requestedAuthority the authority to sync, may be null to indicate all authorities
      * @param extras a Map of SyncAdapter-specific information to control
      *          syncs of a specific provider. Can be null. Is ignored
@@ -502,8 +519,9 @@
      * @param delay how many milliseconds in the future to wait before performing this
      * @param onlyThoseWithUnkownSyncableState
      */
-    public void scheduleSync(Account requestedAccount, int userId, String requestedAuthority,
-            Bundle extras, long delay, boolean onlyThoseWithUnkownSyncableState) {
+    public void scheduleSync(Account requestedAccount, int userId, int reason,
+            String requestedAuthority, Bundle extras, long delay,
+            boolean onlyThoseWithUnkownSyncableState) {
         boolean isLoggable = Log.isLoggable(TAG, Log.VERBOSE);
 
         final boolean backgroundDataUsageAllowed = !mBootCompleted ||
@@ -629,8 +647,9 @@
                                 + ", extras " + newExtras);
                     }
                     scheduleSyncOperation(
-                            new SyncOperation(account.account, account.userId, source, authority,
-                                    newExtras, 0, backoffTime, delayUntil, allowParallelSyncs));
+                            new SyncOperation(account.account, account.userId, reason, source,
+                                    authority, newExtras, 0, backoffTime, delayUntil,
+                                    allowParallelSyncs));
                 }
                 if (!onlyThoseWithUnkownSyncableState) {
                     if (isLoggable) {
@@ -642,17 +661,18 @@
                                 + ", extras " + extras);
                     }
                     scheduleSyncOperation(
-                            new SyncOperation(account.account, account.userId, source, authority,
-                                    extras, delay, backoffTime, delayUntil, allowParallelSyncs));
+                            new SyncOperation(account.account, account.userId, reason, source,
+                                    authority, extras, delay, backoffTime, delayUntil,
+                                    allowParallelSyncs));
                 }
             }
         }
     }
 
-    public void scheduleLocalSync(Account account, int userId, String authority) {
+    public void scheduleLocalSync(Account account, int userId, int reason, String authority) {
         final Bundle extras = new Bundle();
         extras.putBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, true);
-        scheduleSync(account, userId, authority, extras, LOCAL_SYNC_DELAY,
+        scheduleSync(account, userId, reason, authority, extras, LOCAL_SYNC_DELAY,
                 false /* onlyThoseWithUnkownSyncableState */);
     }
 
@@ -878,6 +898,7 @@
                         + "sync in progress: " + operation);
             }
             scheduleSyncOperation(new SyncOperation(operation.account, operation.userId,
+                    operation.reason,
                     operation.syncSource,
                     operation.authority, operation.extras,
                     DELAY_RETRY_SYNC_IN_PROGRESS_IN_SECONDS * 1000,
@@ -902,13 +923,15 @@
 
         updateRunningAccounts();
 
-        mSyncQueue.addPendingOperations(userId);
+        synchronized (mSyncQueue) {
+            mSyncQueue.addPendingOperations(userId);
+        }
 
         // Schedule sync for any accounts under started user
         final Account[] accounts = AccountManagerService.getSingleton().getAccounts(userId);
         for (Account account : accounts) {
-            scheduleSync(account, userId, null, null, 0 /* no delay */,
-                    true /* onlyThoseWithUnknownSyncableState */);
+            scheduleSync(account, userId, SyncOperation.REASON_USER_START, null, null,
+                    0 /* no delay */, true /* onlyThoseWithUnknownSyncableState */);
         }
 
         sendCheckAlarmsMessage();
@@ -1122,12 +1145,13 @@
 
         pw.println();
         pw.println("Active Syncs: " + mActiveSyncContexts.size());
+        final PackageManager pm = mContext.getPackageManager();
         for (SyncManager.ActiveSyncContext activeSyncContext : mActiveSyncContexts) {
             final long durationInSeconds = (now - activeSyncContext.mStartTime) / 1000;
             pw.print("  ");
             pw.print(DateUtils.formatElapsedTime(durationInSeconds));
             pw.print(" - ");
-            pw.print(activeSyncContext.mSyncOperation.dump(false));
+            pw.print(activeSyncContext.mSyncOperation.dump(pm, false));
             pw.println();
         }
 
@@ -1142,78 +1166,96 @@
         pw.println();
         pw.println("Sync Status");
         for (AccountAndUser account : accounts) {
-            pw.print("  Account "); pw.print(account.account.name);
-                    pw.print(" u"); pw.print(account.userId);
-                    pw.print(" "); pw.print(account.account.type);
-                    pw.println(":");
-            for (RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterType :
-                    mSyncAdapters.getAllServices(account.userId)) {
+            pw.printf("Account %s u%d %s\n",
+                    account.account.name, account.userId, account.account.type);
+
+            pw.println("=======================================================================");
+            final PrintTable table = new PrintTable(13);
+            table.set(0, 0,
+                    "Authority", // 0
+                    "Syncable",  // 1
+                    "Enabled",   // 2
+                    "Delay",     // 3
+                    "Loc",       // 4
+                    "Poll",      // 5
+                    "Per",       // 6
+                    "Serv",      // 7
+                    "User",      // 8
+                    "Tot",       // 9
+                    "Time",      // 10
+                    "Last Sync", // 11
+                    "Periodic"   // 12
+            );
+
+            final List<RegisteredServicesCache.ServiceInfo<SyncAdapterType>> sorted =
+                    Lists.newArrayList();
+            sorted.addAll(mSyncAdapters.getAllServices(account.userId));
+            Collections.sort(sorted,
+                    new Comparator<RegisteredServicesCache.ServiceInfo<SyncAdapterType>>() {
+                @Override
+                public int compare(RegisteredServicesCache.ServiceInfo<SyncAdapterType> lhs,
+                        RegisteredServicesCache.ServiceInfo<SyncAdapterType> rhs) {
+                    return lhs.type.authority.compareTo(rhs.type.authority);
+                }
+            });
+            for (RegisteredServicesCache.ServiceInfo<SyncAdapterType> syncAdapterType : sorted) {
                 if (!syncAdapterType.type.accountType.equals(account.account.type)) {
                     continue;
                 }
-
+                int row = table.getNumRows();
                 SyncStorageEngine.AuthorityInfo settings =
                         mSyncStorageEngine.getOrCreateAuthority(
                                 account.account, account.userId, syncAdapterType.type.authority);
                 SyncStatusInfo status = mSyncStorageEngine.getOrCreateSyncStatus(settings);
-                pw.print("    "); pw.print(settings.authority);
-                pw.println(":");
-                pw.print("      settings:");
-                pw.print(" " + (settings.syncable > 0
-                        ? "syncable"
-                        : (settings.syncable == 0 ? "not syncable" : "not initialized")));
-                pw.print(", " + (settings.enabled ? "enabled" : "disabled"));
+
+                String authority = settings.authority;
+                if (authority.length() > 50) {
+                    authority = authority.substring(authority.length() - 50);
+                }
+                table.set(row, 0, authority, settings.syncable, settings.enabled);
+                table.set(row, 4,
+                        status.numSourceLocal,
+                        status.numSourcePoll,
+                        status.numSourcePeriodic,
+                        status.numSourceServer,
+                        status.numSourceUser,
+                        status.numSyncs,
+                        DateUtils.formatElapsedTime(status.totalElapsedTime / 1000));
+
+
+                for (int i = 0; i < settings.periodicSyncs.size(); i++) {
+                    final Pair<Bundle, Long> pair = settings.periodicSyncs.get(0);
+                    final String period = String.valueOf(pair.second);
+                    final String extras = pair.first.size() > 0 ? pair.first.toString() : "";
+                    final String next = formatTime(status.getPeriodicSyncTime(0)
+                            + pair.second * 1000);
+                    table.set(row + i * 2, 12, period + extras);
+                    table.set(row + i * 2 + 1, 12, next);
+                }
+
+                int row1 = row;
                 if (settings.delayUntil > now) {
-                    pw.print(", delay for "
-                            + ((settings.delayUntil - now) / 1000) + " sec");
+                    table.set(row1++, 12, "D: " + (settings.delayUntil - now) / 1000);
+                    if (settings.backoffTime > now) {
+                        table.set(row1++, 12, "B: " + (settings.backoffTime - now) / 1000);
+                        table.set(row1++, 12, settings.backoffDelay / 1000);
+                    }
                 }
-                if (settings.backoffTime > now) {
-                    pw.print(", backoff for "
-                            + ((settings.backoffTime - now) / 1000) + " sec");
-                }
-                if (settings.backoffDelay > 0) {
-                    pw.print(", the backoff increment is " + settings.backoffDelay / 1000
-                                + " sec");
-                }
-                pw.println();
-                for (int periodicIndex = 0;
-                        periodicIndex < settings.periodicSyncs.size();
-                        periodicIndex++) {
-                    Pair<Bundle, Long> info = settings.periodicSyncs.get(periodicIndex);
-                    long lastPeriodicTime = status.getPeriodicSyncTime(periodicIndex);
-                    long nextPeriodicTime = lastPeriodicTime + info.second * 1000;
-                    pw.println("      periodic period=" + info.second
-                            + ", extras=" + info.first
-                            + ", next=" + formatTime(nextPeriodicTime));
-                }
-                pw.print("      count: local="); pw.print(status.numSourceLocal);
-                pw.print(" poll="); pw.print(status.numSourcePoll);
-                pw.print(" periodic="); pw.print(status.numSourcePeriodic);
-                pw.print(" server="); pw.print(status.numSourceServer);
-                pw.print(" user="); pw.print(status.numSourceUser);
-                pw.print(" total="); pw.print(status.numSyncs);
-                pw.println();
-                pw.print("      total duration: ");
-                pw.println(DateUtils.formatElapsedTime(status.totalElapsedTime/1000));
+
                 if (status.lastSuccessTime != 0) {
-                    pw.print("      SUCCESS: source=");
-                    pw.print(SyncStorageEngine.SOURCES[status.lastSuccessSource]);
-                    pw.print(" time=");
-                    pw.println(formatTime(status.lastSuccessTime));
+                    table.set(row1++, 11, SyncStorageEngine.SOURCES[status.lastSuccessSource]
+                            + " " + "SUCCESS");
+                    table.set(row1++, 11, formatTime(status.lastSuccessTime));
                 }
                 if (status.lastFailureTime != 0) {
-                    pw.print("      FAILURE: source=");
-                    pw.print(SyncStorageEngine.SOURCES[
-                            status.lastFailureSource]);
-                    pw.print(" initialTime=");
-                    pw.print(formatTime(status.initialFailureTime));
-                    pw.print(" lastTime=");
-                    pw.println(formatTime(status.lastFailureTime));
-                    int errCode = status.getLastFailureMesgAsInt(0);
-                    pw.print("      message: "); pw.println(
-                            getLastFailureMessage(errCode) + " (" + errCode + ")");
+                    table.set(row1++, 11, SyncStorageEngine.SOURCES[status.lastFailureSource]
+                            + " " + "FAILURE");
+                    table.set(row1++, 11, formatTime(status.lastFailureTime));
+                    //noinspection UnusedAssignment
+                    table.set(row1++, 11, status.lastFailureMesg);
                 }
             }
+            table.writeTo(pw);
         }
     }
 
@@ -1407,9 +1449,9 @@
 
             pw.println();
             pw.println("Recent Sync History");
-            final String format = "  %-" + maxAccount + "s  %s\n";
+            final String format = "  %-" + maxAccount + "s  %-" + maxAuthority + "s %s\n";
             final Map<String, Long> lastTimeMap = Maps.newHashMap();
-
+            final PackageManager pm = mContext.getPackageManager();
             for (int i = 0; i < N; i++) {
                 SyncStorageEngine.SyncHistoryItem item = items.get(i);
                 SyncStorageEngine.AuthorityInfo authority
@@ -1454,7 +1496,8 @@
                         SyncStorageEngine.SOURCES[item.source],
                         ((float) elapsedTime) / 1000,
                         diffString);
-                pw.printf(format, accountKey, authorityName);
+                pw.printf(format, accountKey, authorityName,
+                        SyncOperation.reasonToString(pm, item.reason));
 
                 if (item.event != SyncStorageEngine.EVENT_STOP
                         || item.upstreamActivity != 0
@@ -1469,6 +1512,37 @@
                     pw.printf("    mesg=%s\n", item.mesg);
                 }
             }
+            pw.println();
+            pw.println("Recent Sync History Extras");
+            for (int i = 0; i < N; i++) {
+                final SyncStorageEngine.SyncHistoryItem item = items.get(i);
+                final Bundle extras = item.extras;
+                if (extras == null || extras.size() == 0) {
+                    continue;
+                }
+                final SyncStorageEngine.AuthorityInfo authority
+                        = mSyncStorageEngine.getAuthority(item.authorityId);
+                final String authorityName;
+                final String accountKey;
+                if (authority != null) {
+                    authorityName = authority.authority;
+                    accountKey = authority.account.name + "/" + authority.account.type
+                            + " u" + authority.userId;
+                } else {
+                    authorityName = "Unknown";
+                    accountKey = "Unknown";
+                }
+                final Time time = new Time();
+                final long eventTime = item.eventTime;
+                time.set(eventTime);
+
+                pw.printf("  #%-3d: %s %8s ",
+                        i + 1,
+                        formatTime(eventTime),
+                        SyncStorageEngine.SOURCES[item.source]);
+
+                pw.printf(format, accountKey, authorityName, extras);
+            }
         }
     }
 
@@ -1883,6 +1957,7 @@
                         }
                         scheduleSyncOperation(
                                 new SyncOperation(info.account, info.userId,
+                                        SyncOperation.REASON_PERIODIC,
                                         SyncStorageEngine.SOURCE_PERIODIC,
                                         info.authority, extras, 0 /* delay */,
                                         backoff != null ? backoff.first : 0,
@@ -1957,10 +2032,10 @@
             synchronized (mSyncQueue) {
                 if (isLoggable) {
                     Log.v(TAG, "build the operation array, syncQueue size is "
-                        + mSyncQueue.mOperationsMap.size());
+                        + mSyncQueue.getOperations().size());
                 }
-                Iterator<SyncOperation> operationIterator =
-                        mSyncQueue.mOperationsMap.values().iterator();
+                final Iterator<SyncOperation> operationIterator = mSyncQueue.getOperations()
+                        .iterator();
 
                 final ActivityManager activityManager
                         = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
@@ -2153,7 +2228,7 @@
                     runSyncFinishedOrCanceledLocked(null, toReschedule);
                     scheduleSyncOperation(toReschedule.mSyncOperation);
                 }
-                synchronized (mSyncQueue){
+                synchronized (mSyncQueue) {
                     mSyncQueue.remove(candidate);
                 }
                 dispatchSyncOperation(candidate);
@@ -2284,7 +2359,8 @@
                     }
                     // reschedule the sync if so indicated by the syncResult
                     maybeRescheduleSync(syncResult, syncOperation);
-                    historyMessage = Integer.toString(syncResultToErrorNumber(syncResult));
+                    historyMessage = ContentResolver.syncErrorToString(
+                            syncResultToErrorNumber(syncResult));
                     // TODO: set these correctly when the SyncResult is extended to include it
                     downstreamActivity = 0;
                     upstreamActivity = 0;
@@ -2322,6 +2398,7 @@
 
             if (syncResult != null && syncResult.fullSyncRequested) {
                 scheduleSyncOperation(new SyncOperation(syncOperation.account, syncOperation.userId,
+                        syncOperation.reason,
                         syncOperation.syncSource, syncOperation.authority, new Bundle(), 0,
                         syncOperation.backoff, syncOperation.delayUntil,
                         syncOperation.allowParallelSyncs));
@@ -2601,8 +2678,10 @@
                                 syncOperation.account.name.hashCode());
 
             return mSyncStorageEngine.insertStartSyncEvent(
-                    syncOperation.account, syncOperation.userId, syncOperation.authority,
-                    now, source, syncOperation.isInitialization());
+                    syncOperation.account, syncOperation.userId, syncOperation.reason,
+                    syncOperation.authority,
+                    now, source, syncOperation.isInitialization(), syncOperation.extras
+            );
         }
 
         public void stopSyncEvent(long rowId, SyncOperation syncOperation, String resultMessage,
@@ -2624,4 +2703,66 @@
         }
         return false;
     }
+
+    static class PrintTable {
+        private ArrayList<Object[]> mTable = Lists.newArrayList();
+        private final int mCols;
+
+        PrintTable(int cols) {
+            mCols = cols;
+        }
+
+        void set(int row, int col, Object... values) {
+            if (col + values.length > mCols) {
+                throw new IndexOutOfBoundsException("Table only has " + mCols +
+                        " columns. can't set " + values.length + " at column " + col);
+            }
+            for (int i = mTable.size(); i <= row; i++) {
+                final Object[] list = new Object[mCols];
+                mTable.add(list);
+                for (int j = 0; j < mCols; j++) {
+                    list[j] = "";
+                }
+            }
+            System.arraycopy(values, 0, mTable.get(row), col, values.length);
+        }
+
+        void writeTo(PrintWriter out) {
+            final String[] formats = new String[mCols];
+            int totalLength = 0;
+            for (int col = 0; col < mCols; ++col) {
+                int maxLength = 0;
+                for (Object[] row : mTable) {
+                    final int length = row[col].toString().length();
+                    if (length > maxLength) {
+                        maxLength = length;
+                    }
+                }
+                totalLength += maxLength;
+                formats[col] = String.format("%%-%ds", maxLength);
+            }
+            printRow(out, formats, mTable.get(0));
+            totalLength += (mCols - 1) * 2;
+            for (int i = 0; i < totalLength; ++i) {
+                out.print("-");
+            }
+            out.println();
+            for (int i = 1, mTableSize = mTable.size(); i < mTableSize; i++) {
+                Object[] row = mTable.get(i);
+                printRow(out, formats, row);
+            }
+        }
+
+        private void printRow(PrintWriter out, String[] formats, Object[] row) {
+            for (int j = 0, rowLength = row.length; j < rowLength; j++) {
+                out.printf(String.format(formats[j], row[j].toString()));
+                out.print("  ");
+            }
+            out.println();
+        }
+
+        public int getNumRows() {
+            return mTable.size();
+        }
+    }
 }
diff --git a/core/java/android/content/SyncOperation.java b/core/java/android/content/SyncOperation.java
index 6611fcd..a4c2cff 100644
--- a/core/java/android/content/SyncOperation.java
+++ b/core/java/android/content/SyncOperation.java
@@ -17,6 +17,7 @@
 package android.content;
 
 import android.accounts.Account;
+import android.content.pm.PackageManager;
 import android.os.Bundle;
 import android.os.SystemClock;
 
@@ -25,8 +26,29 @@
  * @hide
  */
 public class SyncOperation implements Comparable {
+    public static final int REASON_BACKGROUND_DATA_SETTINGS_CHANGED = -1;
+    public static final int REASON_ACCOUNTS_UPDATED = -2;
+    public static final int REASON_SERVICE_CHANGED = -3;
+    public static final int REASON_PERIODIC = -4;
+    public static final int REASON_IS_SYNCABLE = -5;
+    public static final int REASON_SYNC_AUTO = -6;
+    public static final int REASON_MASTER_SYNC_AUTO = -7;
+    public static final int REASON_USER_START = -8;
+
+    private static String[] REASON_NAMES = new String[] {
+            "DataSettingsChanged",
+            "AccountsUpdated",
+            "ServiceChanged",
+            "Periodic",
+            "IsSyncable",
+            "AutoSync",
+            "MasterSyncAuto",
+            "UserStart",
+    };
+
     public final Account account;
     public final int userId;
+    public final int reason;
     public int syncSource;
     public String authority;
     public final boolean allowParallelSyncs;
@@ -39,10 +61,12 @@
     public long delayUntil;
     public long effectiveRunTime;
 
-    public SyncOperation(Account account, int userId, int source, String authority, Bundle extras,
-            long delayInMs, long backoff, long delayUntil, boolean allowParallelSyncs) {
+    public SyncOperation(Account account, int userId, int reason, int source, String authority,
+            Bundle extras, long delayInMs, long backoff, long delayUntil,
+            boolean allowParallelSyncs) {
         this.account = account;
         this.userId = userId;
+        this.reason = reason;
         this.syncSource = source;
         this.authority = authority;
         this.allowParallelSyncs = allowParallelSyncs;
@@ -78,6 +102,7 @@
     SyncOperation(SyncOperation other) {
         this.account = other.account;
         this.userId = other.userId;
+        this.reason = other.reason;
         this.syncSource = other.syncSource;
         this.authority = other.authority;
         this.extras = new Bundle(other.extras);
@@ -91,10 +116,10 @@
     }
 
     public String toString() {
-        return dump(true);
+        return dump(null, true);
     }
 
-    public String dump(boolean useOneLine) {
+    public String dump(PackageManager pm, boolean useOneLine) {
         StringBuilder sb = new StringBuilder()
                 .append(account.name)
                 .append(" u")
@@ -110,6 +135,8 @@
         if (expedited) {
             sb.append(", EXPEDITED");
         }
+        sb.append(", reason: ");
+        sb.append(reasonToString(pm, reason));
         if (!useOneLine && !extras.keySet().isEmpty()) {
             sb.append("\n    ");
             extrasToStringBuilder(extras, sb);
@@ -117,6 +144,31 @@
         return sb.toString();
     }
 
+    public static String reasonToString(PackageManager pm, int reason) {
+        if (reason >= 0) {
+            if (pm != null) {
+                final String[] packages = pm.getPackagesForUid(reason);
+                if (packages != null && packages.length == 1) {
+                    return packages[0];
+                }
+                final String name = pm.getNameForUid(reason);
+                if (name != null) {
+                    return name;
+                }
+                return String.valueOf(reason);
+            } else {
+                return String.valueOf(reason);
+            }
+        } else {
+            final int index = -reason - 1;
+            if (index >= REASON_NAMES.length) {
+                return String.valueOf(reason);
+            } else {
+                return REASON_NAMES[index];
+            }
+        }
+    }
+
     public boolean isInitialization() {
         return extras.getBoolean(ContentResolver.SYNC_EXTRAS_INITIALIZE, false);
     }
diff --git a/core/java/android/content/SyncQueue.java b/core/java/android/content/SyncQueue.java
index 395658c..c09703c 100644
--- a/core/java/android/content/SyncQueue.java
+++ b/core/java/android/content/SyncQueue.java
@@ -17,6 +17,8 @@
 package android.content;
 
 import android.accounts.Account;
+import android.content.pm.PackageManager;
+import android.content.pm.RegisteredServicesCache;
 import android.content.pm.RegisteredServicesCache.ServiceInfo;
 import android.os.SystemClock;
 import android.os.UserHandle;
@@ -27,29 +29,32 @@
 import com.google.android.collect.Maps;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Map;
 
 /**
+ * Queue of pending sync operations. Not inherently thread safe, external
+ * callers are responsible for locking.
  *
  * @hide
  */
 public class SyncQueue {
     private static final String TAG = "SyncManager";
-
     private final SyncStorageEngine mSyncStorageEngine;
     private final SyncAdaptersCache mSyncAdapters;
+    private final PackageManager mPackageManager;
 
     // A Map of SyncOperations operationKey -> SyncOperation that is designed for
     // quick lookup of an enqueued SyncOperation.
-    public final HashMap<String, SyncOperation> mOperationsMap = Maps.newHashMap();
+    private final HashMap<String, SyncOperation> mOperationsMap = Maps.newHashMap();
 
-    public SyncQueue(SyncStorageEngine syncStorageEngine, final SyncAdaptersCache syncAdapters) {
+    public SyncQueue(PackageManager packageManager, SyncStorageEngine syncStorageEngine,
+            final SyncAdaptersCache syncAdapters) {
+        mPackageManager = packageManager;
         mSyncStorageEngine = syncStorageEngine;
         mSyncAdapters = syncAdapters;
-
-        addPendingOperations(UserHandle.USER_OWNER);
     }
 
     public void addPendingOperations(int userId) {
@@ -66,8 +71,8 @@
                 continue;
             }
             SyncOperation syncOperation = new SyncOperation(
-                    op.account, op.userId, op.syncSource, op.authority, op.extras, 0 /* delay */,
-                    backoff != null ? backoff.first : 0,
+                    op.account, op.userId, op.reason, op.syncSource, op.authority, op.extras,
+                    0 /* delay */, backoff != null ? backoff.first : 0,
                     mSyncStorageEngine.getDelayUntilTime(op.account, op.userId, op.authority),
                     syncAdapterInfo.type.allowParallelSyncs());
             syncOperation.expedited = op.expedited;
@@ -111,7 +116,7 @@
         operation.pendingOperation = pop;
         if (operation.pendingOperation == null) {
             pop = new SyncStorageEngine.PendingOperation(
-                    operation.account, operation.userId, operation.syncSource,
+                    operation.account, operation.userId, operation.reason, operation.syncSource,
                     operation.authority, operation.extras, operation.expedited);
             pop = mSyncStorageEngine.insertIntoPending(pop);
             if (pop == null) {
@@ -198,6 +203,10 @@
         }
     }
 
+    public Collection<SyncOperation> getOperations() {
+        return mOperationsMap.values();
+    }
+
     public void dump(StringBuilder sb) {
         final long now = SystemClock.elapsedRealtime();
         sb.append("SyncQueue: ").append(mOperationsMap.size()).append(" operation(s)\n");
@@ -209,7 +218,7 @@
                 sb.append(DateUtils.formatElapsedTime((operation.effectiveRunTime - now) / 1000));
             }
             sb.append(" - ");
-            sb.append(operation.dump(false)).append("\n");
+            sb.append(operation.dump(mPackageManager, false)).append("\n");
         }
     }
 }
diff --git a/core/java/android/content/SyncStorageEngine.java b/core/java/android/content/SyncStorageEngine.java
index de97481..be1e796 100644
--- a/core/java/android/content/SyncStorageEngine.java
+++ b/core/java/android/content/SyncStorageEngine.java
@@ -25,7 +25,6 @@
 
 import android.accounts.Account;
 import android.accounts.AccountAndUser;
-import android.content.res.Resources;
 import android.database.Cursor;
 import android.database.sqlite.SQLiteDatabase;
 import android.database.sqlite.SQLiteException;
@@ -145,6 +144,7 @@
     public static class PendingOperation {
         final Account account;
         final int userId;
+        final int reason;
         final int syncSource;
         final String authority;
         final Bundle extras;        // note: read-only.
@@ -153,11 +153,12 @@
         int authorityId;
         byte[] flatExtras;
 
-        PendingOperation(Account account, int userId, int source,
+        PendingOperation(Account account, int userId, int reason,int source,
                 String authority, Bundle extras, boolean expedited) {
             this.account = account;
             this.userId = userId;
             this.syncSource = source;
+            this.reason = reason;
             this.authority = authority;
             this.extras = extras != null ? new Bundle(extras) : extras;
             this.expedited = expedited;
@@ -167,6 +168,7 @@
         PendingOperation(PendingOperation other) {
             this.account = other.account;
             this.userId = other.userId;
+            this.reason = other.reason;
             this.syncSource = other.syncSource;
             this.authority = other.authority;
             this.extras = other.extras;
@@ -245,6 +247,8 @@
         long downstreamActivity;
         String mesg;
         boolean initialization;
+        Bundle extras;
+        int reason;
     }
 
     public static class DayStats {
@@ -264,10 +268,12 @@
          * Called when a sync is needed on an account(s) due to some change in state.
          * @param account
          * @param userId
+         * @param reason
          * @param authority
          * @param extras
          */
-        public void onSyncRequest(Account account, int userId, String authority, Bundle extras);
+        public void onSyncRequest(Account account, int userId, int reason, String authority,
+                Bundle extras);
     }
 
     // Primary list of all syncable authorities.  Also our global lock.
@@ -497,7 +503,8 @@
         }
 
         if (sync) {
-            requestSync(account, userId, providerName, new Bundle());
+            requestSync(account, userId, SyncOperation.REASON_SYNC_AUTO, providerName,
+                    new Bundle());
         }
         reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS);
     }
@@ -545,7 +552,8 @@
         }
 
         if (syncable > 0) {
-            requestSync(account, userId, providerName, new Bundle());
+            requestSync(account, userId, SyncOperation.REASON_IS_SYNCABLE,  providerName,
+                    new Bundle());
         }
         reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS);
     }
@@ -609,23 +617,25 @@
     public void clearAllBackoffs(SyncQueue syncQueue) {
         boolean changed = false;
         synchronized (mAuthorities) {
-            for (AccountInfo accountInfo : mAccounts.values()) {
-                for (AuthorityInfo authorityInfo : accountInfo.authorities.values()) {
-                    if (authorityInfo.backoffTime != NOT_IN_BACKOFF_MODE
-                            || authorityInfo.backoffDelay != NOT_IN_BACKOFF_MODE) {
-                        if (Log.isLoggable(TAG, Log.VERBOSE)) {
-                            Log.v(TAG, "clearAllBackoffs:"
-                                    + " authority:" + authorityInfo.authority
-                                    + " account:" + accountInfo.accountAndUser.account.name
-                                    + " user:" + accountInfo.accountAndUser.userId
-                                    + " backoffTime was: " + authorityInfo.backoffTime
-                                    + " backoffDelay was: " + authorityInfo.backoffDelay);
+            synchronized (syncQueue) {
+                for (AccountInfo accountInfo : mAccounts.values()) {
+                    for (AuthorityInfo authorityInfo : accountInfo.authorities.values()) {
+                        if (authorityInfo.backoffTime != NOT_IN_BACKOFF_MODE
+                                || authorityInfo.backoffDelay != NOT_IN_BACKOFF_MODE) {
+                            if (Log.isLoggable(TAG, Log.VERBOSE)) {
+                                Log.v(TAG, "clearAllBackoffs:"
+                                        + " authority:" + authorityInfo.authority
+                                        + " account:" + accountInfo.accountAndUser.account.name
+                                        + " user:" + accountInfo.accountAndUser.userId
+                                        + " backoffTime was: " + authorityInfo.backoffTime
+                                        + " backoffDelay was: " + authorityInfo.backoffDelay);
+                            }
+                            authorityInfo.backoffTime = NOT_IN_BACKOFF_MODE;
+                            authorityInfo.backoffDelay = NOT_IN_BACKOFF_MODE;
+                            syncQueue.onBackoffChanged(accountInfo.accountAndUser.account,
+                                    accountInfo.accountAndUser.userId, authorityInfo.authority, 0);
+                            changed = true;
                         }
-                        authorityInfo.backoffTime = NOT_IN_BACKOFF_MODE;
-                        authorityInfo.backoffDelay = NOT_IN_BACKOFF_MODE;
-                        syncQueue.onBackoffChanged(accountInfo.accountAndUser.account,
-                                accountInfo.accountAndUser.userId, authorityInfo.authority, 0);
-                        changed = true;
                     }
                 }
             }
@@ -776,7 +786,8 @@
             writeAccountInfoLocked();
         }
         if (flag) {
-            requestSync(null, userId, null, new Bundle());
+            requestSync(null, userId, SyncOperation.REASON_MASTER_SYNC_AUTO, null,
+                    new Bundle());
         }
         reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS);
         mContext.sendBroadcast(SYNC_CONNECTION_SETTING_CHANGED_INTENT);
@@ -1039,8 +1050,8 @@
     /**
      * Note that sync has started for the given account and authority.
      */
-    public long insertStartSyncEvent(Account accountName, int userId, String authorityName,
-                                     long now, int source, boolean initialization) {
+    public long insertStartSyncEvent(Account accountName, int userId, int reason,
+            String authorityName, long now, int source, boolean initialization, Bundle extras) {
         long id;
         synchronized (mAuthorities) {
             if (Log.isLoggable(TAG, Log.VERBOSE)) {
@@ -1059,6 +1070,8 @@
             if (mNextHistoryId < 0) mNextHistoryId = 0;
             item.eventTime = now;
             item.source = source;
+            item.reason = reason;
+            item.extras = extras;
             item.event = EVENT_START;
             mSyncHistory.add(0, item);
             while (mSyncHistory.size() > MAX_HISTORY) {
@@ -2034,7 +2047,7 @@
         }
     }
 
-    public static final int PENDING_OPERATION_VERSION = 2;
+    public static final int PENDING_OPERATION_VERSION = 3;
 
     /**
      * Read all pending operations back in to the initial engine state.
@@ -2063,6 +2076,7 @@
                 } else {
                     expedited = false;
                 }
+                int reason = in.readInt();
                 AuthorityInfo authority = mAuthorities.get(authorityId);
                 if (authority != null) {
                     Bundle extras;
@@ -2074,13 +2088,14 @@
                         extras = new Bundle();
                     }
                     PendingOperation op = new PendingOperation(
-                            authority.account, authority.userId, syncSource,
+                            authority.account, authority.userId, reason, syncSource,
                             authority.authority, extras, expedited);
                     op.authorityId = authorityId;
                     op.flatExtras = flatExtras;
                     if (DEBUG_FILE) Log.v(TAG, "Adding pending op: account=" + op.account
                             + " auth=" + op.authority
                             + " src=" + op.syncSource
+                            + " reason=" + op.reason
                             + " expedited=" + op.expedited
                             + " extras=" + op.extras);
                     mPendingOperations.add(op);
@@ -2100,6 +2115,7 @@
         }
         out.writeByteArray(op.flatExtras);
         out.writeInt(op.expedited ? 1 : 0);
+        out.writeInt(op.reason);
     }
 
     /**
@@ -2194,14 +2210,15 @@
         return bundle;
     }
 
-    private void requestSync(Account account, int userId, String authority, Bundle extras) {
+    private void requestSync(Account account, int userId, int reason, String authority,
+            Bundle extras) {
         // If this is happening in the system process, then call the syncrequest listener
         // to make a request back to the SyncManager directly.
         // If this is probably a test instance, then call back through the ContentResolver
         // which will know which userId to apply based on the Binder id.
         if (android.os.Process.myUid() == android.os.Process.SYSTEM_UID
                 && mSyncRequestListener != null) {
-            mSyncRequestListener.onSyncRequest(account, userId, authority, extras);
+            mSyncRequestListener.onSyncRequest(account, userId, reason, authority, extras);
         } else {
             ContentResolver.requestSync(account, authority, extras);
         }
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index a0283d3..32cc7fd 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -554,6 +554,7 @@
         manageSpaceActivityName = orig.manageSpaceActivityName;
         descriptionRes = orig.descriptionRes;
         uiOptions = orig.uiOptions;
+        backupAgentName = orig.backupAgentName;
     }
 
 
diff --git a/core/java/android/content/pm/RegisteredServicesCache.java b/core/java/android/content/pm/RegisteredServicesCache.java
index 0b91786..6def4a1 100644
--- a/core/java/android/content/pm/RegisteredServicesCache.java
+++ b/core/java/android/content/pm/RegisteredServicesCache.java
@@ -264,7 +264,8 @@
             if (user.services == null) {
                 generateServicesMap(userId);
             }
-            return Collections.unmodifiableCollection(user.services.values());
+            return Collections.unmodifiableCollection(
+                    new ArrayList<ServiceInfo<V>>(user.services.values()));
         }
     }
 
diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java
index 7f3b6b9..2968fbb 100644
--- a/core/java/android/content/res/TypedArray.java
+++ b/core/java/android/content/res/TypedArray.java
@@ -469,20 +469,13 @@
      * {@link android.view.ViewGroup}'s layout_width and layout_height
      * attributes.  This is only here for performance reasons; applications
      * should use {@link #getDimensionPixelSize}.
-     *
+     * 
      * @param index Index of the attribute to retrieve.
      * @param name Textual name of attribute for error reporting.
      * 
      * @return Attribute dimension value multiplied by the appropriate 
      * metric and truncated to integer pixels.
-     *
-     * @throws RuntimeException
-     *             if this TypedArray does not contain an entry for <code>index</code>
-     *
-     * @deprecated Use {@link #getLayoutDimension(int, int)} instead.
-     *
      */
-    @Deprecated
     public int getLayoutDimension(int index, String name) {
         index *= AssetManager.STYLE_NUM_ENTRIES;
         final int[] data = mData;
diff --git a/core/java/android/os/AsyncTask.java b/core/java/android/os/AsyncTask.java
index 69e1de9..ce5f163 100644
--- a/core/java/android/os/AsyncTask.java
+++ b/core/java/android/os/AsyncTask.java
@@ -110,7 +110,7 @@
  * <h2>The 4 steps</h2>
  * <p>When an asynchronous task is executed, the task goes through 4 steps:</p>
  * <ol>
- *     <li>{@link #onPreExecute()}, invoked on the UI thread immediately after the task
+ *     <li>{@link #onPreExecute()}, invoked on the UI thread before the task
  *     is executed. This step is normally used to setup the task, for instance by
  *     showing a progress bar in the user interface.</li>
  *     <li>{@link #doInBackground}, invoked on the background thread
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 4820c5e..6c9290b 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -51,12 +51,17 @@
  * an exhibition/lean-back experience.</p>
  *
  * <p>The Dream lifecycle is as follows:</p>
- * <ul>
- *   <li>onAttachedToWindow</li>
- *   <li>onDreamingStarted</li>
- *   <li>onDreamingStopped</li>
- *   <li>onDetachedFromWindow</li>
- * </ul>
+ * <ol>
+ *   <li>{@link #onAttachedToWindow}
+ *     <p>Use this for initial setup, such as calling {@link #setContentView setContentView()}.</li>
+ *   <li>{@link #onDreamingStarted}
+ *     <p>Your dream has started, so you should begin animations or other behaviors here.</li>
+ *   <li>{@link #onDreamingStopped}
+ *     <p>Use this to stop the things you started in {@link #onDreamingStarted}.</li>
+ *   <li>{@link #onDetachedFromWindow}
+ *     <p>Use this to dismantle resources your dream set up. For example, detach from handlers
+ *        and listeners.</li>
+ * </ol>
  *
  * <p>In addition, onCreate and onDestroy (from the Service interface) will also be called, but
  * initialization and teardown should be done by overriding the hooks above.</p>
@@ -80,14 +85,40 @@
  *         android:resource="@xml/my_dream" />
  * &lt;/service>
  * </pre>
- * <p>If specified, additional information for the dream is defined using the
- * <code>&lt;{@link android.R.styleable#Dream dream}&gt;</code> element.  For example:</p>
- * <pre>
- * (in res/xml/my_dream.xml)
  *
+ * <p>If specified with the {@code &lt;meta-data&gt;} element,
+ * additional information for the dream is defined using the
+ * {@link android.R.styleable#Dream &lt;dream&gt;} element in a separate XML file.
+ * Currently, the only addtional
+ * information you can provide is for a settings activity that allows the user to configure
+ * the dream behavior. For example:</p>
+ * <p class="code-caption">res/xml/my_dream.xml</p>
+ * <pre>
  * &lt;dream xmlns:android="http://schemas.android.com/apk/res/android"
  *     android:settingsActivity="com.example.app/.MyDreamSettingsActivity" />
  * </pre>
+ * <p>This makes a Settings button available alongside your dream's listing in the
+ * system settings, which when pressed opens the specified activity.</p>
+ *
+ *
+ * <p>To specify your dream layout, call {@link #setContentView}, typically during the
+ * {@link #onAttachedToWindow} callback. For example:</p>
+ * <pre>
+ * public class MyDream extends DreamService {
+ *
+ *     &#64;Override
+ *     public void onAttachedToWindow() {
+ *         super.onAttachedToWindow();
+ *
+ *         // Exit dream upon user touch
+ *         setInteractive(false);
+ *         // Hide system UI
+ *         setFullscreen(true);
+ *         // Set the dream layout
+ *         setContentView(R.layout.dream);
+ *     }
+ * }
+ * </pre>
  */
 public class DreamService extends Service implements Window.Callback {
     private final String TAG = DreamService.class.getSimpleName() + "[" + getClass().getSimpleName() + "]";
@@ -323,11 +354,12 @@
 
     /**
      * Sets a view to be the content view for this Dream.
-     * Behaves similarly to {@link android.app.Activity#setContentView(android.view.View)},
+     * Behaves similarly to {@link android.app.Activity#setContentView(android.view.View)} in an activity,
      * including using {@link ViewGroup.LayoutParams#MATCH_PARENT} as the layout height and width of the view.
      *
-     * <p>Note: Requires a window, do not call before {@link #onAttachedToWindow()}</p>
-     * @param view The desired content to display.
+     * <p>Note: This requires a window, so you should usually call it during
+     * {@link #onAttachedToWindow()} and never earlier (you <strong>cannot</strong> call it
+     * during {@link #onCreate}).</p>
      *
      * @see #setContentView(int)
      * @see #setContentView(android.view.View, android.view.ViewGroup.LayoutParams)
@@ -339,9 +371,12 @@
     /**
      * Sets a view to be the content view for this Dream.
      * Behaves similarly to
-     * {@link android.app.Activity#setContentView(android.view.View, android.view.ViewGroup.LayoutParams)}.
+     * {@link android.app.Activity#setContentView(android.view.View, android.view.ViewGroup.LayoutParams)}
+     * in an activity.
      *
-     * <p>Note: Requires a window, do not call before {@link #onAttachedToWindow()}</p>
+     * <p>Note: This requires a window, so you should usually call it during
+     * {@link #onAttachedToWindow()} and never earlier (you <strong>cannot</strong> call it
+     * during {@link #onCreate}).</p>
      *
      * @param view The desired content to display.
      * @param params Layout parameters for the view.
diff --git a/core/java/android/service/dreams/Sandman.java b/core/java/android/service/dreams/Sandman.java
index 70142ce..5f5b079 100644
--- a/core/java/android/service/dreams/Sandman.java
+++ b/core/java/android/service/dreams/Sandman.java
@@ -36,9 +36,6 @@
 public final class Sandman {
     private static final String TAG = "Sandman";
 
-    private static final int DEFAULT_SCREENSAVER_ENABLED = 1;
-    private static final int DEFAULT_SCREENSAVER_ACTIVATED_ON_DOCK = 1;
-
     // The component name of a special dock app that merely launches a dream.
     // We don't want to launch this app when docked because it causes an unnecessary
     // activity transition.  We just want to start the dream.
@@ -109,14 +106,18 @@
     }
 
     private static boolean isScreenSaverEnabled(Context context) {
+        int def = context.getResources().getBoolean(
+                com.android.internal.R.bool.config_dreamsEnabledByDefault) ? 1 : 0;
         return Settings.Secure.getIntForUser(context.getContentResolver(),
-                Settings.Secure.SCREENSAVER_ENABLED, DEFAULT_SCREENSAVER_ENABLED,
+                Settings.Secure.SCREENSAVER_ENABLED, def,
                 UserHandle.USER_CURRENT) != 0;
     }
 
     private static boolean isScreenSaverActivatedOnDock(Context context) {
+        int def = context.getResources().getBoolean(
+                com.android.internal.R.bool.config_dreamsActivatedOnDockByDefault) ? 1 : 0;
         return Settings.Secure.getIntForUser(context.getContentResolver(),
-                Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK,
-                DEFAULT_SCREENSAVER_ACTIVATED_ON_DOCK, UserHandle.USER_CURRENT) != 0;
+                Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK, def,
+                UserHandle.USER_CURRENT) != 0;
     }
 }
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index ec1695e..59f941d 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -1200,7 +1200,12 @@
                             Trace.traceEnd(Trace.TRACE_TAG_VIEW);
                         }
 
-                        status = onPreDraw(dirty);
+                        Trace.traceBegin(Trace.TRACE_TAG_VIEW, "prepareFrame");
+                        try {
+                            status = onPreDraw(dirty);
+                        } finally {
+                            Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+                        }
                         saveCount = canvas.save();
                         callbacks.onHardwarePreDraw(canvas);
 
diff --git a/core/java/android/view/IDisplayContentChangeListener.aidl b/core/java/android/view/IDisplayContentChangeListener.aidl
index 8f23ff6..ef7edea 100644
--- a/core/java/android/view/IDisplayContentChangeListener.aidl
+++ b/core/java/android/view/IDisplayContentChangeListener.aidl
@@ -28,5 +28,6 @@
 oneway interface IDisplayContentChangeListener {
     void onWindowTransition(int displayId, int transition, in WindowInfo info);
     void onRectangleOnScreenRequested(int displayId, in Rect rectangle, boolean immediate);
+    void onWindowLayersChanged(int displayId);
     void onRotationChanged(int rotation);
 }
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index f692e05..26a5b26 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -20,7 +20,6 @@
 import android.os.Handler;
 import android.os.Message;
 import android.widget.FrameLayout;
-import com.android.internal.R;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -44,20 +43,20 @@
  *
  * <pre>LayoutInflater inflater = (LayoutInflater)context.getSystemService
  *      (Context.LAYOUT_INFLATER_SERVICE);</pre>
- *
+ * 
  * <p>
  * To create a new LayoutInflater with an additional {@link Factory} for your
  * own views, you can use {@link #cloneInContext} to clone an existing
  * ViewFactory, and then call {@link #setFactory} on it to include your
  * Factory.
- *
+ * 
  * <p>
  * For performance reasons, view inflation relies heavily on pre-processing of
  * XML files that is done at build time. Therefore, it is not currently possible
  * to use LayoutInflater with an XmlPullParser over a plain XML file at runtime;
  * it only works with an XmlPullParser returned from a compiled resource
  * (R.<em>something</em> file.)
- *
+ * 
  * @see Context#getSystemService
  */
 public abstract class LayoutInflater {
@@ -83,7 +82,7 @@
 
     private static final HashMap<String, Constructor<? extends View>> sConstructorMap =
             new HashMap<String, Constructor<? extends View>>();
-
+    
     private HashMap<String, Boolean> mFilterMap;
 
     private static final String TAG_MERGE = "merge";
@@ -94,36 +93,36 @@
     /**
      * Hook to allow clients of the LayoutInflater to restrict the set of Views that are allowed
      * to be inflated.
-     *
+     * 
      */
     public interface Filter {
         /**
          * Hook to allow clients of the LayoutInflater to restrict the set of Views 
          * that are allowed to be inflated.
-         *
+         * 
          * @param clazz The class object for the View that is about to be inflated
-         *
+         * 
          * @return True if this class is allowed to be inflated, or false otherwise
          */
         @SuppressWarnings("unchecked")
         boolean onLoadClass(Class clazz);
     }
-
+    
     public interface Factory {
         /**
          * Hook you can supply that is called when inflating from a LayoutInflater.
          * You can use this to customize the tag names available in your XML
          * layout files.
-         *
+         * 
          * <p>
          * Note that it is good practice to prefix these custom names with your
          * package (i.e., com.coolcompany.apps) to avoid conflicts with system
          * names.
-         *
+         * 
          * @param name Tag name to be inflated.
          * @param context The context the view is being created in.
          * @param attrs Inflation attributes as specified in XML file.
-         *
+         * 
          * @return View Newly created view. Return null for the default
          *         behavior.
          */
@@ -151,14 +150,14 @@
     private static class FactoryMerger implements Factory2 {
         private final Factory mF1, mF2;
         private final Factory2 mF12, mF22;
-
+        
         FactoryMerger(Factory f1, Factory2 f12, Factory f2, Factory2 f22) {
             mF1 = f1;
             mF2 = f2;
             mF12 = f12;
             mF22 = f22;
         }
-
+        
         public View onCreateView(String name, Context context, AttributeSet attrs) {
             View v = mF1.onCreateView(name, context, attrs);
             if (v != null) return v;
@@ -173,13 +172,13 @@
                     : mF2.onCreateView(name, context, attrs);
         }
     }
-
+    
     /**
      * Create a new LayoutInflater instance associated with a particular Context.
      * Applications will almost always want to use
      * {@link Context#getSystemService Context.getSystemService()} to retrieve
      * the standard {@link Context#LAYOUT_INFLATER_SERVICE Context.INFLATER_SERVICE}.
-     *
+     * 
      * @param context The Context in which this LayoutInflater will create its
      * Views; most importantly, this supplies the theme from which the default
      * values for their attributes are retrieved.
@@ -192,7 +191,7 @@
      * Create a new LayoutInflater instance that is a copy of an existing
      * LayoutInflater, optionally with its Context changed.  For use in
      * implementing {@link #cloneInContext}.
-     *
+     * 
      * @param original The original LayoutInflater to copy.
      * @param newContext The new Context to use.
      */
@@ -203,7 +202,7 @@
         mPrivateFactory = original.mPrivateFactory;
         mFilter = original.mFilter;
     }
-
+    
     /**
      * Obtains the LayoutInflater from the given context.
      */
@@ -221,15 +220,15 @@
      * pointing to a different Context than the original.  This is used by
      * {@link ContextThemeWrapper} to create a new LayoutInflater to go along
      * with the new Context theme.
-     *
+     * 
      * @param newContext The new Context to associate with the new LayoutInflater.
      * May be the same as the original Context if desired.
-     *
+     * 
      * @return Returns a brand spanking new LayoutInflater object associated with
      * the given Context.
      */
     public abstract LayoutInflater cloneInContext(Context newContext);
-
+    
     /**
      * Return the context we are running in, for access to resources, class
      * loader, etc.
@@ -265,7 +264,7 @@
      * called on each element name as the xml is parsed. If the factory returns
      * a View, that is added to the hierarchy. If it returns null, the next
      * factory default {@link #onCreateView} method is called.
-     *
+     * 
      * <p>If you have an existing
      * LayoutInflater and want to add your own factory to it, use
      * {@link #cloneInContext} to clone the existing instance and then you
@@ -321,13 +320,13 @@
     public Filter getFilter() {
         return mFilter;
     }
-
+    
     /**
      * Sets the {@link Filter} to by this LayoutInflater. If a view is attempted to be inflated
      * which is not allowed by the {@link Filter}, the {@link #inflate(int, ViewGroup)} call will
      * throw an {@link InflateException}. This filter will replace any previous filter set on this
      * LayoutInflater.
-     *
+     * 
      * @param filter The Filter which restricts the set of Views that are allowed to be inflated.
      *        This filter will replace any previous filter set on this LayoutInflater.
      */
@@ -341,7 +340,7 @@
     /**
      * Inflate a new view hierarchy from the specified xml resource. Throws
      * {@link InflateException} if there is an error.
-     *
+     * 
      * @param resource ID for an XML layout resource to load (e.g.,
      *        <code>R.layout.main_page</code>)
      * @param root Optional view to be the parent of the generated hierarchy.
@@ -361,7 +360,7 @@
      * reasons, view inflation relies heavily on pre-processing of XML files
      * that is done at build time. Therefore, it is not currently possible to
      * use LayoutInflater with an XmlPullParser over a plain XML file at runtime.
-     *
+     * 
      * @param parser XML dom node containing the description of the view
      *        hierarchy.
      * @param root Optional view to be the parent of the generated hierarchy.
@@ -376,7 +375,7 @@
     /**
      * Inflate a new view hierarchy from the specified xml resource. Throws
      * {@link InflateException} if there is an error.
-     *
+     * 
      * @param resource ID for an XML layout resource to load (e.g.,
      *        <code>R.layout.main_page</code>)
      * @param root Optional view to be the parent of the generated hierarchy (if
@@ -408,7 +407,7 @@
      * reasons, view inflation relies heavily on pre-processing of XML files
      * that is done at build time. Therefore, it is not currently possible to
      * use LayoutInflater with an XmlPullParser over a plain XML file at runtime.
-     *
+     * 
      * @param parser XML dom node containing the description of the view
      *        hierarchy.
      * @param root Optional view to be the parent of the generated hierarchy (if
@@ -443,7 +442,7 @@
                 }
 
                 final String name = parser.getName();
-
+                
                 if (DEBUG) {
                     System.out.println("**************************");
                     System.out.println("Creating root view: "
@@ -529,17 +528,17 @@
      * Low-level function for instantiating a view by name. This attempts to
      * instantiate a view class of the given <var>name</var> found in this
      * LayoutInflater's ClassLoader.
-     *
+     * 
      * <p>
      * There are two things that can happen in an error case: either the
      * exception describing the error will be thrown, or a null will be
      * returned. You must deal with both possibilities -- the former will happen
      * the first time createView() is called for a class of a particular name,
      * the latter every time there-after for that class name.
-     *
+     * 
      * @param name The full name of the class to be instantiated.
      * @param attrs The XML attributes supplied for this instance.
-     *
+     * 
      * @return View The newly instantiated view, or null.
      */
     public final View createView(String name, String prefix, AttributeSet attrs)
@@ -552,7 +551,7 @@
                 // Class not found in the cache, see if it's real, and try to add it
                 clazz = mContext.getClassLoader().loadClass(
                         prefix != null ? (prefix + name) : name).asSubclass(View.class);
-
+                
                 if (mFilter != null && clazz != null) {
                     boolean allowed = mFilter.onLoadClass(clazz);
                     if (!allowed) {
@@ -570,7 +569,7 @@
                         // New class -- remember whether it is allowed
                         clazz = mContext.getClassLoader().loadClass(
                                 prefix != null ? (prefix + name) : name).asSubclass(View.class);
-
+                        
                         boolean allowed = clazz != null && mFilter.onLoadClass(clazz);
                         mFilterMap.put(name, allowed);
                         if (!allowed) {
@@ -633,10 +632,10 @@
      * given the xml element name. Override it to handle custom view objects. If
      * you override this in your subclass be sure to call through to
      * super.onCreateView(name) for names you do not recognize.
-     *
+     * 
      * @param name The fully qualified class name of the View to be create.
      * @param attrs An AttributeSet of attributes to apply to the View.
-     *
+     * 
      * @return View The View created.
      */
     protected View onCreateView(String name, AttributeSet attrs)
@@ -680,7 +679,7 @@
             if (view == null && mPrivateFactory != null) {
                 view = mPrivateFactory.onCreateView(parent, name, mContext, attrs);
             }
-
+            
             if (view == null) {
                 if (-1 == name.indexOf('.')) {
                     view = onCreateView(parent, name, attrs);
@@ -727,7 +726,7 @@
             }
 
             final String name = parser.getName();
-
+            
             if (TAG_REQUEST_FOCUS.equals(name)) {
                 parseRequestFocus(parser, parent);
             } else if (TAG_INCLUDE.equals(name)) {
@@ -742,7 +741,7 @@
                 final ViewGroup viewGroup = (ViewGroup) parent;
                 final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs);
                 rInflate(parser, view, attrs, true);
-                viewGroup.addView(view, params);
+                viewGroup.addView(view, params);                
             } else {
                 final View view = createViewFromTag(parent, name, attrs);
                 final ViewGroup viewGroup = (ViewGroup) parent;
@@ -811,14 +810,21 @@
                         // We try to load the layout params set in the <include /> tag. If
                         // they don't exist, we will rely on the layout params set in the
                         // included XML file.
-                        TypedArray ta = getContext().obtainStyledAttributes(attrs,
-                                                            R.styleable.ViewGroup_Layout);
-                        boolean definesBothWidthAndHeight =
-                                ta.hasValue(R.styleable.ViewGroup_Layout_layout_width) &&
-                                ta.hasValue(R.styleable.ViewGroup_Layout_layout_height);
-                        AttributeSet attributes = definesBothWidthAndHeight ? attrs : childAttrs;
-                        view.setLayoutParams(group.generateLayoutParams(attributes));
-                        ta.recycle();
+                        // During a layoutparams generation, a runtime exception is thrown
+                        // if either layout_width or layout_height is missing. We catch
+                        // this exception and set localParams accordingly: true means we
+                        // successfully loaded layout params from the <include /> tag,
+                        // false means we need to rely on the included layout params.
+                        ViewGroup.LayoutParams params = null;
+                        try {
+                            params = group.generateLayoutParams(attrs);
+                        } catch (RuntimeException e) {
+                            params = group.generateLayoutParams(childAttrs);
+                        } finally {
+                            if (params != null) {
+                                view.setLayoutParams(params);
+                            }
+                        }
 
                         // Inflate all children.
                         rInflate(childParser, view, childAttrs, true);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index d2a088d..79a545f 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -10002,8 +10002,10 @@
 
     /**
      * Resolve the layout parameters depending on the resolved layout direction
+     *
+     * @hide
      */
-    private void resolveLayoutParams() {
+    public void resolveLayoutParams() {
         if (mLayoutParams != null) {
             mLayoutParams.resolveLayoutDirection(getLayoutDirection());
         }
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 20308c8..146fe2d 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -3477,7 +3477,7 @@
         }
 
         if (child.isLayoutDirectionInherited()) {
-            child.resetResolvedLayoutDirection();
+            child.resetRtlProperties();
             child.resolveRtlPropertiesIfNeeded();
         }
 
@@ -5453,6 +5453,19 @@
      * @hide
      */
     @Override
+    public void resolveLayoutParams() {
+        super.resolveLayoutParams();
+        int count = getChildCount();
+        for (int i = 0; i < count; i++) {
+            final View child = getChildAt(i);
+            child.resolveLayoutParams();
+        }
+    }
+
+    /**
+     * @hide
+     */
+    @Override
     public void resetRtlProperties() {
         super.resetRtlProperties();
         int count = getChildCount();
@@ -5702,19 +5715,15 @@
         }
 
         /**
-         * Extracts the <code>width</code> and <code>height</code> layout parameters
-         * from the supplied TypedArray, <code>a</code>, and assigns them
-         * to the appropriate fields. If, <code>a</code>, does not contain an
-         * entry for either attribute, the value, {@link ViewGroup.LayoutParams#WRAP_CONTENT},
-         * is used as a default.
+         * Extracts the layout parameters from the supplied attributes.
          *
          * @param a the style attributes to extract the parameters from
          * @param widthAttr the identifier of the width attribute
          * @param heightAttr the identifier of the height attribute
          */
         protected void setBaseAttributes(TypedArray a, int widthAttr, int heightAttr) {
-            width = a.getLayoutDimension(widthAttr, WRAP_CONTENT);
-            height = a.getLayoutDimension(heightAttr, WRAP_CONTENT);
+            width = a.getLayoutDimension(widthAttr, "layout_width");
+            height = a.getLayoutDimension(heightAttr, "layout_height");
         }
 
         /**
@@ -6072,6 +6081,11 @@
          */
         @Override
         public void resolveLayoutDirection(int layoutDirection) {
+            // No need to resolve if it is the same layout direction as before
+            if (this.layoutDirection == layoutDirection) {
+                return;
+            }
+
             setLayoutDirection(layoutDirection);
 
             if (!isMarginRelative()) return;
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index c6b3ba7..ed9201d 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -323,6 +323,7 @@
     ArrayList<View> mLayoutRequesters = new ArrayList<View>();
     boolean mHandlingLayoutInLayoutRequest = false;
 
+    private int mViewLayoutDirectionInitial;
 
     /**
      * Consistency verifier for debugging purposes.
@@ -472,6 +473,7 @@
         synchronized (this) {
             if (mView == null) {
                 mView = view;
+                mViewLayoutDirectionInitial = mView.getRawLayoutDirection();
                 mFallbackEventHandler.setView(view);
                 mWindowAttributes.copyFrom(attrs);
                 attrs = mWindowAttributes;
@@ -894,11 +896,13 @@
         // Intersect with the bounds of the window to skip
         // updates that lie outside of the visible region
         final float appScale = mAttachInfo.mApplicationScale;
-        localDirty.intersect(0, 0,
-                (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f));
-
-        if (!mWillDrawSoon) {
-            scheduleTraversals();
+        if (localDirty.intersect(0, 0,
+                (int) (mWidth * appScale + 0.5f), (int) (mHeight * appScale + 0.5f))) {
+            if (!mWillDrawSoon) {
+                scheduleTraversals();
+            }
+        } else {
+            localDirty.setEmpty();
         }
 
         return null;
@@ -1191,6 +1195,10 @@
             viewVisibilityChanged = false;
             mLastConfiguration.setTo(host.getResources().getConfiguration());
             mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
+            // Set the layout direction if it has not been set before (inherit is the default)
+            if (mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) {
+                host.setLayoutDirection(mLastConfiguration.getLayoutDirection());
+            }
             host.dispatchAttachedToWindow(attachInfo, 0);
             mFitSystemWindowsInsets.set(mAttachInfo.mContentInsets);
             host.fitSystemWindows(mFitSystemWindowsInsets);
@@ -2736,7 +2744,13 @@
             // the one in them which may be newer.
             config = mView.getResources().getConfiguration();
             if (force || mLastConfiguration.diff(config) != 0) {
+                final int lastLayoutDirection = mLastConfiguration.getLayoutDirection();
+                final int currentLayoutDirection = config.getLayoutDirection();
                 mLastConfiguration.setTo(config);
+                if (lastLayoutDirection != currentLayoutDirection &&
+                        mViewLayoutDirectionInitial == View.LAYOUT_DIRECTION_INHERIT) {
+                    mView.setLayoutDirection(currentLayoutDirection);
+                }
                 mView.dispatchConfigurationChanged(config);
             }
         }
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index 7855763c..5cdc1ed 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -99,6 +99,7 @@
     public static final int ADD_STARTING_NOT_NEEDED = -6;
     public static final int ADD_MULTIPLE_SINGLETON = -7;
     public static final int ADD_PERMISSION_DENIED = -8;
+    public static final int ADD_INVALID_DISPLAY = -9;
 
     private static WindowManagerGlobal sDefaultWindowManager;
     private static IWindowManager sWindowManagerService;
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index 646fe7e..3b5e75b 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -241,6 +241,7 @@
     
     @Override
     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+        super.onSizeChanged(w, h, oldw, oldh);
         updateThumbPos(w, h);
     }
 
@@ -555,4 +556,23 @@
         }
         return false;
     }
+
+    @Override
+    public void onRtlPropertiesChanged(int layoutDirection) {
+        super.onRtlPropertiesChanged(layoutDirection);
+
+        int max = getMax();
+        float scale = max > 0 ? (float) getProgress() / (float) max : 0;
+
+        Drawable thumb = mThumb;
+        if (thumb != null) {
+            setThumbPos(getWidth(), thumb, scale, Integer.MIN_VALUE);
+            /*
+             * Since we draw translated, the drawable's bounds that it signals
+             * for invalidation won't be the actual bounds we want invalidated,
+             * so just invalidate this whole view.
+             */
+            invalidate();
+        }
+    }
 }
diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
index 75d1471..f0eb94f 100644
--- a/core/java/android/widget/AutoCompleteTextView.java
+++ b/core/java/android/widget/AutoCompleteTextView.java
@@ -1093,7 +1093,6 @@
             mPopup.setInputMethodMode(ListPopupWindow.INPUT_METHOD_NEEDED);
             mPopup.setListItemExpandMax(EXPAND_MAX);
         }
-        mPopup.setLayoutDirection(getLayoutDirection());
         mPopup.show();
         mPopup.getListView().setOverScrollMode(View.OVER_SCROLL_ALWAYS);
     }
diff --git a/core/java/android/widget/FrameLayout.java b/core/java/android/widget/FrameLayout.java
index 45f30df..e158776 100644
--- a/core/java/android/widget/FrameLayout.java
+++ b/core/java/android/widget/FrameLayout.java
@@ -608,12 +608,6 @@
          */
         public int gravity = -1;
 
-        @Override
-        protected void setBaseAttributes(TypedArray a, int widthAttr, int heightAttr) {
-            width = a.getLayoutDimension(widthAttr, MATCH_PARENT);
-            height = a.getLayoutDimension(heightAttr, MATCH_PARENT);
-        }
-
         /**
          * {@inheritDoc}
          */
diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java
index 1c81d11..3d6b69e 100644
--- a/core/java/android/widget/ListPopupWindow.java
+++ b/core/java/android/widget/ListPopupWindow.java
@@ -1021,8 +1021,6 @@
                 mDropDownList.setOnItemSelectedListener(mItemSelectedListener);
             }
 
-            mDropDownList.setLayoutDirection(mLayoutDirection);
-
             dropDownView = mDropDownList;
 
             View hintView = mPromptView;
@@ -1132,21 +1130,6 @@
     }
 
     /**
-     * Set the layout direction for this popup. Should be a resolved direction as the
-     * popup as no capacity to do the resolution on his own.
-     *
-     * @param layoutDirection One of {@link View#LAYOUT_DIRECTION_LTR},
-     *   {@link View#LAYOUT_DIRECTION_RTL},
-     *
-     */
-    public void setLayoutDirection(int layoutDirection) {
-        mLayoutDirection = layoutDirection;
-        if (mDropDownList != null) {
-            mDropDownList.setLayoutDirection(mLayoutDirection);
-        }
-    }
-
-    /**
      * <p>Wrapper class for a ListView. This wrapper can hijack the focus to
      * make sure the list uses the appropriate drawables and states when
      * displayed on screen within a drop down. The focus is never actually
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index af3365e..b71649a 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -142,6 +142,8 @@
         };
     private int mAnchorXoff, mAnchorYoff;
 
+    private boolean mPopupViewInitialLayoutDirectionInherited;
+
     /**
      * <p>Create a new empty, non focusable popup window of dimension (0,0).</p>
      *
@@ -968,6 +970,8 @@
         } else {
             mPopupView = mContentView;
         }
+        mPopupViewInitialLayoutDirectionInherited =
+                (mPopupView.getRawLayoutDirection() == View.LAYOUT_DIRECTION_INHERIT);
         mPopupWidth = p.width;
         mPopupHeight = p.height;
     }
@@ -985,9 +989,19 @@
             p.packageName = mContext.getPackageName();
         }
         mPopupView.setFitsSystemWindows(mLayoutInsetDecor);
+        setLayoutDirectionFromAnchor();
         mWindowManager.addView(mPopupView, p);
     }
 
+    private void setLayoutDirectionFromAnchor() {
+        if (mAnchor != null) {
+            View anchor = mAnchor.get();
+            if (anchor != null && mPopupViewInitialLayoutDirectionInherited) {
+                mPopupView.setLayoutDirection(anchor.getLayoutDirection());
+            }
+        }
+    }
+
     /**
      * <p>Generate the layout parameters for the popup window.</p>
      *
@@ -1304,8 +1318,9 @@
             p.flags = newFlags;
             update = true;
         }
-        
+
         if (update) {
+            setLayoutDirectionFromAnchor();
             mWindowManager.updateViewLayout(mPopupView, p);
         }
     }
@@ -1406,6 +1421,7 @@
         }
 
         if (update) {
+            setLayoutDirectionFromAnchor();
             mWindowManager.updateViewLayout(mPopupView, p);
         }
     }
@@ -1482,7 +1498,7 @@
         } else {
             updateAboveAnchor(findDropDownPosition(anchor, p, mAnchorXoff, mAnchorYoff));            
         }
-        
+
         update(p.x, p.y, width, height, x != p.x || y != p.y);
     }
 
diff --git a/core/java/android/widget/RadioGroup.java b/core/java/android/widget/RadioGroup.java
index 42d63b2..78d05b0 100644
--- a/core/java/android/widget/RadioGroup.java
+++ b/core/java/android/widget/RadioGroup.java
@@ -297,6 +297,33 @@
         public LayoutParams(MarginLayoutParams source) {
             super(source);
         }
+
+        /**
+         * <p>Fixes the child's width to
+         * {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT} and the child's
+         * height to  {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT}
+         * when not specified in the XML file.</p>
+         *
+         * @param a the styled attributes set
+         * @param widthAttr the width attribute to fetch
+         * @param heightAttr the height attribute to fetch
+         */
+        @Override
+        protected void setBaseAttributes(TypedArray a,
+                int widthAttr, int heightAttr) {
+
+            if (a.hasValue(widthAttr)) {
+                width = a.getLayoutDimension(widthAttr, "layout_width");
+            } else {
+                width = WRAP_CONTENT;
+            }
+            
+            if (a.hasValue(heightAttr)) {
+                height = a.getLayoutDimension(heightAttr, "layout_height");
+            } else {
+                height = WRAP_CONTENT;
+            }
+        }
     }
 
     /**
diff --git a/core/java/android/widget/TableLayout.java b/core/java/android/widget/TableLayout.java
index b65b421..f4b2ce0 100644
--- a/core/java/android/widget/TableLayout.java
+++ b/core/java/android/widget/TableLayout.java
@@ -741,9 +741,14 @@
          * @param heightAttr the height attribute to fetch
          */
         @Override
-        protected void setBaseAttributes(TypedArray a, int widthAttr, int heightAttr) {
+        protected void setBaseAttributes(TypedArray a,
+                int widthAttr, int heightAttr) {
             this.width = MATCH_PARENT;
-            this.height = a.getLayoutDimension(heightAttr, WRAP_CONTENT);
+            if (a.hasValue(heightAttr)) {
+                this.height = a.getLayoutDimension(heightAttr, "layout_height");
+            } else {
+                this.height = WRAP_CONTENT;
+            }
         }
     }
 
diff --git a/core/java/android/widget/TableRow.java b/core/java/android/widget/TableRow.java
index a647d10..a8cc406 100644
--- a/core/java/android/widget/TableRow.java
+++ b/core/java/android/widget/TableRow.java
@@ -505,8 +505,19 @@
 
         @Override
         protected void setBaseAttributes(TypedArray a, int widthAttr, int heightAttr) {
-            width = a.getLayoutDimension(widthAttr, MATCH_PARENT);
-            height = a.getLayoutDimension(heightAttr, WRAP_CONTENT);
+            // We don't want to force users to specify a layout_width
+            if (a.hasValue(widthAttr)) {
+                width = a.getLayoutDimension(widthAttr, "layout_width");
+            } else {
+                width = MATCH_PARENT;
+            }
+
+            // We don't want to force users to specify a layout_height
+            if (a.hasValue(heightAttr)) {
+                height = a.getLayoutDimension(heightAttr, "layout_height");
+            } else {
+                height = WRAP_CONTENT;
+            }
         }
     }
 
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index f0b3832..8d00444 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -6318,7 +6318,7 @@
         if (mDeferScroll >= 0) {
             int curs = mDeferScroll;
             mDeferScroll = -1;
-            bringPointIntoView(curs);
+            bringPointIntoView(Math.min(curs, mText.length()));
         }
         if (changed && mEditor != null) mEditor.invalidateTextDisplayList();
     }
diff --git a/core/java/com/android/internal/net/VpnProfile.java b/core/java/com/android/internal/net/VpnProfile.java
index 7287327..c9b7cb3 100644
--- a/core/java/com/android/internal/net/VpnProfile.java
+++ b/core/java/com/android/internal/net/VpnProfile.java
@@ -70,6 +70,47 @@
         this.key = key;
     }
 
+    public VpnProfile(Parcel in) {
+        key = in.readString();
+        name = in.readString();
+        type = in.readInt();
+        server = in.readString();
+        username = in.readString();
+        password = in.readString();
+        dnsServers = in.readString();
+        searchDomains = in.readString();
+        routes = in.readString();
+        mppe = in.readInt() != 0;
+        l2tpSecret = in.readString();
+        ipsecIdentifier = in.readString();
+        ipsecSecret = in.readString();
+        ipsecUserCert = in.readString();
+        ipsecCaCert = in.readString();
+        ipsecServerCert = in.readString();
+        saveLogin = in.readInt() != 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeString(key);
+        out.writeString(name);
+        out.writeInt(type);
+        out.writeString(server);
+        out.writeString(username);
+        out.writeString(password);
+        out.writeString(dnsServers);
+        out.writeString(searchDomains);
+        out.writeString(routes);
+        out.writeInt(mppe ? 1 : 0);
+        out.writeString(l2tpSecret);
+        out.writeString(ipsecIdentifier);
+        out.writeString(ipsecSecret);
+        out.writeString(ipsecUserCert);
+        out.writeString(ipsecCaCert);
+        out.writeString(ipsecServerCert);
+        out.writeInt(saveLogin ? 1 : 0);
+    }
+
     public static VpnProfile decode(String key, byte[] value) {
         try {
             if (key == null) {
@@ -155,17 +196,10 @@
         }
     }
 
-    @Override
-    public void writeToParcel(Parcel out, int flags) {
-        out.writeString(key);
-        out.writeByteArray(encode());
-    }
-
     public static final Creator<VpnProfile> CREATOR = new Creator<VpnProfile>() {
         @Override
         public VpnProfile createFromParcel(Parcel in) {
-            final String key = in.readString();
-            return decode(key, in.createByteArray());
+            return new VpnProfile(in);
         }
 
         @Override
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 3ca085b..b159ced 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -200,6 +200,7 @@
 	libETC1 \
 	libhardware \
 	libhardware_legacy \
+	libselinux \
 	libsonivox \
 	libcrypto \
 	libssl \
@@ -213,12 +214,6 @@
 	libharfbuzz \
 	libz
 
-ifeq ($(HAVE_SELINUX),true)
-LOCAL_C_INCLUDES += external/libselinux/include
-LOCAL_SHARED_LIBRARIES += libselinux
-LOCAL_CFLAGS += -DHAVE_SELINUX
-endif # HAVE_SELINUX
-
 ifeq ($(USE_OPENGL_RENDERER),true)
 	LOCAL_SHARED_LIBRARIES += libhwui
 endif
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index fd7a6a7..f485e03 100644
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -7,7 +7,7 @@
 #include "SkUnPreMultiply.h"

 

 #include <binder/Parcel.h>

-#include "android_os_Parcel.h"
+#include "android_os_Parcel.h"

 #include "android_util_Binder.h"

 #include "android_nio_utils.h"

 #include "CreateJavaOutputStreamAdaptor.h"

@@ -353,6 +353,15 @@
     bitmap->setIsOpaque(!hasAlpha);

 }

 

+static jboolean Bitmap_hasMipMap(JNIEnv* env, jobject, SkBitmap* bitmap) {

+    return bitmap->hasHardwareMipMap();

+}

+

+static void Bitmap_setHasMipMap(JNIEnv* env, jobject, SkBitmap* bitmap,

+                                jboolean hasMipMap) {

+    bitmap->setHasHardwareMipMap(hasMipMap);

+}

+

 ///////////////////////////////////////////////////////////////////////////////

 

 static jobject Bitmap_createFromParcel(JNIEnv* env, jobject, jobject parcel) {

@@ -666,6 +675,8 @@
     {   "nativeConfig",             "(I)I", (void*)Bitmap_config },

     {   "nativeHasAlpha",           "(I)Z", (void*)Bitmap_hasAlpha },

     {   "nativeSetHasAlpha",        "(IZ)V", (void*)Bitmap_setHasAlpha },

+    {   "nativeHasMipMap",          "(I)Z", (void*)Bitmap_hasMipMap },

+    {   "nativeSetHasMipMap",       "(IZ)V", (void*)Bitmap_setHasMipMap },

     {   "nativeCreateFromParcel",

         "(Landroid/os/Parcel;)Landroid/graphics/Bitmap;",

         (void*)Bitmap_createFromParcel },

diff --git a/core/jni/android/graphics/YuvToJpegEncoder.cpp b/core/jni/android/graphics/YuvToJpegEncoder.cpp
index 8333e00..f386905 100644
--- a/core/jni/android/graphics/YuvToJpegEncoder.cpp
+++ b/core/jni/android/graphics/YuvToJpegEncoder.cpp
@@ -90,8 +90,9 @@
     // process 16 lines of Y and 8 lines of U/V each time.
     while (cinfo->next_scanline < cinfo->image_height) {
         //deitnerleave u and v
-        deinterleave(vuPlanar, uRows, vRows, cinfo->next_scanline, width);
+        deinterleave(vuPlanar, uRows, vRows, cinfo->next_scanline, width, height);
 
+        // Jpeg library ignores the rows whose indices are greater than height.
         for (int i = 0; i < 16; i++) {
             // y row
             y[i] = yPlanar + (cinfo->next_scanline + i) * fStrides[0];
@@ -112,8 +113,10 @@
 }
 
 void Yuv420SpToJpegEncoder::deinterleave(uint8_t* vuPlanar, uint8_t* uRows,
-        uint8_t* vRows, int rowIndex, int width) {
-    for (int row = 0; row < 8; ++row) {
+        uint8_t* vRows, int rowIndex, int width, int height) {
+    int numRows = (height - rowIndex) / 2;
+    if (numRows > 8) numRows = 8;
+    for (int row = 0; row < numRows; ++row) {
         int offset = ((rowIndex >> 1) + row) * fStrides[1];
         uint8_t* vu = vuPlanar + offset;
         for (int i = 0; i < (width >> 1); ++i) {
@@ -164,6 +167,7 @@
     while (cinfo->next_scanline < cinfo->image_height) {
         deinterleave(yuvOffset, yRows, uRows, vRows, cinfo->next_scanline, width, height);
 
+        // Jpeg library ignores the rows whose indices are greater than height.
         for (int i = 0; i < 16; i++) {
             // y row
             y[i] = yRows + i * width;
@@ -185,7 +189,9 @@
 
 void Yuv422IToJpegEncoder::deinterleave(uint8_t* yuv, uint8_t* yRows, uint8_t* uRows,
         uint8_t* vRows, int rowIndex, int width, int height) {
-    for (int row = 0; row < 16; ++row) {
+    int numRows = height - rowIndex;
+    if (numRows > 16) numRows = 16;
+    for (int row = 0; row < numRows; ++row) {
         uint8_t* yuvSeg = yuv + (rowIndex + row) * fStrides[0];
         for (int i = 0; i < (width >> 1); ++i) {
             int indexY = row * width + (i << 1);
diff --git a/core/jni/android/graphics/YuvToJpegEncoder.h b/core/jni/android/graphics/YuvToJpegEncoder.h
index 97106ce..0d418ed 100644
--- a/core/jni/android/graphics/YuvToJpegEncoder.h
+++ b/core/jni/android/graphics/YuvToJpegEncoder.h
@@ -55,7 +55,7 @@
      void deinterleaveYuv(uint8_t* yuv, int width, int height,
             uint8_t*& yPlanar, uint8_t*& uPlanar, uint8_t*& vPlanar);
      void deinterleave(uint8_t* vuPlanar, uint8_t* uRows, uint8_t* vRows,
-             int rowIndex, int width);
+             int rowIndex, int width, int height);
      void compress(jpeg_compress_struct* cinfo, uint8_t* yuv, int* offsets);
 };
 
diff --git a/core/jni/android_os_SELinux.cpp b/core/jni/android_os_SELinux.cpp
index e813c38..b12fdfc 100644
--- a/core/jni/android_os_SELinux.cpp
+++ b/core/jni/android_os_SELinux.cpp
@@ -20,10 +20,8 @@
 #include "JNIHelp.h"
 #include "jni.h"
 #include "android_runtime/AndroidRuntime.h"
-#ifdef HAVE_SELINUX
 #include "selinux/selinux.h"
 #include "selinux/android.h"
-#endif
 #include <errno.h>
 
 namespace android {
@@ -56,11 +54,7 @@
    * Exceptions: none
    */
   static jboolean isSELinuxEnforced(JNIEnv *env, jobject clazz) {
-#ifdef HAVE_SELINUX
     return (security_getenforce() == 1) ? true : false;
-#else
-    return false;
-#endif
   }
 
   /*
@@ -71,16 +65,12 @@
    * Exceptions: none
    */
   static jboolean setSELinuxEnforce(JNIEnv *env, jobject clazz, jboolean value) {
-#ifdef HAVE_SELINUX
     if (isSELinuxDisabled)
       return false;
 
     int enforce = (value) ? 1 : 0;
 
     return (security_setenforce(enforce) != -1) ? true : false;
-#else
-    return false;
-#endif
   }
 
   /*
@@ -92,7 +82,6 @@
    * Exceptions: NullPointerException if fileDescriptor object is NULL
    */
   static jstring getPeerCon(JNIEnv *env, jobject clazz, jobject fileDescriptor) {
-#ifdef HAVE_SELINUX
     if (isSELinuxDisabled)
       return NULL;
 
@@ -123,9 +112,6 @@
       freecon(context);
 
     return securityString;
-#else
-    return NULL;
-#endif
   }
 
   /*
@@ -138,7 +124,6 @@
    * Exception: none
    */
   static jboolean setFSCreateCon(JNIEnv *env, jobject clazz, jstring context) {
-#ifdef HAVE_SELINUX
     if (isSELinuxDisabled)
       return false;
 
@@ -163,9 +148,6 @@
       env->ReleaseStringUTFChars(context, constant_securityContext);
 
     return (ret == 0) ? true : false;
-#else
-    return false;
-#endif
   }
 
   /*
@@ -178,7 +160,6 @@
    * Exception: NullPointerException is thrown if either path or context strign are NULL
    */
   static jboolean setFileCon(JNIEnv *env, jobject clazz, jstring path, jstring con) {
-#ifdef HAVE_SELINUX
     if (isSELinuxDisabled)
       return false;
 
@@ -208,9 +189,6 @@
     env->ReleaseStringUTFChars(path, objectPath);
     env->ReleaseStringUTFChars(con, constant_con);
     return (ret == 0) ? true : false;
-#else
-    return false;
-#endif
   }
 
   /*
@@ -224,7 +202,6 @@
    * Exceptions: NullPointerException if the path object is null
    */
   static jstring getFileCon(JNIEnv *env, jobject clazz, jstring path) {
-#ifdef HAVE_SELINUX
     if (isSELinuxDisabled)
       return NULL;
 
@@ -252,9 +229,6 @@
     env->ReleaseStringUTFChars(path, objectPath);
 
     return securityString;
-#else
-    return NULL;
-#endif
   }
 
   /*
@@ -266,7 +240,6 @@
    * Exceptions: none
    */
   static jstring getCon(JNIEnv *env, jobject clazz) {
-#ifdef HAVE_SELINUX
     if (isSELinuxDisabled)
       return NULL;
 
@@ -285,9 +258,6 @@
       freecon(context);
 
     return securityString;
-#else
-    return NULL;
-#endif
   }
 
   /*
@@ -300,7 +270,6 @@
    * Exceptions: none
    */
   static jstring getPidCon(JNIEnv *env, jobject clazz, jint pid) {
-#ifdef HAVE_SELINUX
     if (isSELinuxDisabled)
       return NULL;
 
@@ -321,9 +290,6 @@
       freecon(context);
 
     return securityString;
-#else
-    return NULL;
-#endif
   }
 
   /*
@@ -335,7 +301,6 @@
    * Exceptions: None
    */
   static jobjectArray getBooleanNames(JNIEnv *env, JNIEnv clazz) {
-#ifdef HAVE_SELINUX
     if (isSELinuxDisabled)
       return NULL;
 
@@ -359,9 +324,6 @@
     free(list);
 
     return stringArray;
-#else
-    return NULL;
-#endif
   }
 
   /*
@@ -373,7 +335,6 @@
    * Exceptions: None
    */
   static jboolean getBooleanValue(JNIEnv *env, jobject clazz, jstring name) {
-#ifdef HAVE_SELINUX
     if (isSELinuxDisabled)
       return false;
 
@@ -386,9 +347,6 @@
     ret = security_get_boolean_active(boolean_name);
     env->ReleaseStringUTFChars(name, boolean_name);
     return (ret == 1) ? true : false;
-#else
-    return false;
-#endif
   }
 
   /*
@@ -401,7 +359,6 @@
    * Exceptions: None
    */
   static jboolean setBooleanValue(JNIEnv *env, jobject clazz, jstring name, jboolean value) {
-#ifdef HAVE_SELINUX
     if (isSELinuxDisabled)
       return false;
 
@@ -420,9 +377,6 @@
       return false;
 
     return true;
-#else
-    return false;
-#endif
   }
 
   /*
@@ -436,7 +390,6 @@
    * Exceptions: None
    */
   static jboolean checkSELinuxAccess(JNIEnv *env, jobject clazz, jstring scon, jstring tcon, jstring tclass, jstring perm) {
-#ifdef HAVE_SELINUX
     if (isSELinuxDisabled)
       return true;
 
@@ -468,10 +421,6 @@
 
   bail:
     return (accessGranted == 0) ? true : false;
-
-#else
-    return true;
-#endif
   }
 
   /*
@@ -482,7 +431,6 @@
    * Exceptions: none
    */
   static jboolean native_restorecon(JNIEnv *env, jobject clazz, jstring pathname) {
-#ifdef HAVE_SELINUX
     if (isSELinuxDisabled)
       return true;
 
@@ -490,9 +438,6 @@
     int ret = selinux_android_restorecon(file);
     env->ReleaseStringUTFChars(pathname, file);
     return (ret == 0);
-#else
-    return true;
-#endif
   }
 
   /*
@@ -526,14 +471,12 @@
   }
 
   int register_android_os_SELinux(JNIEnv *env) {
-#ifdef HAVE_SELINUX
     union selinux_callback cb;
     cb.func_log = log_callback;
     selinux_set_callback(SELINUX_CB_LOG, cb);
 
     isSELinuxDisabled = (is_selinux_enabled() != 1) ? true : false;
 
-#endif
     return AndroidRuntime::registerNativeMethods(
          env, "android/os/SELinux",
          method_table, NELEM(method_table));
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 1b71b43..5d306d2 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -829,7 +829,6 @@
 
 static void android_view_GLES20Canvas_setTextureLayerTransform(JNIEnv* env, jobject clazz,
         Layer* layer, SkMatrix* matrix) {
-
     layer->getTransform().load(*matrix);
 }
 
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index aa67ec2..92aa06a 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -2032,7 +2032,7 @@
     <permission android:name="android.permission.SERIAL_PORT"
         android:label="@string/permlab_serialPort"
         android:description="@string/permdesc_serialPort"
-        android:protectionLevel="normal" />
+        android:protectionLevel="signature|system" />
 
     <!-- Allows the holder to access content providers from outside an ApplicationThread.
          This permission is enforced by the ActivityManagerService on the corresponding APIs,
diff --git a/core/res/res/drawable-hdpi/ic_notify_wifidisplay.png b/core/res/res/drawable-hdpi/ic_notify_wifidisplay.png
new file mode 100644
index 0000000..35f27df
--- /dev/null
+++ b/core/res/res/drawable-hdpi/ic_notify_wifidisplay.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/ic_notify_wifidisplay.png b/core/res/res/drawable-mdpi/ic_notify_wifidisplay.png
new file mode 100644
index 0000000..f9c8678
--- /dev/null
+++ b/core/res/res/drawable-mdpi/ic_notify_wifidisplay.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/ic_notify_wifidisplay.png b/core/res/res/drawable-xhdpi/ic_notify_wifidisplay.png
new file mode 100644
index 0000000..4cc0ee8
--- /dev/null
+++ b/core/res/res/drawable-xhdpi/ic_notify_wifidisplay.png
Binary files differ
diff --git a/core/res/res/layout-port/keyguard_host_view.xml b/core/res/res/layout-port/keyguard_host_view.xml
index 20726d0..981fe6d 100644
--- a/core/res/res/layout-port/keyguard_host_view.xml
+++ b/core/res/res/layout-port/keyguard_host_view.xml
@@ -33,7 +33,8 @@
 
     <com.android.internal.policy.impl.keyguard.KeyguardSecurityViewFlipper
         android:id="@+id/view_flipper"
-        android:layout_height="0dp"
+        android:layout_width="match_parent"
+        android:layout_height="0dip"
         android:clipChildren="false"
         android:clipToPadding="false"
         android:layout_weight="1"
diff --git a/core/res/res/layout-port/keyguard_status_area.xml b/core/res/res/layout-port/keyguard_status_area.xml
index e0a49dc..c1f6aab 100644
--- a/core/res/res/layout-port/keyguard_status_area.xml
+++ b/core/res/res/layout-port/keyguard_status_area.xml
@@ -45,6 +45,8 @@
 
         <TextView
             android:id="@+id/alarm_status"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
             android:layout_marginEnd="@dimen/kg_status_line_font_right_margin"
             android:singleLine="true"
             android:ellipsize="marquee"
@@ -93,4 +95,4 @@
         android:textSize="@dimen/kg_status_line_font_size"
         />
         
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
diff --git a/core/res/res/layout-sw600dp-port/keyguard_status_area.xml b/core/res/res/layout-sw600dp-port/keyguard_status_area.xml
index f21254a..405ac14 100644
--- a/core/res/res/layout-sw600dp-port/keyguard_status_area.xml
+++ b/core/res/res/layout-sw600dp-port/keyguard_status_area.xml
@@ -78,4 +78,4 @@
         android:textAppearance="?android:attr/textAppearance"
         android:textSize="@dimen/kg_status_line_font_size"
         />
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
diff --git a/core/res/res/layout/default_navigation.xml b/core/res/res/layout/default_navigation.xml
index b13103c..b216ded 100644
--- a/core/res/res/layout/default_navigation.xml
+++ b/core/res/res/layout/default_navigation.xml
@@ -18,6 +18,8 @@
 -->
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/keyguard_click_area"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content"
     android:gravity="center">
 
     <!-- message area for security screen -->
diff --git a/core/res/res/layout/keyguard_password_view.xml b/core/res/res/layout/keyguard_password_view.xml
index ab8aa85..81916f7 100644
--- a/core/res/res/layout/keyguard_password_view.xml
+++ b/core/res/res/layout/keyguard_password_view.xml
@@ -53,6 +53,7 @@
                      since the backspace/IME switcher looks better inside -->
                 <LinearLayout
                     android:layout_gravity="center_vertical|fill_horizontal"
+                    android:layout_height="wrap_content"
                     android:layout_width="match_parent"
                     android:orientation="horizontal"
                     android:background="#70000000"
diff --git a/core/res/res/layout/keyguard_sim_pin_view.xml b/core/res/res/layout/keyguard_sim_pin_view.xml
index 163dc15..ae59d1d 100644
--- a/core/res/res/layout/keyguard_sim_pin_view.xml
+++ b/core/res/res/layout/keyguard_sim_pin_view.xml
@@ -91,6 +91,7 @@
         <!-- Numeric keyboard -->
         <com.android.internal.widget.PasswordEntryKeyboardView android:id="@+id/keyboard"
             android:layout_width="match_parent"
+            android:layout_height="wrap_content"
             android:layout_marginStart="4dip"
             android:layout_marginEnd="4dip"
             android:paddingTop="4dip"
diff --git a/core/res/res/layout/keyguard_sim_puk_view.xml b/core/res/res/layout/keyguard_sim_puk_view.xml
index 6e45b0b..414806f 100644
--- a/core/res/res/layout/keyguard_sim_puk_view.xml
+++ b/core/res/res/layout/keyguard_sim_puk_view.xml
@@ -93,6 +93,7 @@
         <!-- Numeric keyboard -->
         <com.android.internal.widget.PasswordEntryKeyboardView android:id="@+id/keyboard"
             android:layout_width="match_parent"
+            android:layout_height="wrap_content"
             android:layout_marginStart="4dip"
             android:layout_marginEnd="4dip"
             android:paddingTop="4dip"
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index c93008d..3e8892b 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1418,7 +1418,7 @@
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Jy het jou ontsluitpatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerdelik geteken. Na nog <xliff:g id="NUMBER_1">%d</xliff:g> onsuksesvolle pogings, sal jy gevra word om jou tablet te ontsluit deur middel van \'n e-posrekening."\n\n" Probeer weer oor <xliff:g id="NUMBER_2">%d</xliff:g> sekondes."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Jy het jou ontsluitpatroon <xliff:g id="NUMBER_0">%d</xliff:g> keer verkeerdelik geteken. Na nog <xliff:g id="NUMBER_1">%d</xliff:g> onsuksesvolle pogings, sal jy gevra word om jou foon te ontsluit deur middel van \'n e-posrekening."\n\n" Probeer weer oor <xliff:g id="NUMBER_2">%d</xliff:g> sekondes."</string>
     <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Moet volume bo veilige vlak verhoog word?"\n"Deur vir lang tydperke op hoë volume te luister, kan jou gehoor beskadig."</string>
-    <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Hou twee vingers in om toeganklikheid te aktiveer."</string>
+    <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Hou aan met twee vingers inhou om toeganklikheid te aktiveer."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Toeganklikheid geaktiveer."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Toeganklikheid gekanselleer."</string>
     <string name="user_switched" msgid="3768006783166984410">"Huidige gebruiker <xliff:g id="NAME">%1$s</xliff:g> ."</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index dfa88344..61ec74d 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1418,8 +1418,7 @@
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"لقد رسمت نقش إلغاء التأمين بشكل غير صحيح <xliff:g id="NUMBER_0">%d</xliff:g> مرة. بعد إجراء <xliff:g id="NUMBER_1">%d</xliff:g> من المحاولات غير الناجحة الأخرى، ستطالَب بإلغاء تأمين الجهاز اللوحي باستخدام معلومات حساب بريد إلكتروني."\n\n" أعد المحاولة خلال <xliff:g id="NUMBER_2">%d</xliff:g> ثانية."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"لقد رسمت نقش إلغاء التأمين بشكل غير صحيح <xliff:g id="NUMBER_0">%d</xliff:g> مرة. بعد إجراء <xliff:g id="NUMBER_1">%d</xliff:g> من المحاولات غير الناجحة الأخرى، ستُطالب بإلغاء تأمين الهاتف باستخدام حساب بريد إلكتروني لإلغاء تأمين الهاتف."\n\n" أعد المحاولة خلال <xliff:g id="NUMBER_2">%d</xliff:g> ثانية."</string>
     <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"هل تريد رفع مستوى الصوت فوق المستوى الآمن؟"\n"قد يضر سماع صوت عالٍ لفترات طويلة بسمعك."</string>
-    <!-- no translation found for continue_to_enable_accessibility (1626427372316070258) -->
-    <skip />
+    <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"اضغط بإصبعين لأسفل مع الاستمرار لتمكين تسهيل الدخول."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"تم تمكين إمكانية الدخول."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"تم إلغاء تسهيل الدخول."</string>
     <string name="user_switched" msgid="3768006783166984410">"المستخدم الحالي <xliff:g id="NAME">%1$s</xliff:g>."</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 4403f97..dd16a34 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -1419,8 +1419,7 @@
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Вы няправільна ўвялі графічны ключ разблакiроўкi пэўную колькасць разоў: <xliff:g id="NUMBER_0">%d</xliff:g>. Пасля яшчэ некалькiх няўдалых спроб (<xliff:g id="NUMBER_1">%d</xliff:g>) вам будзе прапанавана разблакiраваць тэлефон, увайшоўшы ў Google."\n\n" Паўтарыце спробу праз <xliff:g id="NUMBER_2">%d</xliff:g> с."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Вы няправільна ўвялі графічны ключ разблакiроўкi пэўную колькасць разоў: <xliff:g id="NUMBER_0">%d</xliff:g>. Пасля яшчэ некалькiх няўдалых спроб (<xliff:g id="NUMBER_1">%d</xliff:g>) вам будзе прапанавана разблакiраваць тэлефон, увайшоўшы ў Google."\n\n" Паўтарыце спробу праз <xliff:g id="NUMBER_2">%d</xliff:g> с."</string>
     <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Павялiчыць гук больш за рэкамендаваны ўзровень?"\n"Доўгае слуханне музыкi на вялiкай гучнасцi можа пашкодзiць ваш слых."</string>
-    <!-- no translation found for continue_to_enable_accessibility (1626427372316070258) -->
-    <skip />
+    <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Утрымлiвайце два пальцы, каб уключыць доступ."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Даступнасць уключана."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Даступнасць адменена."</string>
     <string name="user_switched" msgid="3768006783166984410">"Бягучы карыстальнік <xliff:g id="NAME">%1$s</xliff:g>."</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index b46e30a..ad806db 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1418,8 +1418,7 @@
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Начертахте неправилно фигурата си за отключване <xliff:g id="NUMBER_0">%d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%d</xliff:g> неуспешни опита ще бъдете помолени да отключите таблета посредством имейл адрес."\n\n" Опитайте отново след <xliff:g id="NUMBER_2">%d</xliff:g> секунди."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Начертахте неправилно фигурата си за отключване <xliff:g id="NUMBER_0">%d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%d</xliff:g> неуспешни опита ще бъдете помолени да отключите телефона посредством имейл адрес."\n\n" Опитайте отново след <xliff:g id="NUMBER_2">%d</xliff:g> секунди."</string>
     <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Да се увеличи ли силата на звука над безопасното ниво?"\n"Продължителното слушане при висока сила на звука може да увреди слуха ви."</string>
-    <!-- no translation found for continue_to_enable_accessibility (1626427372316070258) -->
-    <skip />
+    <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Продължете да натискате с два пръста, за да активирате функцията за достъпност."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Достъпността е активирана."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Функцията за достъпност е анулирана."</string>
     <string name="user_switched" msgid="3768006783166984410">"Текущ потребител <xliff:g id="NAME">%1$s</xliff:g>."</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 7381366..5d43397 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1418,8 +1418,7 @@
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Již <xliff:g id="NUMBER_0">%d</xliff:g>krát jste nesprávně nakreslili své heslo odemknutí. Po <xliff:g id="NUMBER_1">%d</xliff:g>dalších neúspěšných pokusech budete požádáni o odemčení tabletu pomocí e-mailového účtu."\n\n" Zkuste to znovu za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Již <xliff:g id="NUMBER_0">%d</xliff:g>krát jste nesprávně nakreslili své heslo odemknutí. Po <xliff:g id="NUMBER_1">%d</xliff:g> dalších neúspěšných pokusech budete požádáni o odemčení telefonu pomocí e-mailového účtu."\n\n" Zkuste to znovu za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
     <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Chcete hlasitost zvýšit nad bezpečnou úroveň?"\n"Dlouhodobý poslech hlasitého zvuku může poškodit sluch."</string>
-    <!-- no translation found for continue_to_enable_accessibility (1626427372316070258) -->
-    <skip />
+    <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Usnadnění zapnete dlouhým stisknutím dvěma prsty."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Usnadnění přístupu je aktivováno."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Usnadnění zrušeno."</string>
     <string name="user_switched" msgid="3768006783166984410">"Aktuální uživatel je <xliff:g id="NAME">%1$s</xliff:g>."</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index c938ca5..d66665b 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -1418,8 +1418,7 @@
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%d</xliff:g> weiteren erfolglosen Versuchen werden Sie aufgefordert, Ihr Tablet mithilfe eines E-Mail-Kontos zu entsperren."\n\n" Versuchen Sie es in <xliff:g id="NUMBER_2">%d</xliff:g> Sekunden erneut."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Sie haben Ihr Entsperrungsmuster <xliff:g id="NUMBER_0">%d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%d</xliff:g> weiteren erfolglosen Versuchen werden Sie aufgefordert, Ihr Telefon mithilfe eines E-Mail-Kontos zu entsperren."\n\n" Versuchen Sie es in <xliff:g id="NUMBER_2">%d</xliff:g> Sekunden erneut."</string>
     <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Lautstärke höher als Schwellenwert stellen?"\n"Wenn Sie über längere Zeiträume hinweg Musik in hoher Lautstärke hören, kann dies Ihr Gehör schädigen."</string>
-    <!-- no translation found for continue_to_enable_accessibility (1626427372316070258) -->
-    <skip />
+    <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Drücken Sie mit zwei Fingern, um die Bedienungshilfen zu aktivieren."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Bedienungshilfen aktiviert"</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Bedienungshilfen abgebrochen"</string>
     <string name="user_switched" msgid="3768006783166984410">"Aktueller Nutzer <xliff:g id="NAME">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index d0a1cd9..ef6962f 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -1418,8 +1418,7 @@
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Dibujaste incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. Luego de <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos más, se te solicitará que desbloquees tu tableta mediante el uso de una cuenta de correo."\n\n" Vuelve a intentarlo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Dibujaste incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%d</xliff:g> veces. Luego de <xliff:g id="NUMBER_1">%d</xliff:g> intentos incorrectos más, se te solicitará que desbloquees tu dispositivo mediante el uso de una cuenta de correo."\n\n" Vuelve a intentarlo en <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
     <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"¿Aumentar el volumen por encima del nivel seguro?"\n"Si escuchas con el volumen alto durante períodos prolongados, puedes dañar tu audición."</string>
-    <!-- no translation found for continue_to_enable_accessibility (1626427372316070258) -->
-    <skip />
+    <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Mantén presionado con dos dedos para activar la accesibilidad."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Se activó la accesibilidad."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Se canceló la accesibilidad."</string>
     <string name="user_switched" msgid="3768006783166984410">"Usuario actual: <xliff:g id="NAME">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index ae0ca2b..a50947c 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -1418,8 +1418,7 @@
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"شما الگوی بازگشایی قفل خود را <xliff:g id="NUMBER_0">%d</xliff:g> بار اشتباه کشیده‎اید. بعد از <xliff:g id="NUMBER_1">%d</xliff:g> تلاش ناموفق، از شما خواسته می‎شود که با استفاده از یک حساب ایمیل قفل رایانه لوحی خود را باز کنید."\n\n" لطفاً پس از <xliff:g id="NUMBER_2">%d</xliff:g> ثانیه دوباره امتحان کنید."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"شما الگوی بازگشایی قفل خود را <xliff:g id="NUMBER_0">%d</xliff:g> بار اشتباه کشیده‌اید. پس از <xliff:g id="NUMBER_1">%d</xliff:g> تلاش ناموفق، از شما خواسته می‎شود که با استفاده از یک حساب ایمیل قفل تلفن خود را باز کنید."\n\n" لطفاً پس از <xliff:g id="NUMBER_2">%d</xliff:g> ثانیه دوباره امتحان کنید."</string>
     <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"صدا به بالاتر از سطح ایمن افزایش یابد؟"\n"گوش دادن به صدای بلند برای زمان‌های طولانی می‌تواند به شنوایی شما آسیب برساند."</string>
-    <!-- no translation found for continue_to_enable_accessibility (1626427372316070258) -->
-    <skip />
+    <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"برای فعال کردن قابلیت دسترسی، با دو انگشت خود همچنان به طرف پایین فشار دهید."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"قابلیت دسترسی فعال شد."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"قابلیت دسترسی لغو شد."</string>
     <string name="user_switched" msgid="3768006783166984410">"کاربر کنونی <xliff:g id="NAME">%1$s</xliff:g>."</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index ae2a4cb..ef2f047 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -1418,8 +1418,7 @@
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Piirsit lukituksenpoistokuvion väärin <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. Jos piirrät kuvion väärin vielä <xliff:g id="NUMBER_1">%d</xliff:g> kertaa, sinua pyydetään poistamaan tablet-laitteesi lukitus sähköpostitilin avulla."\n\n" Yritä uudelleen <xliff:g id="NUMBER_2">%d</xliff:g> sekunnin kuluttua."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Piirsit lukituksenpoistokuvion väärin <xliff:g id="NUMBER_0">%d</xliff:g> kertaa. Jos piirrät kuvion väärin vielä <xliff:g id="NUMBER_1">%d</xliff:g> kertaa, sinua pyydetään poistamaan puhelimesi lukitus sähköpostitilin avulla."\n\n" Yritä uudelleen <xliff:g id="NUMBER_2">%d</xliff:g> sekunnin kuluttua."</string>
     <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Nostetaanko äänenvoimakkuus turvallista tasoa voimakkaammaksi?"\n"Jos kuuntelet suurella äänenvoimakkuudella pitkiä aikoja, kuulosi voi vahingoittua."</string>
-    <!-- no translation found for continue_to_enable_accessibility (1626427372316070258) -->
-    <skip />
+    <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Ota esteettömyystila käyttöön koskettamalla pitkään kahdella sormella."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Esteettömyystila käytössä."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Esteettömyystila peruutettu."</string>
     <string name="user_switched" msgid="3768006783166984410">"Nykyinen käyttäjä: <xliff:g id="NAME">%1$s</xliff:g>."</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index aa4f91e..cefc2b8 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1418,8 +1418,7 @@
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%d</xliff:g> fois, vous devrez déverrouiller votre tablette à l\'aide d\'un compte de messagerie électronique."\n\n" Veuillez réessayer dans <xliff:g id="NUMBER_2">%d</xliff:g> secondes."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%d</xliff:g> fois, vous devrez déverrouiller votre téléphone à l\'aide d\'un compte de messagerie électronique."\n\n" Veuillez réessayer dans <xliff:g id="NUMBER_2">%d</xliff:g> secondes."</string>
     <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Augmenter le volume au-dessus du niveau de sécurité ?"\n"L\'écoute à un volume élevé pendant des périodes prolongées peut endommager votre audition."</string>
-    <!-- no translation found for continue_to_enable_accessibility (1626427372316070258) -->
-    <skip />
+    <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Pour activer l\'accessibilité, appuyez de manière prolongée avec deux doigts."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"L\'accessibilité a bien été activée."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Accessibilité annulée."</string>
     <string name="user_switched" msgid="3768006783166984410">"Utilisateur actuel : <xliff:g id="NAME">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index d0f1dc5..6bf3d09 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1262,7 +1262,7 @@
     <string name="media_shared" product="nosdcard" msgid="5830814349250834225">"USB संग्रहण का उपयोग वर्तमान में एक कंप्‍यूटर द्वारा किया जा रहा है."</string>
     <string name="media_shared" product="default" msgid="5706130568133540435">"SD कार्ड का उपयोग वर्तमान में एक कंप्‍यूटर द्वारा किया जा रहा है."</string>
     <string name="media_unknown_state" msgid="729192782197290385">"बाह्य मीडिया अज्ञात स्‍थिति में है."</string>
-    <string name="share" msgid="1778686618230011964">"शेयर करें"</string>
+    <string name="share" msgid="1778686618230011964">"साझा करें"</string>
     <string name="find" msgid="4808270900322985960">"ढूंढें"</string>
     <string name="websearch" msgid="4337157977400211589">"वेब खोज"</string>
     <string name="find_next" msgid="5742124618942193978">"अगला ढूंढें"</string>
@@ -1418,8 +1418,7 @@
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"आपने अपने अनलॉक प्रतिमान को <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से आरेखित किया है. <xliff:g id="NUMBER_1">%d</xliff:g> और असफल प्रयासों के बाद, आपसे अपने टेबलेट को किसी ईमेल खाते के उपयोग से अनलॉक करने के लिए कहा जाएगा."\n\n" <xliff:g id="NUMBER_2">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"आपने अपने अनलॉक प्रतिमान को <xliff:g id="NUMBER_0">%d</xliff:g> बार गलत तरीके से आरेखित किया है. <xliff:g id="NUMBER_1">%d</xliff:g> और असफल प्रयासों के बाद, आपसे अपने फ़ोन को किसी ईमेल खाते का उपयोग करके अनलॉक करने के लिए कहा जाएगा."\n\n" <xliff:g id="NUMBER_2">%d</xliff:g> सेकंड में पुन: प्रयास करें."</string>
     <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"वॉल्यूम को सुरक्षित स्तर से अधिक करें?"\n"अधिक देर तक उच्च वॉल्यूम पर सुनने से आपकी सुनने की क्षमता को नुकसान हो सकता है."</string>
-    <!-- no translation found for continue_to_enable_accessibility (1626427372316070258) -->
-    <skip />
+    <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"पहुंच-योग्यता को सक्षम करने के लिए दो अंगुलियों से नीचे दबाए रखें."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"पहुंच-योग्यता सक्षम कर दी है."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"पहुंच-योग्यता रद्द की गई."</string>
     <string name="user_switched" msgid="3768006783166984410">"वर्तमान उपयोगकर्ता <xliff:g id="NAME">%1$s</xliff:g>."</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index f223fa6..588960b 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -1418,8 +1418,7 @@
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Netočno ste iscrtali obrazac za otključavanje <xliff:g id="NUMBER_0">%d</xliff:g> puta. Nakon još ovoliko neuspješnih pokušaja: <xliff:g id="NUMBER_1">%d</xliff:g> morat ćete otključati tabletno računalo pomoću računa e-pošte."\n\n" Pokušajte ponovo za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Netočno ste iscrtali obrazac za otključavanje <xliff:g id="NUMBER_0">%d</xliff:g> puta. Nakon još ovoliko neuspješnih pokušaja: <xliff:g id="NUMBER_1">%d</xliff:g> morat ćete otključati telefon pomoću računa e-pošte."\n\n" Pokušajte ponovo za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
     <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Pojačati iznad sigurne razine?"\n"Dulje slušanje preglasne glazbe može vam oštetiti sluh."</string>
-    <!-- no translation found for continue_to_enable_accessibility (1626427372316070258) -->
-    <skip />
+    <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Nastavite držati s dva prsta kako biste omogućili pristupačnost."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Dostupnost je omogućena."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Pristupačnost otkazana."</string>
     <string name="user_switched" msgid="3768006783166984410">"Trenutačni korisnik <xliff:g id="NAME">%1$s</xliff:g>."</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 3815c38..4645842 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1418,8 +1418,7 @@
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"<xliff:g id="NUMBER_0">%d</xliff:g> alkalommal helytelenül rajzolta le a feloldási mintát. További <xliff:g id="NUMBER_1">%d</xliff:g> sikertelen kísérlet után egy e-mail fiók használatával kell feloldania a táblagépét."\n\n" Kérjük, próbálja újra <xliff:g id="NUMBER_2">%d</xliff:g> másodperc múlva."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"<xliff:g id="NUMBER_0">%d</xliff:g> alkalommal helytelenül rajzolta le a feloldási mintát. További <xliff:g id="NUMBER_1">%d</xliff:g> sikertelen kísérlet után egy e-mail fiók használatával kell feloldania a telefonját."\n\n" Kérjük, próbálja újra <xliff:g id="NUMBER_2">%d</xliff:g> másodperc múlva."</string>
     <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"A biztonságos szint fölé emeli a hangerőt?"\n"Ha hosszú ideig hangosan hallgatja a zenét, az károsíthatja a hallását."</string>
-    <!-- no translation found for continue_to_enable_accessibility (1626427372316070258) -->
-    <skip />
+    <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Továbbra is tartsa lenyomva két ujját a hozzáférés engedélyezéséhez."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Hozzáférés engedélyezve"</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Hozzáférés megszakítva."</string>
     <string name="user_switched" msgid="3768006783166984410">"<xliff:g id="NAME">%1$s</xliff:g> az aktuális felhasználó."</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 17b4944..7b04c96 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -1418,8 +1418,7 @@
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali salah menggambar pola pembuka kunci. Setelah <xliff:g id="NUMBER_1">%d</xliff:g> lagi upaya gagal, Anda akan diminta membuka kunci tablet menggunakan akun email."\n\n"Coba lagi dalam <xliff:g id="NUMBER_2">%d</xliff:g> detik."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Anda telah <xliff:g id="NUMBER_0">%d</xliff:g> kali salah menggambar pola pembuka kunci. Setelah <xliff:g id="NUMBER_1">%d</xliff:g> lagi upaya gagal, Anda akan diminta membuka kunci ponsel menggunakan akun email."\n\n"Coba lagi dalam <xliff:g id="NUMBER_2">%d</xliff:g> detik."</string>
     <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Naikkan volume di atas tingkat aman?"\n"Mendengarkan volume tinggi dalam jangka waktu yang lama dapat merusak pendengaran Anda."</string>
-    <!-- no translation found for continue_to_enable_accessibility (1626427372316070258) -->
-    <skip />
+    <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Tahan terus dua jari untuk mengaktifkan aksesibilitas."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Aksesibilitas diaktifkan."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Aksesibilitas dibatalkan."</string>
     <string name="user_switched" msgid="3768006783166984410">"Pengguna saat ini <xliff:g id="NAME">%1$s</xliff:g>."</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index bd1ffb7..46ca017 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1418,8 +1418,7 @@
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"שרטטת את קו ביטול הנעילה באופן שגוי <xliff:g id="NUMBER_0">%d</xliff:g> פעמים. לאחר <xliff:g id="NUMBER_1">%d</xliff:g> ניסיונות כושלים נוספים, תתבקש לבטל את נעילת הטאבלט באמצעות חשבון דוא\"ל‏."\n\n"נסה שוב בעוד <xliff:g id="NUMBER_2">%d</xliff:g> שניות."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"שרטטת את קו ביטול הנעילה באופן שגוי <xliff:g id="NUMBER_0">%d</xliff:g> פעמים. לאחר <xliff:g id="NUMBER_1">%d</xliff:g> ניסיונות כושלים נוספים, תתבקש לבטל את נעילת הטלפון באמצעות חשבון דוא\"ל‏."\n\n"נסה שוב בעוד <xliff:g id="NUMBER_2">%d</xliff:g> שניות."</string>
     <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"האם להעלות את עוצמת הקול מעל לרמה הבטוחה?"\n"האזנה בעוצמת קול גבוהה למשך זמן ארוך עלולה לפגוע בשמיעה."</string>
-    <!-- no translation found for continue_to_enable_accessibility (1626427372316070258) -->
-    <skip />
+    <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"המשך לגעת בשתי אצבעות כדי להפעיל נגישות."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"נגישות הופעלה."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"נגישות בוטלה."</string>
     <string name="user_switched" msgid="3768006783166984410">"המשתמש הנוכחי <xliff:g id="NAME">%1$s</xliff:g>."</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 97a1675..d97753b 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1418,8 +1418,7 @@
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"ロック解除パターンの入力を<xliff:g id="NUMBER_0">%d</xliff:g>回間違えました。あと<xliff:g id="NUMBER_1">%d</xliff:g>回間違えると、タブレットのロック解除にメールアカウントが必要になります。"\n\n"<xliff:g id="NUMBER_2">%d</xliff:g>秒以内にもう一度お試しください。"</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"ロック解除パターンの入力を<xliff:g id="NUMBER_0">%d</xliff:g>回間違えました。あと<xliff:g id="NUMBER_1">%d</xliff:g>回間違えると、携帯端末のロック解除にメールアカウントが必要になります。"\n\n"<xliff:g id="NUMBER_2">%d</xliff:g>秒以内にもう一度お試しください。"</string>
     <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"安全レベルを超えるまで音量を上げますか?"\n"大音量で長時間聞き続けると、聴力を損なう恐れがあります。"</string>
-    <!-- no translation found for continue_to_enable_accessibility (1626427372316070258) -->
-    <skip />
+    <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"ユーザー補助機能を有効にするには2本の指で押し続けてください。"</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"ユーザー補助が有効になりました。"</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"ユーザー補助をキャンセルしました。"</string>
     <string name="user_switched" msgid="3768006783166984410">"現在のユーザーは<xliff:g id="NAME">%1$s</xliff:g>です。"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index e10fd3f..332e320 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1418,8 +1418,7 @@
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"잠금해제 패턴을 <xliff:g id="NUMBER_0">%d</xliff:g>회 잘못 그렸습니다. <xliff:g id="NUMBER_1">%d</xliff:g>회 더 실패하면 이메일 계정을 사용하여 태블릿을 잠금해제해야 합니다."\n\n" <xliff:g id="NUMBER_2">%d</xliff:g>초 후에 다시 시도해 주세요."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"잠금해제 패턴을 <xliff:g id="NUMBER_0">%d</xliff:g>회 잘못 그렸습니다. <xliff:g id="NUMBER_1">%d</xliff:g>회 더 실패하면 이메일 계정을 사용하여 휴대전화를 잠금해제해야 합니다."\n\n" <xliff:g id="NUMBER_2">%d</xliff:g>초 후에 다시 시도해 주세요."</string>
     <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"안전한 수준 이상으로 볼륨을 높이시겠습니까?"\n"높은 볼륨으로 장시간 청취하면 청력에 손상이 올 수 있습니다."</string>
-    <!-- no translation found for continue_to_enable_accessibility (1626427372316070258) -->
-    <skip />
+    <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"두 손가락으로 길게 누르면 접근성을 사용하도록 설정됩니다."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"접근성을 사용 설정했습니다."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"접근성이 취소되었습니다."</string>
     <string name="user_switched" msgid="3768006783166984410">"현재 사용자는 <xliff:g id="NAME">%1$s</xliff:g>님입니다."</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 79eefef..920865b 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -1418,8 +1418,7 @@
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Anda telah tersilap melukis corak buka kunci sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%d</xliff:g> lagi percubaan yang tidak berjaya, anda akan diminta membuka kunci tablet anda menggunakan log masuk Google anda."\n\n" Cuba lagi dalam <xliff:g id="NUMBER_2">%d</xliff:g> saat."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Anda telah tersilap lukis corak buka kunci sebanyak <xliff:g id="NUMBER_0">%d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%d</xliff:g> lagi percubaan yang tidak berjaya, anda akan diminta membuka kunci telefon anda menggunakan log masuk Google anda."\n\n" Cuba lagi dalam <xliff:g id="NUMBER_2">%d</xliff:g> saat."</string>
     <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Tingkatkan kelantangan di atas tahap selamat?"\n"Mendengar pada kelantangan tinggi untuk tempoh yang panjang boleh merosakkan pendengaran anda."</string>
-    <!-- no translation found for continue_to_enable_accessibility (1626427372316070258) -->
-    <skip />
+    <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Teruskan menahan dengan dua jari untuk mendayakan kebolehcapaian."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Kebolehcapaian didayakan."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Kebolehcapaian dibatalkan."</string>
     <string name="user_switched" msgid="3768006783166984410">"Pengguna semasa <xliff:g id="NAME">%1$s</xliff:g>."</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 7381794b..6fa3c51 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1419,8 +1419,7 @@
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> nieprawidłowo narysowałeś wzór odblokowania. Po kolejnych <xliff:g id="NUMBER_1">%d</xliff:g> nieudanych próbach konieczne będzie odblokowanie tabletu przy użyciu danych logowania na konto Google."\n\n" Spróbuj ponownie za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Po raz <xliff:g id="NUMBER_0">%d</xliff:g> nieprawidłowo narysowałeś wzór odblokowania. Po kolejnych <xliff:g id="NUMBER_1">%d</xliff:g> nieudanych próbach konieczne będzie odblokowanie telefonu przy użyciu danych logowania na konto Google."\n\n" Spróbuj ponownie za <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
     <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Chcesz ustawić głośność powyżej bezpiecznego poziomu?"\n"Słuchanie przy dużym poziomie głośności przez dłuższy czas może doprowadzić do uszkodzenia słuchu."</string>
-    <!-- no translation found for continue_to_enable_accessibility (1626427372316070258) -->
-    <skip />
+    <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Aby włączyć ułatwienia dostępu, przytrzymaj dwa palce."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Włączono ułatwienia dostępu."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Ułatwienia dostępu zostały anulowane."</string>
     <string name="user_switched" msgid="3768006783166984410">"Bieżący użytkownik: <xliff:g id="NAME">%1$s</xliff:g>."</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 55f727a2..36f2ded 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1418,8 +1418,7 @@
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas incorretas, será solicitado que você use o login do Google para desbloquear seu tablet."\n\n" Tente novamente em <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%d</xliff:g> tentativas incorretas, será solicitado que você use o login do Google para desbloquear."\n\n" Tente novamente em <xliff:g id="NUMBER_2">%d</xliff:g> segundos."</string>
     <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Aumentar o volume acima do nível seguro?"\n"A audição em volume elevado por períodos longos pode prejudicar sua audição."</string>
-    <!-- no translation found for continue_to_enable_accessibility (1626427372316070258) -->
-    <skip />
+    <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Mantenha pressionado com dois dedos para ativar a acessibilidade."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Acessibilidade ativada."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Acessibilidade cancelada."</string>
     <string name="user_switched" msgid="3768006783166984410">"Usuário atual <xliff:g id="NAME">%1$s</xliff:g>."</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 81aaaa0..263e56b 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -1418,8 +1418,7 @@
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%d</xliff:g> încercări nereuşite, vi se va solicita să deblocaţi tableta cu ajutorul unui cont de e-mail."\n\n" Încercaţi din nou peste <xliff:g id="NUMBER_2">%d</xliff:g> (de) secunde."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Aţi desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%d</xliff:g> încercări nereuşite, vi se va solicita să deblocaţi telefonul cu ajutorul unui cont de e-mail."\n\n" Încercaţi din nou peste <xliff:g id="NUMBER_2">%d</xliff:g> (de) secunde."</string>
     <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Ridicaţi volumul mai sus de nivelul sigur?"\n"Ascultarea la volum ridicat pe perioade lungi de timp vă poate afecta auzul."</string>
-    <!-- no translation found for continue_to_enable_accessibility (1626427372316070258) -->
-    <skip />
+    <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Menţineţi două degete pe ecran pentru a activa accesibilitatea."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"S-a activat accesibilitatea."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Accesibilitatea a fost anulată"</string>
     <string name="user_switched" msgid="3768006783166984410">"Utilizator curent: <xliff:g id="NAME">%1$s</xliff:g>."</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 0b3d009..f008479 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1418,8 +1418,7 @@
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Вы <xliff:g id="NUMBER_0">%d</xliff:g> раз неверно указали графический ключ. После <xliff:g id="NUMBER_1">%d</xliff:g> неверных попыток для разблокировки планшетного ПК потребуется войти в аккаунт Google."\n\n"Повтор через <xliff:g id="NUMBER_2">%d</xliff:g> сек."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Вы <xliff:g id="NUMBER_0">%d</xliff:g> раз неверно указали графический ключ. После <xliff:g id="NUMBER_1">%d</xliff:g> неверных попыток для разблокировки телефона потребуется войти в аккаунт Google."\n\n"Повтор через <xliff:g id="NUMBER_2">%d</xliff:g> сек."</string>
     <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Увеличить громкость до небезопасного уровня?"\n"Долговременное прослушивание на такой громкости может повредить слух."</string>
-    <!-- no translation found for continue_to_enable_accessibility (1626427372316070258) -->
-    <skip />
+    <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Чтобы включить специальные возможности, удерживайте пальцы на экране."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Специальные возможности включены."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Специальные возможности не будут включены."</string>
     <string name="user_switched" msgid="3768006783166984410">"Выбран аккаунт пользователя <xliff:g id="NAME">%1$s</xliff:g>."</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index e6a3b38..9be07a9 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1418,8 +1418,7 @@
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"<xliff:g id="NUMBER_0">%d</xliff:g>-krát ste nesprávne nakreslili svoj bezpečnostný vzor. Po ďalších <xliff:g id="NUMBER_1">%d</xliff:g> neúspešných pokusoch sa zobrazí výzva na odomknutie tabletu pomocou e-mailového účtu."\n\n" Skúste to znova o <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"<xliff:g id="NUMBER_0">%d</xliff:g>-krát ste nesprávne nakreslili svoj bezpečnostný vzor. Po <xliff:g id="NUMBER_1">%d</xliff:g> ďalších neúspešných pokusoch sa zobrazí výzva na odomknutie telefónu pomocou e-mailového účtu."\n\n" Skúste to znova o <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
     <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Chcete zvýšiť hlasitosť nad bezpečnú úroveň?"\n"Dlhodobé počúvanie pri vysokej hlasitosti môže viesť k poškodeniu vášho sluchu."</string>
-    <!-- no translation found for continue_to_enable_accessibility (1626427372316070258) -->
-    <skip />
+    <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Zjednodušenie ovládania povolíte dlhým stlačením dvoma prstami."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Zjednodušenie ovládania je povolené."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Zjednodušenie ovládania bolo zrušené."</string>
     <string name="user_switched" msgid="3768006783166984410">"Aktuálny používateľ je <xliff:g id="NAME">%1$s</xliff:g>."</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index cdd8d112..42cf0af 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -1418,8 +1418,7 @@
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Vzorec za odklepanje ste <xliff:g id="NUMBER_0">%d</xliff:g>-krat napačno vnesli. Po nadaljnjih <xliff:g id="NUMBER_1">%d</xliff:g> neuspešnih poskusih boste pozvani, da tablični računalnik odklenete z e-poštnim računom."\n\n"Poskusite znova čez <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Vzorec za odklepanje ste <xliff:g id="NUMBER_0">%d</xliff:g>-krat napačno vnesli. Po nadaljnjih <xliff:g id="NUMBER_1">%d</xliff:g> neuspešnih poskusih boste pozvani, da odklenete telefon z Googlovimi podatki za prijavo."\n\n"Poskusite znova čez <xliff:g id="NUMBER_2">%d</xliff:g> s."</string>
     <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Želite povečati glasnost nad varno raven?"\n"Dolgotrajna izpostavljenost glasnim tonom lahko poškoduje sluh."</string>
-    <!-- no translation found for continue_to_enable_accessibility (1626427372316070258) -->
-    <skip />
+    <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Če želite omogočiti pripomočke za ljudi s posebnimi potrebami, na zaslonu pridržite z dvema prstoma."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Pripomočki za ljudi s posebnimi potrebami so omogočeni."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Omogočanje pripomočkov za ljudi s posebnimi potrebami preklicano."</string>
     <string name="user_switched" msgid="3768006783166984410">"Trenutni uporabnik <xliff:g id="NAME">%1$s</xliff:g>."</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index bfeb021..e69bd5d 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -1418,8 +1418,7 @@
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Нацртали сте шаблон за откључавање неисправно <xliff:g id="NUMBER_0">%d</xliff:g> пута. После још <xliff:g id="NUMBER_1">%d</xliff:g> неуспешна(их) покушаја, од вас ће бити затражено да откључате таблет помоћу налога е-поште."\n\n"Покушајте поново за <xliff:g id="NUMBER_2">%d</xliff:g> секунде(и)."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Нацртали сте шаблон за откључавање неисправно <xliff:g id="NUMBER_0">%d</xliff:g> пута. После још <xliff:g id="NUMBER_1">%d</xliff:g> неуспешна(их) покушаја, од вас ће бити затражено да откључате телефон помоћу налога е-поште."\n\n"Покушајте поново за <xliff:g id="NUMBER_2">%d</xliff:g> секунде(и)."</string>
     <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Желите да појачате звук изнад безбедног нивоа?"\n"Ако дуже време слушате гласну музику, може доћи до оштећења слуха."</string>
-    <!-- no translation found for continue_to_enable_accessibility (1626427372316070258) -->
-    <skip />
+    <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Држите са два прста да бисте омогућили приступачност."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Приступачност је омогућена."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Приступачност је отказана."</string>
     <string name="user_switched" msgid="3768006783166984410">"Актуелни корисник <xliff:g id="NAME">%1$s</xliff:g>."</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 428e3d6..e295e2d 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -1418,8 +1418,7 @@
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%d</xliff:g> försök ombeds du låsa upp surfplattan med ett e-postkonto."\n\n" Försök igen om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%d</xliff:g> försök ombeds du låsa upp mobilen med hjälp av ett e-postkonto."\n\n" Försök igen om <xliff:g id="NUMBER_2">%d</xliff:g> sekunder."</string>
     <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Vill du höja volymen över den säkra nivån?"\n"Om du lyssnar på hög volym under långa perioder kan din hörsel skadas."</string>
-    <!-- no translation found for continue_to_enable_accessibility (1626427372316070258) -->
-    <skip />
+    <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Fortsätt trycka med två fingrar om du vill aktivera tillgänglighetsläget."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Tillgänglighetsläget har aktiverats."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Byte till tillgänglighetsläge avbrutet."</string>
     <string name="user_switched" msgid="3768006783166984410">"Nuvarande användare: <xliff:g id="NAME">%1$s</xliff:g>."</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index a619a36..3dc4bff 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1418,8 +1418,7 @@
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"คุณวาดรูปแบบการปลดล็อกไม่ถูกต้อง <xliff:g id="NUMBER_0">%d</xliff:g> ครั้งแล้ว หากทำไม่สำเร็จอีก <xliff:g id="NUMBER_1">%d</xliff:g> ครั้ง ระบบจะขอให้คุณปลดล็อกแท็บเล็ตโดยใช้บัญชีอีเมล"\n\n" โปรดลองอีกครั้งใน <xliff:g id="NUMBER_2">%d</xliff:g> วินาที"</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"คุณวาดรูปแบบการปลดล็อกไม่ถูกต้อง <xliff:g id="NUMBER_0">%d</xliff:g> ครั้งแล้ว หากทำไม่สำเร็จอีก <xliff:g id="NUMBER_1">%d</xliff:g> ครั้ง ระบบจะขอให้คุณปลดล็อกโทรศัพท์โดยใช้ับัญชีอีเมล"\n\n" โปรดลองอีกครั้งในอีก <xliff:g id="NUMBER_2">%d</xliff:g> วินาที"</string>
     <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"เพิ่มระดับเสียงจนเกินระดับที่ปลอดภัยหรือไม่"\n"การฟังเสียงดังเป็นเวลานานอาจทำให้การได้ยินของคุณบกพร่องได้"</string>
-    <!-- no translation found for continue_to_enable_accessibility (1626427372316070258) -->
-    <skip />
+    <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"ใช้สองนิ้วแตะค้างไว้เพื่อเปิดใช้งานการเข้าถึง"</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"เปิดใช้งานการเข้าถึงแล้ว"</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"ยกเลิกการเข้าถึงแล้ว"</string>
     <string name="user_switched" msgid="3768006783166984410">"ผู้ใช้ปัจจุบัน <xliff:g id="NAME">%1$s</xliff:g>"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index cfe58c7..201d77b 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1418,8 +1418,7 @@
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Naguhit mo nang hindi tama ang iyong pattern sa pag-unlock nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. Pagkatapos ng <xliff:g id="NUMBER_1">%d</xliff:g> pang hindi matagumpay na pagtatangka, hihilingin sa iyong i-unlock ang tablet mo gamit ang isang email account."\n\n" Subukang muli sa loob ng <xliff:g id="NUMBER_2">%d</xliff:g> (na) segundo."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Naguhit mo nang hindi tama ang iyong pattern sa pag-unlock nang <xliff:g id="NUMBER_0">%d</xliff:g> (na) beses. Pagkatapos ng <xliff:g id="NUMBER_1">%d</xliff:g> pang hindi matagumpay na pagtatangka, hihilingin sa iyong i-unlock ang telepono mo gamit ang isang email account."\n\n" Subukang muli sa loob ng <xliff:g id="NUMBER_2">%d</xliff:g> (na) segundo."</string>
     <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Lakasan ang volume nang lagpas sa ligtas na antas?"\n"Maaaring mapinsala ng pakikinig sa malakas na volume sa loob ng mahahabang panahon ang iyong pandinig."</string>
-    <!-- no translation found for continue_to_enable_accessibility (1626427372316070258) -->
-    <skip />
+    <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Panatilihing nakapindot nang matagal ang iyong dalawang daliri upang paganahin ang pagiging naa-access."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Pinagana ang accessibility."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Nakansela ang pagiging naa-access."</string>
     <string name="user_switched" msgid="3768006783166984410">"Kasalukuyang user <xliff:g id="NAME">%1$s</xliff:g>."</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 2c9407b..fd59e41 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1418,8 +1418,7 @@
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış çizdiniz. <xliff:g id="NUMBER_1">%d</xliff:g> başarısız denemeden sonra, tabletinizi bir e-posta hesabı kullanarak açmanız istenir."\n\n" <xliff:g id="NUMBER_2">%d</xliff:g> saniye içinde tekrar deneyin."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%d</xliff:g> kez yanlış çizdiniz. <xliff:g id="NUMBER_1">%d</xliff:g> başarısız denemeden sonra telefonunuzu bir e-posta hesabı kullanarak açmanız istenir."\n\n" <xliff:g id="NUMBER_2">%d</xliff:g> saniye içinde tekrar deneyin."</string>
     <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Ses düzeyi güvenli seviyenin üzerine çıkarılsın mı?"\n"Yüksek sesle uzun süre dinlemek işitme yetinize zarar verebilir."</string>
-    <!-- no translation found for continue_to_enable_accessibility (1626427372316070258) -->
-    <skip />
+    <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Erişilebilirliği etkinleştirmek için iki parmağınızı basılı tutmaya devam edin."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Erişilebilirlik etkinleştirildi."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Erişilebilirlik iptal edildi."</string>
     <string name="user_switched" msgid="3768006783166984410">"Geçerli kullanıcı: <xliff:g id="NAME">%1$s</xliff:g>."</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 3072cb9..5547f56 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -1418,8 +1418,7 @@
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Ключ розблокування неправильно намальовано стільки разів: <xliff:g id="NUMBER_0">%d</xliff:g>. У вас є ще стільки спроб: <xliff:g id="NUMBER_1">%d</xliff:g>. У разі невдачі з’явиться запит розблокувати планшетний ПК за допомогою облікового запису електронної пошти."\n\n" Повторіть спробу через <xliff:g id="NUMBER_2">%d</xliff:g> сек."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Ключ розблокування неправильно намальовано стільки разів: <xliff:g id="NUMBER_0">%d</xliff:g>. У вас є ще стільки спроб: <xliff:g id="NUMBER_1">%d</xliff:g>. У разі невдачі з’явиться запит розблокувати телефон за допомогою облікового запису електронної пошти."\n\n" Повторіть спробу через <xliff:g id="NUMBER_2">%d</xliff:g> сек."</string>
     <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Збільшити гучність понад безпечний рівень?"\n"Надто гучне прослуховування впродовж тривалого періоду може пошкодити слух."</string>
-    <!-- no translation found for continue_to_enable_accessibility (1626427372316070258) -->
-    <skip />
+    <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Утримуйте двома пальцями, щоб увімкнути доступність."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Доступність увімкнено."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Доступність скасовано."</string>
     <string name="user_switched" msgid="3768006783166984410">"Поточний користувач: <xliff:g id="NAME">%1$s</xliff:g>."</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 3dbe71b..df5d184 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1418,8 +1418,7 @@
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần vẽ không chính xác hình mở khóa của mình. Sau <xliff:g id="NUMBER_1">%d</xliff:g> lần thử không thành công nữa, bạn sẽ được yêu cầu mở khóa máy tính bảng bằng tài khoản email."\n\n" Vui lòng thử lại sau <xliff:g id="NUMBER_2">%d</xliff:g> giây."</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"Bạn đã <xliff:g id="NUMBER_0">%d</xliff:g> lần vẽ không chính xác hình mở khóa của mình. Sau <xliff:g id="NUMBER_1">%d</xliff:g> lần thử không thành công nữa, bạn sẽ được yêu cầu mở khóa điện thoại bằng tài khoản email."\n\n" Vui lòng thử lại sau <xliff:g id="NUMBER_2">%d</xliff:g> giây."</string>
     <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"Tăng âm lượng trên mức an toàn?"\n"Nghe ở âm lượng cao trong thời gian dài có thể gây hại cho thính giác của bạn."</string>
-    <!-- no translation found for continue_to_enable_accessibility (1626427372316070258) -->
-    <skip />
+    <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"Tiếp tục giữ hai ngón tay để bật trợ năng."</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"Trợ năng đã được bật."</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"Đã hủy trợ năng."</string>
     <string name="user_switched" msgid="3768006783166984410">"Người dùng hiện tại <xliff:g id="NAME">%1$s</xliff:g>."</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index ea55480..d4c8ac0 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -777,7 +777,7 @@
     <string name="lockscreen_transport_pause_description" msgid="7659088786780128001">"“暂停”按钮"</string>
     <string name="lockscreen_transport_play_description" msgid="5888422938351019426">"“播放”按钮"</string>
     <string name="lockscreen_transport_stop_description" msgid="4562318378766987601">"“停止”按钮"</string>
-    <string name="emergency_calls_only" msgid="6733978304386365407">"只能使用紧急呼救"</string>
+    <string name="emergency_calls_only" msgid="6733978304386365407">"只能拨打紧急呼救电话"</string>
     <string name="lockscreen_network_locked_message" msgid="143389224986028501">"网络已锁定"</string>
     <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"SIM 卡已用 PUK 码锁定"</string>
     <string name="lockscreen_sim_puk_locked_instructions" msgid="8127916255245181063">"请参阅《用户指南》或与客服人员联系。"</string>
@@ -1418,8 +1418,7 @@
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"您已经 <xliff:g id="NUMBER_0">%d</xliff:g> 次错误地绘制了解锁图案。如果再尝试 <xliff:g id="NUMBER_1">%d</xliff:g> 次后仍不成功,系统就会要求您使用自己的电子邮件帐户解锁平板电脑。"\n\n"请在 <xliff:g id="NUMBER_2">%d</xliff:g> 秒后重试。"</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"您已经 <xliff:g id="NUMBER_0">%d</xliff:g> 次错误地绘制了解锁图案。如果再尝试 <xliff:g id="NUMBER_1">%d</xliff:g> 次后仍不成功,系统就会要求您使用自己的电子邮件帐户解锁手机。"\n\n"请在 <xliff:g id="NUMBER_2">%d</xliff:g> 秒后重试。"</string>
     <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"将音量调高到安全级别以上?"\n"长时间聆听高音量可能会损伤听力。"</string>
-    <!-- no translation found for continue_to_enable_accessibility (1626427372316070258) -->
-    <skip />
+    <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"持续按住双指即可启用辅助功能。"</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"辅助功能已启用。"</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"已取消辅助功能。"</string>
     <string name="user_switched" msgid="3768006783166984410">"当前用户是<xliff:g id="NAME">%1$s</xliff:g>。"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 3301945..12c7f41 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1418,8 +1418,7 @@
     <string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="3253575572118914370">"您的解鎖圖形已畫錯 <xliff:g id="NUMBER_0">%d</xliff:g> 次,如果再嘗試 <xliff:g id="NUMBER_1">%d</xliff:g> 次仍未成功,系統就會要求您透過電子郵件帳戶解除平板電腦的鎖定狀態。"\n\n"請在 <xliff:g id="NUMBER_2">%d</xliff:g> 秒後再試一次。"</string>
     <string name="kg_failed_attempts_almost_at_login" product="default" msgid="1437638152015574839">"您的解鎖圖形已畫錯 <xliff:g id="NUMBER_0">%d</xliff:g> 次,如果再嘗試 <xliff:g id="NUMBER_1">%d</xliff:g> 次仍未成功,系統就會要求您透過電子郵件帳戶解除手機的鎖定狀態。"\n\n"請在 <xliff:g id="NUMBER_2">%d</xliff:g> 秒後再試一次。"</string>
     <string name="safe_media_volume_warning" product="default" msgid="7382971871993371648">"要將音量調高到安全等級以上嗎?"\n"長時間聆聽偏高音量可能會損害您的聽力。"</string>
-    <!-- no translation found for continue_to_enable_accessibility (1626427372316070258) -->
-    <skip />
+    <string name="continue_to_enable_accessibility" msgid="1626427372316070258">"持續用兩指按住即可啟用協助工具。"</string>
     <string name="accessibility_enabled" msgid="1381972048564547685">"協助工具已啟用。"</string>
     <string name="enable_accessibility_canceled" msgid="3833923257966635673">"協助工具已取消。"</string>
     <string name="user_switched" msgid="3768006783166984410">"目前的使用者是 <xliff:g id="NAME">%1$s</xliff:g>。"</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 4698002..0890a18 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -636,19 +636,12 @@
          of new location providers at run-time. The new package does not
          have to be explicitly listed here, however it must have a signature
          that matches the signature of at least one package on this list.
-         Platforms should overlay additional packages in
-         config_overlay_locationProviderPackageNames, instead of overlaying
-         this config, if they only want to append packages and not replace
-         the entire array.
          -->
     <string-array name="config_locationProviderPackageNames" translatable="false">
+        <!-- The standard AOSP fused location provider -->
         <item>com.android.location.fused</item>
     </string-array>
 
-    <!-- Pacakge name(s) supplied by overlay, and appended to
-         config_locationProviderPackageNames. -->
-    <string-array name="config_overlay_locationProviderPackageNames" translatable="false" />
-
     <!-- Boolean indicating if current platform supports bluetooth SCO for off call
     use cases -->
     <bool name="config_bluetooth_sco_off_call">true</bool>
@@ -902,8 +895,16 @@
     <!-- Name of the wimax state tracker clas -->
     <string name="config_wimaxStateTrackerClassname" translatable="false"></string>
 
-    <!-- enable screen saver feature -->
-    <bool name="config_enableDreams">true</bool>
+    <!-- Is the dreams feature supported? -->
+    <bool name="config_dreamsSupported">true</bool>
+    <!-- If supported, are dreams enabled? (by default) -->
+    <bool name="config_dreamsEnabledByDefault">true</bool>
+    <!-- If supported and enabled, are dreams activated when docked? (by default) -->
+    <bool name="config_dreamsActivatedOnDockByDefault">true</bool>
+    <!-- If supported and enabled, are dreams activated when asleep and charging? (by default) -->
+    <bool name="config_dreamsActivatedOnSleepByDefault">false</bool>
+    <!-- ComponentName of the default dream (Settings.Secure.SCREENSAVER_COMPONENT) -->
+    <string name="config_dreamsDefaultComponent">com.google.android.deskclock/com.android.deskclock.Screensaver</string>
 
     <!-- Base "touch slop" value used by ViewConfiguration as a
          movement threshold where scrolling should begin. -->
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 72de22c..f8dbd84 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3821,6 +3821,13 @@
     <!-- Title text to show within the overlay.  [CHAR LIMIT=50] -->
     <string name="display_manager_overlay_display_title"><xliff:g id="name">%1$s</xliff:g>: <xliff:g id="width">%2$d</xliff:g>x<xliff:g id="height">%3$d</xliff:g>, <xliff:g id="dpi">%4$d</xliff:g> dpi</string>
 
+    <!-- Title of the notification to indicate an active wifi display connection.  [CHAR LIMIT=50] -->
+    <string name="wifi_display_notification_title">Wireless display is connected</string>
+    <!-- Message of the notification to indicate an active wifi display connection.  [CHAR LIMIT=80] -->
+    <string name="wifi_display_notification_message">This screen is showing on another device</string>
+    <!-- Label of a button to disconnect an active wifi display connection.  [CHAR LIMIT=25] -->
+    <string name="wifi_display_notification_disconnect">Disconnect</string>
+
     <!-- Keyguard strings -->
     <!-- Label shown on emergency call button in keyguard -->
     <string name="kg_emergency_call_label">Emergency call</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 9837425..d1b5f3a 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1475,7 +1475,6 @@
   <java-symbol type="array" name="radioAttributes" />
   <java-symbol type="array" name="config_oemUsbModeOverride" />
   <java-symbol type="array" name="config_locationProviderPackageNames" />
-  <java-symbol type="array" name="config_overlay_locationProviderPackageNames" />
   <java-symbol type="bool" name="config_animateScreenLights" />
   <java-symbol type="bool" name="config_automatic_brightness_available" />
   <java-symbol type="bool" name="config_sf_limitedAlpha" />
@@ -1486,6 +1485,7 @@
   <java-symbol type="bool" name="show_ongoing_ime_switcher" />
   <java-symbol type="color" name="config_defaultNotificationColor" />
   <java-symbol type="drawable" name="ic_notification_ime_default" />
+  <java-symbol type="drawable" name="ic_notify_wifidisplay" />
   <java-symbol type="drawable" name="stat_notify_car_mode" />
   <java-symbol type="drawable" name="stat_notify_disabled" />
   <java-symbol type="drawable" name="stat_notify_disk_full" />
@@ -1621,10 +1621,17 @@
   <java-symbol type="string" name="vpn_lockdown_error" />
   <java-symbol type="string" name="vpn_lockdown_reset" />
   <java-symbol type="string" name="wallpaper_binding_label" />
+  <java-symbol type="string" name="wifi_display_notification_title" />
+  <java-symbol type="string" name="wifi_display_notification_message" />
+  <java-symbol type="string" name="wifi_display_notification_disconnect" />
   <java-symbol type="style" name="Theme.Dialog.AppError" />
   <java-symbol type="style" name="Theme.Toast" />
   <java-symbol type="xml" name="storage_list" />
-  <java-symbol type="bool" name="config_enableDreams" />
+  <java-symbol type="bool" name="config_dreamsSupported" />
+  <java-symbol type="bool" name="config_dreamsEnabledByDefault" />
+  <java-symbol type="bool" name="config_dreamsActivatedOnDockByDefault" />
+  <java-symbol type="bool" name="config_dreamsActivatedOnSleepByDefault" />
+  <java-symbol type="string" name="config_dreamsDefaultComponent" />
   <java-symbol type="string" name="enable_explore_by_touch_warning_title" />
   <java-symbol type="string" name="enable_explore_by_touch_warning_message" />
 
diff --git a/core/tests/ConnectivityManagerTest/AndroidManifest.xml b/core/tests/ConnectivityManagerTest/AndroidManifest.xml
index 05f8b39..1bbc7df 100644
--- a/core/tests/ConnectivityManagerTest/AndroidManifest.xml
+++ b/core/tests/ConnectivityManagerTest/AndroidManifest.xml
@@ -72,5 +72,6 @@
     <uses-permission android:name="android.permission.WAKE_LOCK" />
     <uses-permission android:name="android.permission.DEVICE_POWER" />
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
-
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
 </manifest>
diff --git a/core/tests/coretests/src/android/content/SyncOperationTest.java b/core/tests/coretests/src/android/content/SyncOperationTest.java
index 910c721..1fd25d2 100644
--- a/core/tests/coretests/src/android/content/SyncOperationTest.java
+++ b/core/tests/coretests/src/android/content/SyncOperationTest.java
@@ -43,6 +43,7 @@
 
         SyncOperation op1 = new SyncOperation(account1, 0,
                 1,
+                SyncOperation.REASON_PERIODIC,
                 "authority1",
                 b1,
                 100,
@@ -53,6 +54,7 @@
         // Same as op1 but different time infos
         SyncOperation op2 = new SyncOperation(account1, 0,
                 1,
+                SyncOperation.REASON_PERIODIC,
                 "authority1",
                 b1,
                 200,
@@ -63,6 +65,7 @@
         // Same as op1 but different authority
         SyncOperation op3 = new SyncOperation(account1, 0,
                 1,
+                SyncOperation.REASON_PERIODIC,
                 "authority2",
                 b1,
                 100,
@@ -73,6 +76,7 @@
         // Same as op1 but different account
         SyncOperation op4 = new SyncOperation(account2, 0,
                 1,
+                SyncOperation.REASON_PERIODIC,
                 "authority1",
                 b1,
                 100,
@@ -83,6 +87,7 @@
         // Same as op1 but different bundle
         SyncOperation op5 = new SyncOperation(account1, 0,
                 1,
+                SyncOperation.REASON_PERIODIC,
                 "authority1",
                 b2,
                 100,
diff --git a/core/tests/coretests/src/android/content/SyncStorageEngineTest.java b/core/tests/coretests/src/android/content/SyncStorageEngineTest.java
index 2add623..58d2327 100644
--- a/core/tests/coretests/src/android/content/SyncStorageEngineTest.java
+++ b/core/tests/coretests/src/android/content/SyncStorageEngineTest.java
@@ -16,8 +16,6 @@
 
 package android.content;
 
-import com.android.internal.os.AtomicFile;
-
 import android.accounts.Account;
 import android.os.Bundle;
 import android.test.AndroidTestCase;
@@ -28,6 +26,8 @@
 import android.test.suitebuilder.annotation.MediumTest;
 import android.test.suitebuilder.annotation.SmallTest;
 
+import com.android.internal.os.AtomicFile;
+
 import java.io.File;
 import java.io.FileOutputStream;
 import java.util.List;
@@ -56,8 +56,8 @@
 
         long time0 = 1000;
         long historyId = engine.insertStartSyncEvent(
-                account, 0, authority, time0, SyncStorageEngine.SOURCE_LOCAL,
-                false /* initialization */);
+                account, 0, SyncOperation.REASON_PERIODIC, authority, time0,
+                SyncStorageEngine.SOURCE_LOCAL, false /* initialization */, null /* extras */);
         long time1 = time0 + SyncStorageEngine.MILLIS_IN_4WEEKS * 2;
         engine.stopSyncEvent(historyId, time1 - time0, "yay", 0, 0);
     }
diff --git a/data/fonts/DroidNaskh-Bold.ttf b/data/fonts/DroidNaskh-Bold.ttf
index 692b796..14d8768 100644
--- a/data/fonts/DroidNaskh-Bold.ttf
+++ b/data/fonts/DroidNaskh-Bold.ttf
Binary files differ
diff --git a/data/fonts/DroidNaskh-Regular.ttf b/data/fonts/DroidNaskh-Regular.ttf
index da9a45f..03662f2 100644
--- a/data/fonts/DroidNaskh-Regular.ttf
+++ b/data/fonts/DroidNaskh-Regular.ttf
Binary files differ
diff --git a/docs/html/guide/topics/ui/dialogs.jd b/docs/html/guide/topics/ui/dialogs.jd
index 62c054a..3cfed13 100644
--- a/docs/html/guide/topics/ui/dialogs.jd
+++ b/docs/html/guide/topics/ui/dialogs.jd
@@ -119,7 +119,7 @@
 a {@link android.support.v4.app.DialogFragment}:</p>
 
 <pre>
-public class FireMissilesDialog extends DialogFragment {
+public class FireMissilesDialogFragment extends DialogFragment {
     &#64;Override
     public Dialog onCreateDialog(Bundle savedInstanceState) {
         // Use the Builder class for convenient dialog construction
@@ -469,7 +469,7 @@
            })
            .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int id) {
-                   NoticeDialog.this.getDialog().cancel();
+                   LoginDialogFragment.this.getDialog().cancel();
                }
            });      
     return builder.create();
@@ -497,15 +497,15 @@
 <p>When the user touches one of the dialog's action buttons or selects an item from its list,
 your {@link android.support.v4.app.DialogFragment} might perform the necessary
 action itself, but often you'll want to deliver the event to the activity or fragment that
-opened the dialog. To do this, define an interface with a method for each type of click event,
-then implement that interface in the host component that will
+opened the dialog. To do this, define an interface with a method for each type of click event.
+Then implement that interface in the host component that will
 receive the action events from the dialog.</p>
 
 <p>For example, here's a {@link android.support.v4.app.DialogFragment} that defines an
 interface through which it delivers the events back to the host activity:</p>
 
 <pre>
-public class NoticeDialog extends DialogFragment {
+public class NoticeDialogFragment extends DialogFragment {
     
     /* The activity that creates an instance of this dialog fragment must
      * implement this interface in order to receive event callbacks.
@@ -516,48 +516,44 @@
     }
     
     // Use this instance of the interface to deliver action events
-    static NoticeDialogListener mListener;
-        
-    /* Call this to instantiate a new NoticeDialog.
-     * @param activity  The activity hosting the dialog, which must implement the
-     *                  NoticeDialogListener to receive event callbacks.
-     * @returns A new instance of NoticeDialog.
-     * @throws  ClassCastException if the host activity does not
-     *          implement NoticeDialogListener
-     */
-    public static NoticeDialog newInstance(Activity activity) {
+    NoticeDialogListener mListener;
+    
+    // Override the Fragment.onAttach() method to instantiate the NoticeDialogListener
+    &#64;Override
+    public void onAttach(Activity activity) {
+        super.onAttach(activity);
         // Verify that the host activity implements the callback interface
         try {
-            // Instantiate the NoticeDialogListener so we can send events with it
+            // Instantiate the NoticeDialogListener so we can send events to the host
             mListener = (NoticeDialogListener) activity;
         } catch (ClassCastException e) {
             // The activity doesn't implement the interface, throw exception
             throw new ClassCastException(activity.toString()
                     + " must implement NoticeDialogListener");
         }
-        NoticeDialog frag = new NoticeDialog();
-        return frag;
     }
-    
     ...
 }
 </pre>
 
-<p>The activity hosting the dialog creates and shows an instance of the dialog
-by calling {@code NoticeDialog.newInstance()} and receives the dialog's
+<p>The activity hosting the dialog creates an instance of the dialog
+with the dialog fragment's constructor and receives the dialog's
 events through an implementation of the {@code NoticeDialogListener} interface:</p>
 
 <pre>
 public class MainActivity extends FragmentActivity
-                          implements NoticeDialog.NoticeDialogListener{
+                          implements NoticeDialogFragment.NoticeDialogListener{
     ...
     
     public void showNoticeDialog() {
         // Create an instance of the dialog fragment and show it
-        DialogFragment dialog = NoticeDialog.newInstance(this);
-        dialog.show(getSupportFragmentManager(), "NoticeDialog");
+        DialogFragment dialog = new NoticeDialogFragment();
+        dialog.show(getSupportFragmentManager(), "NoticeDialogFragment");
     }
 
+    // The dialog fragment receives a reference to this Activity through the
+    // Fragment.onAttach() callback, which it uses to call the following methods
+    // defined by the NoticeDialogFragment.NoticeDialogListener interface
     &#64;Override
     public void onDialogPositiveClick(DialogFragment dialog) {
         // User touched the dialog's positive button
@@ -573,11 +569,12 @@
 </pre>
 
 <p>Because the host activity implements the {@code NoticeDialogListener}&mdash;which is
-enforced by the {@code newInstance()} method shown above&mdash;the dialog fragment can use the
+enforced by the {@link android.support.v4.app.Fragment#onAttach onAttach()}
+callback method shown above&mdash;the dialog fragment can use the
 interface callback methods to deliver click events to the activity:</p>
 
 <pre>
-public class NoticeDialog extends DialogFragment {
+public class NoticeDialogFragment extends DialogFragment {
     ...
 
     &#64;Override
@@ -588,13 +585,13 @@
                .setPositiveButton(R.string.fire, new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int id) {
                        // Send the positive button event back to the host activity
-                       mListener.onDialogPositiveClick(NoticeDialog.this);
+                       mListener.onDialogPositiveClick(NoticeDialogFragment.this);
                    }
                })
                .setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int id) {
                        // Send the negative button event back to the host activity
-                       mListener.onDialogPositiveClick(NoticeDialog.this);
+                       mListener.onDialogPositiveClick(NoticeDialogFragment.this);
                    }
                });
         return builder.create();
@@ -604,8 +601,6 @@
 
 
 
-
-
 <h2 id="ShowingADialog">Showing a Dialog</h2>
 
 <p>When you want to show your dialog, create an instance of your {@link
@@ -621,7 +616,7 @@
 
 <pre>
 public void confirmFireMissiles() {
-    DialogFragment newFragment = FireMissilesDialog.newInstance(this);
+    DialogFragment newFragment = new FireMissilesDialogFragment();
     newFragment.show(getSupportFragmentManager(), "missiles");
 }
 </pre>
@@ -653,7 +648,7 @@
 dialog or an embeddable fragment (using a layout named <code>purchase_items.xml</code>):</p>
 
 <pre>
-public class CustomLayoutDialog extends DialogFragment {
+public class CustomDialogFragment extends DialogFragment {
     /** The system calls this to get the DialogFragment's layout, regardless
         of whether it's being displayed as a dialog or an embedded fragment. */
     &#64;Override
@@ -683,7 +678,7 @@
 <pre>
 public void showDialog() {
     FragmentManager fragmentManager = getSupportFragmentManager();
-    CustomLayoutDialog newFragment = new CustomLayoutDialog();
+    CustomDialogFragment newFragment = new CustomDialogFragment();
     
     if (mIsLargeLayout) {
         // The device is using a large layout, so show the fragment as a dialog
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 6238edb..22ecc61 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -1030,6 +1030,51 @@
     }
 
     /**
+     * Indicates whether the renderer responsible for drawing this
+     * bitmap should attempt to use mipmaps when this bitmap is drawn
+     * scaled down.
+     * 
+     * If you know that you are going to draw this bitmap at less than
+     * 50% of its original size, you may be able to obtain a higher
+     * quality
+     * 
+     * This property is only a suggestion that can be ignored by the
+     * renderer. It is not guaranteed to have any effect.
+     * 
+     * @return true if the renderer should attempt to use mipmaps,
+     *         false otherwise
+     * 
+     * @see #setHasMipMap(boolean)
+     */
+    public final boolean hasMipMap() {
+        return nativeHasMipMap(mNativeBitmap);
+    }
+
+    /**
+     * Set a hint for the renderer responsible for drawing this bitmap
+     * indicating that it should attempt to use mipmaps when this bitmap
+     * is drawn scaled down.
+     *
+     * If you know that you are going to draw this bitmap at less than
+     * 50% of its original size, you may be able to obtain a higher
+     * quality by turning this property on.
+     * 
+     * Note that if the renderer respects this hint it might have to
+     * allocate extra memory to hold the mipmap levels for this bitmap.
+     *
+     * This property is only a suggestion that can be ignored by the
+     * renderer. It is not guaranteed to have any effect.
+     *
+     * @param hasMipMap indicates whether the renderer should attempt
+     *                  to use mipmaps
+     *
+     * @see #hasMipMap()
+     */
+    public final void setHasMipMap(boolean hasMipMap) {
+        nativeSetHasMipMap(mNativeBitmap, hasMipMap);
+    }
+
+    /**
      * Fills the bitmap's pixels with the specified {@link Color}.
      *
      * @throws IllegalStateException if the bitmap is not mutable.
@@ -1356,7 +1401,6 @@
     private static native int nativeHeight(int nativeBitmap);
     private static native int nativeRowBytes(int nativeBitmap);
     private static native int nativeConfig(int nativeBitmap);
-    private static native boolean nativeHasAlpha(int nativeBitmap);
 
     private static native int nativeGetPixel(int nativeBitmap, int x, int y);
     private static native void nativeGetPixels(int nativeBitmap, int[] pixels,
@@ -1385,7 +1429,10 @@
                                                     int[] offsetXY);
 
     private static native void nativePrepareToDraw(int nativeBitmap);
+    private static native boolean nativeHasAlpha(int nativeBitmap);
     private static native void nativeSetHasAlpha(int nBitmap, boolean hasAlpha);
+    private static native boolean nativeHasMipMap(int nativeBitmap);
+    private static native void nativeSetHasMipMap(int nBitmap, boolean hasMipMap);
     private static native boolean nativeSameAs(int nb0, int nb1);
     
     /* package */ final int ni() {
diff --git a/graphics/java/android/renderscript/ScriptIntrinsicLUT.java b/graphics/java/android/renderscript/ScriptIntrinsicLUT.java
index 188e04c..41bdd25 100644
--- a/graphics/java/android/renderscript/ScriptIntrinsicLUT.java
+++ b/graphics/java/android/renderscript/ScriptIntrinsicLUT.java
@@ -41,7 +41,7 @@
             mCache[ct + 512] = (byte)ct;
             mCache[ct + 768] = (byte)ct;
         }
-        bindAllocation(mTables, 0);
+        setVar(0, mTables);
     }
 
     /**
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index d18a5b0..e7085b0 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -399,9 +399,20 @@
     if (scissorEnabled && (x != mScissorX || y != mScissorY ||
             width != mScissorWidth || height != mScissorHeight)) {
 
-        if (x < 0) x = 0;
-        if (y < 0) y = 0;
-
+        if (x < 0) {
+            width += x;
+            x = 0;
+        }
+        if (y < 0) {
+            height += y;
+            y = 0;
+        }
+        if (width < 0) {
+            width = 0;
+        }
+        if (height < 0) {
+            height = 0;
+        }
         glScissor(x, y, width, height);
 
         mScissorX = x;
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 589d5c2..81e68bd 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -1434,7 +1434,7 @@
     mHeight = height;
 }
 
-int DisplayListRenderer::prepareDirty(float left, float top,
+status_t DisplayListRenderer::prepareDirty(float left, float top,
         float right, float bottom, bool opaque) {
     mSnapshot = new Snapshot(mFirstSnapshot,
             SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 2610055..e42def5 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -550,7 +550,7 @@
     virtual bool isDeferred();
 
     virtual void setViewport(int width, int height);
-    virtual int prepareDirty(float left, float top, float right, float bottom, bool opaque);
+    virtual status_t prepareDirty(float left, float top, float right, float bottom, bool opaque);
     virtual void finish();
 
     virtual status_t callDrawGLFunction(Functor *functor, Rect& dirty);
diff --git a/libs/hwui/Layer.cpp b/libs/hwui/Layer.cpp
index 882e4bb..1cdc063 100644
--- a/libs/hwui/Layer.cpp
+++ b/libs/hwui/Layer.cpp
@@ -31,6 +31,7 @@
     meshIndices = NULL;
     meshElementCount = 0;
     cacheable = true;
+    dirty = false;
     textureLayer = false;
     renderTarget = GL_TEXTURE_2D;
     texture.width = layerWidth;
diff --git a/libs/hwui/Layer.h b/libs/hwui/Layer.h
index 69be317..e1f6a70 100644
--- a/libs/hwui/Layer.h
+++ b/libs/hwui/Layer.h
@@ -162,6 +162,14 @@
         this->cacheable = cacheable;
     }
 
+    inline bool isDirty() {
+        return dirty;
+    }
+
+    inline void setDirty(bool dirty) {
+        this->dirty = dirty;
+    }
+
     inline bool isTextureLayer() {
         return textureLayer;
     }
@@ -209,6 +217,9 @@
     }
 
     inline void allocateTexture(GLenum format, GLenum storage) {
+#if DEBUG_LAYERS
+        ALOGD("  Allocate layer: %dx%d", getWidth(), getHeight());
+#endif
         glTexImage2D(renderTarget, 0, format, getWidth(), getHeight(), 0, format, storage, NULL);
     }
 
@@ -284,6 +295,12 @@
     bool textureLayer;
 
     /**
+     * When set to true, this layer is dirty and should be cleared
+     * before any rendering occurs.
+     */
+    bool dirty;
+
+    /**
      * Indicates the render target.
      */
     GLenum renderTarget;
diff --git a/libs/hwui/LayerRenderer.cpp b/libs/hwui/LayerRenderer.cpp
index f2e7f66..3484d41 100644
--- a/libs/hwui/LayerRenderer.cpp
+++ b/libs/hwui/LayerRenderer.cpp
@@ -18,6 +18,8 @@
 
 #include <ui/Rect.h>
 
+#include <private/hwui/DrawGlInfo.h>
+
 #include "LayerCache.h"
 #include "LayerRenderer.h"
 #include "Matrix.h"
@@ -41,7 +43,8 @@
     initViewport(width, height);
 }
 
-int LayerRenderer::prepareDirty(float left, float top, float right, float bottom, bool opaque) {
+status_t LayerRenderer::prepareDirty(float left, float top, float right, float bottom,
+        bool opaque) {
     LAYER_RENDERER_LOGD("Rendering into layer, fbo = %d", mLayer->getFbo());
 
     glBindFramebuffer(GL_FRAMEBUFFER, mLayer->getFbo());
@@ -63,6 +66,20 @@
     return OpenGLRenderer::prepareDirty(dirty.left, dirty.top, dirty.right, dirty.bottom, opaque);
 }
 
+status_t LayerRenderer::clear(float left, float top, float right, float bottom, bool opaque) {
+    if (mLayer->isDirty()) {
+        getCaches().disableScissor();
+        glClear(GL_COLOR_BUFFER_BIT);
+
+        getCaches().resetScissor();
+        mLayer->setDirty(false);
+
+        return DrawGlInfo::kStatusDone;
+    }
+
+    return OpenGLRenderer::clear(left, top, right, bottom, opaque);
+}
+
 void LayerRenderer::finish() {
     OpenGLRenderer::finish();
 
@@ -201,6 +218,7 @@
     layer->setAlpha(255, SkXfermode::kSrcOver_Mode);
     layer->setBlend(!isOpaque);
     layer->setColorFilter(NULL);
+    layer->setDirty(true);
     layer->region.clear();
 
     GLuint previousFbo;
@@ -229,9 +247,6 @@
     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
             layer->getTexture(), 0);
 
-    caches.disableScissor();
-    glClear(GL_COLOR_BUFFER_BIT);
-
     glBindFramebuffer(GL_FRAMEBUFFER, previousFbo);
 
     return layer;
diff --git a/libs/hwui/LayerRenderer.h b/libs/hwui/LayerRenderer.h
index acedbcc..c44abce 100644
--- a/libs/hwui/LayerRenderer.h
+++ b/libs/hwui/LayerRenderer.h
@@ -48,7 +48,8 @@
     virtual ~LayerRenderer();
 
     virtual void setViewport(int width, int height);
-    virtual int prepareDirty(float left, float top, float right, float bottom, bool opaque);
+    virtual status_t prepareDirty(float left, float top, float right, float bottom, bool opaque);
+    virtual status_t clear(float left, float top, float right, float bottom, bool opaque);
     virtual void finish();
 
     ANDROID_API static Layer* createTextureLayer(bool isOpaque);
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index 2b50091..914516c 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -49,7 +49,7 @@
 
 #define ALPHA_THRESHOLD 0
 
-#define FILTER(paint) (paint && paint->isFilterBitmap() ? GL_LINEAR : GL_NEAREST)
+#define FILTER(paint) (!paint || paint->isFilterBitmap() ? GL_LINEAR : GL_NEAREST)
 
 ///////////////////////////////////////////////////////////////////////////////
 // Globals
@@ -165,11 +165,12 @@
     mFirstSnapshot->viewport.set(0, 0, width, height);
 }
 
-int OpenGLRenderer::prepare(bool opaque) {
+status_t OpenGLRenderer::prepare(bool opaque) {
     return prepareDirty(0.0f, 0.0f, mWidth, mHeight, opaque);
 }
 
-int OpenGLRenderer::prepareDirty(float left, float top, float right, float bottom, bool opaque) {
+status_t OpenGLRenderer::prepareDirty(float left, float top, float right, float bottom,
+        bool opaque) {
     mCaches.clearGarbage();
 
     mSnapshot = new Snapshot(mFirstSnapshot,
@@ -203,15 +204,18 @@
 
     debugOverdraw(true, true);
 
+    return clear(left, top, right, bottom, opaque);
+}
+
+status_t OpenGLRenderer::clear(float left, float top, float right, float bottom, bool opaque) {
     if (!opaque) {
         mCaches.enableScissor();
         mCaches.setScissor(left, mSnapshot->height - bottom, right - left, bottom - top);
         glClear(GL_COLOR_BUFFER_BIT);
         return DrawGlInfo::kStatusDrew;
-    } else {
-        mCaches.resetScissor();
     }
 
+    mCaches.resetScissor();
     return DrawGlInfo::kStatusDone;
 }
 
@@ -743,6 +747,7 @@
             bounds.getWidth() / float(layer->getWidth()), 0.0f);
     layer->setColorFilter(mColorFilter);
     layer->setBlend(true);
+    layer->setDirty(false);
 
     // Save the layer in the snapshot
     mSnapshot->flags |= Snapshot::kFlagIsLayer;
@@ -895,12 +900,6 @@
 void OpenGLRenderer::drawTextureLayer(Layer* layer, const Rect& rect) {
     float alpha = layer->getAlpha() / 255.0f;
 
-    mat4& transform = layer->getTransform();
-    if (!transform.isIdentity()) {
-        save(0);
-        mSnapshot->transform->multiply(transform);
-    }
-
     setupDraw();
     if (layer->getRenderTarget() == GL_TEXTURE_2D) {
         setupDrawWithTexture();
@@ -937,10 +936,6 @@
     glDrawArrays(GL_TRIANGLE_STRIP, 0, gMeshCount);
 
     finishDrawTexture();
-
-    if (!transform.isIdentity()) {
-        restore();
-    }
 }
 
 void OpenGLRenderer::composeLayerRect(Layer* layer, const Rect& rect, bool swap) {
@@ -1730,35 +1725,22 @@
 
 status_t OpenGLRenderer::drawBitmapMesh(SkBitmap* bitmap, int meshWidth, int meshHeight,
         float* vertices, int* colors, SkPaint* paint) {
-    // TODO: Do a quickReject
     if (!vertices || mSnapshot->isIgnored()) {
         return DrawGlInfo::kStatusDone;
     }
 
-    mCaches.activeTexture(0);
-    Texture* texture = mCaches.textureCache.get(bitmap);
-    if (!texture) return DrawGlInfo::kStatusDone;
-    const AutoTexture autoCleanup(texture);
-
-    texture->setWrap(GL_CLAMP_TO_EDGE, true);
-    texture->setFilter(FILTER(paint), true);
-
-    int alpha;
-    SkXfermode::Mode mode;
-    getAlphaAndMode(paint, &alpha, &mode);
-
-    const uint32_t count = meshWidth * meshHeight * 6;
-
+    // TODO: We should compute the bounding box when recording the display list
     float left = FLT_MAX;
     float top = FLT_MAX;
     float right = FLT_MIN;
     float bottom = FLT_MIN;
 
-    const bool hasActiveLayer = hasLayer();
+    const uint32_t count = meshWidth * meshHeight * 6;
 
     // TODO: Support the colors array
     TextureVertex mesh[count];
     TextureVertex* vertex = mesh;
+
     for (int32_t y = 0; y < meshHeight; y++) {
         for (int32_t x = 0; x < meshWidth; x++) {
             uint32_t i = (y * (meshWidth + 1) + x) * 2;
@@ -1785,17 +1767,31 @@
             TextureVertex::set(vertex++, vertices[cx], vertices[cy], u2, v1);
             TextureVertex::set(vertex++, vertices[dx], vertices[dy], u2, v2);
 
-            if (hasActiveLayer) {
-                // TODO: This could be optimized to avoid unnecessary ops
-                left = fminf(left, fminf(vertices[ax], fminf(vertices[bx], vertices[cx])));
-                top = fminf(top, fminf(vertices[ay], fminf(vertices[by], vertices[cy])));
-                right = fmaxf(right, fmaxf(vertices[ax], fmaxf(vertices[bx], vertices[cx])));
-                bottom = fmaxf(bottom, fmaxf(vertices[ay], fmaxf(vertices[by], vertices[cy])));
-            }
+            // TODO: This could be optimized to avoid unnecessary ops
+            left = fminf(left, fminf(vertices[ax], fminf(vertices[bx], vertices[cx])));
+            top = fminf(top, fminf(vertices[ay], fminf(vertices[by], vertices[cy])));
+            right = fmaxf(right, fmaxf(vertices[ax], fmaxf(vertices[bx], vertices[cx])));
+            bottom = fmaxf(bottom, fmaxf(vertices[ay], fmaxf(vertices[by], vertices[cy])));
         }
     }
 
-    if (hasActiveLayer) {
+    if (quickReject(left, top, right, bottom)) {
+        return DrawGlInfo::kStatusDone;
+    }
+
+    mCaches.activeTexture(0);
+    Texture* texture = mCaches.textureCache.get(bitmap);
+    if (!texture) return DrawGlInfo::kStatusDone;
+    const AutoTexture autoCleanup(texture);
+
+    texture->setWrap(GL_CLAMP_TO_EDGE, true);
+    texture->setFilter(FILTER(paint), true);
+
+    int alpha;
+    SkXfermode::Mode mode;
+    getAlphaAndMode(paint, &alpha, &mode);
+
+    if (hasLayer()) {
         dirtyLayer(left, top, right, bottom, *mSnapshot->transform);
     }
 
@@ -2791,12 +2787,24 @@
         return DrawGlInfo::kStatusDone;
     }
 
+    mat4* transform = NULL;
+    if (layer->isTextureLayer()) {
+        transform = &layer->getTransform();
+        if (!transform->isIdentity()) {
+            save(0);
+            mSnapshot->transform->multiply(*transform);
+        }
+    }
+
     Rect transformed;
     Rect clip;
     const bool rejected = quickRejectNoScissor(x, y,
             x + layer->layer.getWidth(), y + layer->layer.getHeight(), transformed, clip);
 
     if (rejected) {
+        if (transform && !transform->isIdentity()) {
+            restore();
+        }
         return DrawGlInfo::kStatusDone;
     }
 
@@ -2857,6 +2865,10 @@
         }
     }
 
+    if (transform && !transform->isIdentity()) {
+        restore();
+    }
+
     return DrawGlInfo::kStatusDrew;
 }
 
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index a40d69a..c5e4c8e 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -94,7 +94,7 @@
      *               and will not be cleared. If false, the target surface
      *               will be cleared
      */
-    ANDROID_API int prepare(bool opaque);
+    ANDROID_API status_t prepare(bool opaque);
 
     /**
      * Prepares the renderer to draw a frame. This method must be invoked
@@ -110,7 +110,7 @@
      *               and will not be cleared. If false, the target surface
      *               will be cleared in the specified dirty rectangle
      */
-    virtual int prepareDirty(float left, float top, float right, float bottom, bool opaque);
+    virtual status_t prepareDirty(float left, float top, float right, float bottom, bool opaque);
 
     /**
      * Indicates the end of a frame. This method must be invoked whenever
@@ -270,6 +270,11 @@
     void initViewport(int width, int height);
 
     /**
+     * Clears the underlying surface if needed.
+     */
+    virtual status_t clear(float left, float top, float right, float bottom, bool opaque);
+
+    /**
      * Call this method after updating a layer during a drawing pass.
      */
     void resumeAfterLayer();
@@ -355,6 +360,10 @@
         return false;
     }
 
+    Caches& getCaches() {
+        return mCaches;
+    }
+
 private:
     /**
      * Ensures the state of the renderer is the same as the state of
diff --git a/libs/hwui/Texture.h b/libs/hwui/Texture.h
index 03e2172..8d88bdc 100644
--- a/libs/hwui/Texture.h
+++ b/libs/hwui/Texture.h
@@ -36,6 +36,8 @@
         minFilter = GL_NEAREST;
         magFilter = GL_NEAREST;
 
+        mipMap = false;
+
         firstFilter = true;
         firstWrap = true;
 
@@ -83,6 +85,8 @@
                 glBindTexture(renderTarget, id);
             }
 
+            if (mipMap && min == GL_LINEAR) min = GL_LINEAR_MIPMAP_LINEAR;
+
             glTexParameteri(renderTarget, GL_TEXTURE_MIN_FILTER, min);
             glTexParameteri(renderTarget, GL_TEXTURE_MAG_FILTER, mag);
         }
@@ -116,7 +120,12 @@
      * Optional, size of the original bitmap.
      */
     uint32_t bitmapSize;
+    /**
+     * Indicates whether this texture will use trilinear filtering.
+     */
+    bool mipMap;
 
+private:
     /**
      * Last wrap modes set on this texture. Defaults to GL_CLAMP_TO_EDGE.
      */
@@ -129,7 +138,6 @@
     GLenum minFilter;
     GLenum magFilter;
 
-private:
     bool firstFilter;
     bool firstWrap;
 }; // struct Texture
diff --git a/libs/hwui/TextureCache.cpp b/libs/hwui/TextureCache.cpp
index 9fb61e4..10d112a 100644
--- a/libs/hwui/TextureCache.cpp
+++ b/libs/hwui/TextureCache.cpp
@@ -22,6 +22,7 @@
 
 #include <utils/threads.h>
 
+#include "Caches.h"
 #include "TextureCache.h"
 #include "Properties.h"
 
@@ -216,8 +217,15 @@
         return;
     }
 
+    // We could also enable mipmapping if both bitmap dimensions are powers
+    // of 2 but we'd have to deal with size changes. Let's keep this simple
+    const bool canMipMap = Caches::getInstance().extensions.hasNPot();
+
+    // If the texture had mipmap enabled but not anymore,
+    // force a glTexImage2D to discard the mipmap levels
     const bool resize = !regenerate || bitmap->width() != int(texture->width) ||
-            bitmap->height() != int(texture->height);
+            bitmap->height() != int(texture->height) ||
+            (regenerate && canMipMap && texture->mipMap && !bitmap->hasHardwareMipMap());
 
     if (!regenerate) {
         glGenTextures(1, &texture->id);
@@ -228,25 +236,22 @@
     texture->height = bitmap->height();
 
     glBindTexture(GL_TEXTURE_2D, texture->id);
-    if (!regenerate) {
-        glPixelStorei(GL_UNPACK_ALIGNMENT, bitmap->bytesPerPixel());
-    }
 
     switch (bitmap->getConfig()) {
     case SkBitmap::kA8_Config:
-        if (!regenerate) {
-            glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
-        }
+        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
         uploadToTexture(resize, GL_ALPHA, bitmap->rowBytesAsPixels(), texture->height,
                 GL_UNSIGNED_BYTE, bitmap->getPixels());
         texture->blend = true;
         break;
     case SkBitmap::kRGB_565_Config:
+        glPixelStorei(GL_UNPACK_ALIGNMENT, bitmap->bytesPerPixel());
         uploadToTexture(resize, GL_RGB, bitmap->rowBytesAsPixels(), texture->height,
                 GL_UNSIGNED_SHORT_5_6_5, bitmap->getPixels());
         texture->blend = false;
         break;
     case SkBitmap::kARGB_8888_Config:
+        glPixelStorei(GL_UNPACK_ALIGNMENT, bitmap->bytesPerPixel());
         uploadToTexture(resize, GL_RGBA, bitmap->rowBytesAsPixels(), texture->height,
                 GL_UNSIGNED_BYTE, bitmap->getPixels());
         // Do this after calling getPixels() to make sure Skia's deferred
@@ -255,6 +260,7 @@
         break;
     case SkBitmap::kARGB_4444_Config:
     case SkBitmap::kIndex8_Config:
+        glPixelStorei(GL_UNPACK_ALIGNMENT, bitmap->bytesPerPixel());
         uploadLoFiTexture(resize, bitmap, texture->width, texture->height);
         texture->blend = !bitmap->isOpaque();
         break;
@@ -263,6 +269,13 @@
         break;
     }
 
+    if (canMipMap) {
+        texture->mipMap = bitmap->hasHardwareMipMap();
+        if (texture->mipMap) {
+            glGenerateMipmap(GL_TEXTURE_2D);
+        }
+    }
+
     if (!regenerate) {
         texture->setFilter(GL_NEAREST);
         texture->setWrap(GL_CLAMP_TO_EDGE);
diff --git a/location/java/android/location/LocationRequest.java b/location/java/android/location/LocationRequest.java
index cb291ea..6871ee2 100644
--- a/location/java/android/location/LocationRequest.java
+++ b/location/java/android/location/LocationRequest.java
@@ -221,6 +221,18 @@
     /** @hide */
     public LocationRequest() { }
 
+    /** @hide */
+    public LocationRequest(LocationRequest src) {
+        mQuality = src.mQuality;
+        mInterval = src.mInterval;
+        mFastestInterval = src.mFastestInterval;
+        mExplicitFastestInterval = src.mExplicitFastestInterval;
+        mExpireAt = src.mExpireAt;
+        mNumUpdates = src.mNumUpdates;
+        mSmallestDisplacement = src.mSmallestDisplacement;
+        mProvider = src.mProvider;
+    }
+
     /**
      * Set the quality of the request.
      *
diff --git a/media/java/android/media/AudioService.java b/media/java/android/media/AudioService.java
index f77cbfb..dd320a0 100644
--- a/media/java/android/media/AudioService.java
+++ b/media/java/android/media/AudioService.java
@@ -634,7 +634,8 @@
         final ContentResolver cr = mContentResolver;
 
         int ringerModeFromSettings =
-                Settings.Global.getInt(cr, System.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL);
+                Settings.Global.getInt(
+                        cr, Settings.Global.MODE_RINGER, AudioManager.RINGER_MODE_NORMAL);
         int ringerMode = ringerModeFromSettings;
         // sanity check in case the settings are restored from a device with incompatible
         // ringer modes
@@ -645,7 +646,7 @@
             ringerMode = AudioManager.RINGER_MODE_SILENT;
         }
         if (ringerMode != ringerModeFromSettings) {
-            Settings.Global.putInt(cr, System.MODE_RINGER, ringerMode);
+            Settings.Global.putInt(cr, Settings.Global.MODE_RINGER, ringerMode);
         }
         synchronized(mSettingsLock) {
             mRingerMode = ringerMode;
@@ -3118,7 +3119,7 @@
         }
 
         private void persistRingerMode(int ringerMode) {
-            Settings.Global.putInt(mContentResolver, System.MODE_RINGER, ringerMode);
+            Settings.Global.putInt(mContentResolver, Settings.Global.MODE_RINGER, ringerMode);
         }
 
         private void playSoundEffect(int effectType, int volume) {
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
index 9b1098e..1c60401 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
@@ -114,10 +114,10 @@
             mProcMemWriter = new BufferedWriter(new FileWriter
                     (new File(MEDIA_PROCMEM_OUTPUT), true));
             mProcMemWriter.write(this.getName() + "\n");
-            mMemWriter = new BufferedWriter(new FileWriter
-                    (new File(MEDIA_MEMORY_OUTPUT), true));
         }
-
+        mMemWriter = new BufferedWriter(new FileWriter
+                (new File(MEDIA_MEMORY_OUTPUT), true));
+        mMemWriter.write(this.getName() + "\n");
     }
 
     @Override
@@ -126,10 +126,10 @@
             MediaTestUtil.getNativeHeapDump(this.getName() + "_after");
 
         if (MediaFrameworkPerfTestRunner.mGetProcmem) {
-            mMemWriter.write("\n");
             mProcMemWriter.close();
-            mMemWriter.close();
         }
+        mMemWriter.write("\n");
+        mMemWriter.close();
         super.tearDown();
     }
 
diff --git a/packages/FusedLocation/AndroidManifest.xml b/packages/FusedLocation/AndroidManifest.xml
index 4c57401..10b9064 100644
--- a/packages/FusedLocation/AndroidManifest.xml
+++ b/packages/FusedLocation/AndroidManifest.xml
@@ -18,7 +18,8 @@
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
         package="com.android.location.fused"
-        coreApp="true">
+        coreApp="true"
+        android:sharedUserId="android.uid.system">
 
     <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
     <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
@@ -39,7 +40,7 @@
            <intent-filter>
                <action android:name="com.android.location.service.FusedLocationProvider" />
            </intent-filter>
-           <meta-data android:name="version" android:value="1" />
+           <meta-data android:name="serviceVersion" android:value="0" />
         </service>
     </application>
 </manifest>
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 9e137ce..94e2286 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -165,16 +165,6 @@
          Value here is the same as WifiStateMachine.DEFAULT_MAX_DHCP_RETRIES -->
     <integer name="def_max_dhcp_retries">9</integer>
 
-    <!-- Dreams (screen saver) default settings -->
-    <!-- Whether the feature is enabled when charging (Settings.Secure.SCREENSAVER_ENABLED) -->
-    <bool name="def_screensaver_enabled">true</bool>
-    <!-- Whether the feature activates when docked (SCREENSAVER_ACTIVATE_ON_DOCK) -->
-    <bool name="def_screensaver_activate_on_dock">true</bool>
-    <!-- Whether the feature activates when docked (SCREENSAVER_ACTIVATE_ON_SLEEP) -->
-    <bool name="def_screensaver_activate_on_sleep">false</bool>
-    <!-- ComponentName of the default screen saver (Settings.Secure.SCREENSAVER_COMPONENT) -->
-    <string name="def_screensaver_component">com.google.android.deskclock/com.android.deskclock.Screensaver</string>
-
     <!-- Default for Settings.Secure.USER_SETUP_COMPLETE -->
     <bool name="def_user_setup_complete">false</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 0689268..b649b43 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -1166,15 +1166,15 @@
                 stmt = db.compileStatement("INSERT OR REPLACE INTO secure(name,value)"
                         + " VALUES(?,?);");
                 loadBooleanSetting(stmt, Settings.Secure.SCREENSAVER_ENABLED,
-                        R.bool.def_screensaver_enabled);
+                        com.android.internal.R.bool.config_dreamsEnabledByDefault);
                 loadBooleanSetting(stmt, Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK,
-                        R.bool.def_screensaver_activate_on_dock);
+                        com.android.internal.R.bool.config_dreamsActivatedOnDockByDefault);
                 loadBooleanSetting(stmt, Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP,
-                        R.bool.def_screensaver_activate_on_sleep);
-                loadStringSetting(stmt, Settings.Secure.SCREENSAVER_DEFAULT_COMPONENT,
-                        R.string.def_screensaver_component);
+                        com.android.internal.R.bool.config_dreamsActivatedOnSleepByDefault);
                 loadStringSetting(stmt, Settings.Secure.SCREENSAVER_COMPONENTS,
-                        R.string.def_screensaver_component);
+                        com.android.internal.R.string.config_dreamsDefaultComponent);
+                loadStringSetting(stmt, Settings.Secure.SCREENSAVER_DEFAULT_COMPONENT,
+                        com.android.internal.R.string.config_dreamsDefaultComponent);
 
                 db.setTransactionSuccessful();
             } finally {
@@ -2027,15 +2027,15 @@
             }
 
             loadBooleanSetting(stmt, Settings.Secure.SCREENSAVER_ENABLED,
-                    R.bool.def_screensaver_enabled);
+                    com.android.internal.R.bool.config_dreamsEnabledByDefault);
             loadBooleanSetting(stmt, Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK,
-                    R.bool.def_screensaver_activate_on_dock);
+                    com.android.internal.R.bool.config_dreamsActivatedOnDockByDefault);
             loadBooleanSetting(stmt, Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP,
-                    R.bool.def_screensaver_activate_on_sleep);
+                    com.android.internal.R.bool.config_dreamsActivatedOnSleepByDefault);
             loadStringSetting(stmt, Settings.Secure.SCREENSAVER_COMPONENTS,
-                    R.string.def_screensaver_component);
+                    com.android.internal.R.string.config_dreamsDefaultComponent);
             loadStringSetting(stmt, Settings.Secure.SCREENSAVER_DEFAULT_COMPONENT,
-                    R.string.def_screensaver_component);
+                    com.android.internal.R.string.config_dreamsDefaultComponent);
 
             loadBooleanSetting(stmt, Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED,
                     R.bool.def_accessibility_display_magnification_enabled);
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index f0e5a87..cfe70dc 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -63,7 +63,6 @@
     <uses-permission android:name="android.permission.WRITE_DREAM_STATE" />
 
     <application
-        android:name="com.android.systemui.SystemUIApplication"
         android:persistent="true"
         android:allowClearUserData="false"
         android:allowBackup="false"
@@ -109,7 +108,7 @@
 
         <activity android:name=".recent.RecentsActivity"
                 android:label="@string/accessibility_desc_recent_apps"
-                android:theme="@android:style/Theme.Holo.Wallpaper.NoTitleBar"
+                android:theme="@style/RecentsStyle"
                 android:excludeFromRecents="true"
                 android:launchMode="singleInstance"
                 android:exported="true">
@@ -118,6 +117,15 @@
           </intent-filter>
         </activity>
 
+        <receiver
+            android:name=".recent.RecentsPreloadReceiver"
+            android:exported="false">
+            <intent-filter>
+                <action android:name="com.android.systemui.recent.action.PRELOAD" />
+                <action android:name="com.android.systemui.recent.action.CANCEL_PRELOAD" />
+            </intent-filter>
+        </receiver>
+
         <!-- started from UsbDeviceSettingsManager -->
         <activity android:name=".usb.UsbConfirmActivity"
             android:exported="true"
diff --git a/packages/SystemUI/res/anim/recents_launch_from_launcher_enter.xml b/packages/SystemUI/res/anim/recents_launch_from_launcher_enter.xml
index 73ae9f2..1135bc0 100644
--- a/packages/SystemUI/res/anim/recents_launch_from_launcher_enter.xml
+++ b/packages/SystemUI/res/anim/recents_launch_from_launcher_enter.xml
@@ -18,7 +18,6 @@
 -->
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
-     android:detachWallpaper="true"
      android:shareInterpolator="false"
      android:zAdjustment="normal">
   <!--scale android:fromXScale="2.0" android:toXScale="1.0"
@@ -28,9 +27,4 @@
          android:fillBefore="true" android:fillAfter="true"
          android:pivotX="50%p" android:pivotY="50%p"
          android:duration="250" /-->
-  <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
-         android:fillEnabled="true"
-         android:fillBefore="true" android:fillAfter="true"
-         android:interpolator="@android:interpolator/decelerate_cubic"
-         android:duration="250"/>
 </set>
diff --git a/packages/SystemUI/res/anim/recents_launch_from_launcher_exit.xml b/packages/SystemUI/res/anim/recents_launch_from_launcher_exit.xml
index becc9d0..fa28cf4 100644
--- a/packages/SystemUI/res/anim/recents_launch_from_launcher_exit.xml
+++ b/packages/SystemUI/res/anim/recents_launch_from_launcher_exit.xml
@@ -19,7 +19,7 @@
 
 <set xmlns:android="http://schemas.android.com/apk/res/android"
      android:shareInterpolator="false"
-     android:zAdjustment="normal">
+     android:zAdjustment="top">
   <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
          android:fillEnabled="true"
          android:fillBefore="true" android:fillAfter="true"
diff --git a/packages/SystemUI/res/anim/wallpaper_recents_launch_from_launcher_enter.xml b/packages/SystemUI/res/anim/wallpaper_recents_launch_from_launcher_enter.xml
new file mode 100644
index 0000000..121daae
--- /dev/null
+++ b/packages/SystemUI/res/anim/wallpaper_recents_launch_from_launcher_enter.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+     android:shareInterpolator="false"
+     android:zAdjustment="normal">
+  <!--scale android:fromXScale="2.0" android:toXScale="1.0"
+         android:fromYScale="2.0" android:toYScale="1.0"
+         android:interpolator="@android:interpolator/decelerate_cubic"
+         android:fillEnabled="true"
+         android:fillBefore="true" android:fillAfter="true"
+         android:pivotX="50%p" android:pivotY="50%p"
+         android:duration="250" /-->
+  <alpha android:fromAlpha="0.0" android:toAlpha="1.0"
+         android:fillEnabled="true"
+         android:fillBefore="true" android:fillAfter="true"
+         android:interpolator="@android:interpolator/decelerate_cubic"
+         android:duration="250"/>
+</set>
diff --git a/packages/SystemUI/res/anim/wallpaper_recents_launch_from_launcher_exit.xml b/packages/SystemUI/res/anim/wallpaper_recents_launch_from_launcher_exit.xml
new file mode 100644
index 0000000..fa28cf4
--- /dev/null
+++ b/packages/SystemUI/res/anim/wallpaper_recents_launch_from_launcher_exit.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2012, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android"
+     android:shareInterpolator="false"
+     android:zAdjustment="top">
+  <alpha android:fromAlpha="1.0" android:toAlpha="0.0"
+         android:fillEnabled="true"
+         android:fillBefore="true" android:fillAfter="true"
+         android:interpolator="@android:interpolator/decelerate_cubic"
+         android:duration="250"/>
+</set>
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_notifications.png b/packages/SystemUI/res/drawable-hdpi/ic_notifications.png
deleted file mode 100644
index 612ab72..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_notifications.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_notifications2.png b/packages/SystemUI/res/drawable-hdpi/ic_notifications2.png
deleted file mode 100644
index 315c488..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_notifications2.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_notifications_normal.png b/packages/SystemUI/res/drawable-hdpi/ic_notifications_normal.png
new file mode 100644
index 0000000..62afe76
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_notifications_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_notify_clear_normal.png b/packages/SystemUI/res/drawable-hdpi/ic_notify_clear_normal.png
index a54761f..ead184d 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_notify_clear_normal.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_notify_clear_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_notify_clear_pressed.png b/packages/SystemUI/res/drawable-hdpi/ic_notify_clear_pressed.png
index f3f336c..203e232 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_notify_clear_pressed.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_notify_clear_pressed.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_notify_open_normal.png b/packages/SystemUI/res/drawable-hdpi/ic_notify_open_normal.png
new file mode 100644
index 0000000..2adafea
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_notify_open_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_notify_open_pressed.png b/packages/SystemUI/res/drawable-hdpi/ic_notify_open_pressed.png
new file mode 100644
index 0000000..8521ffc
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/ic_notify_open_pressed.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_notify_quicksettings_normal.png b/packages/SystemUI/res/drawable-hdpi/ic_notify_quicksettings_normal.png
index 172fd55..4436359 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_notify_quicksettings_normal.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_notify_quicksettings_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_notify_quicksettings_pressed.png b/packages/SystemUI/res/drawable-hdpi/ic_notify_quicksettings_pressed.png
index 5318a6e..c86710d 100644
--- a/packages/SystemUI/res/drawable-hdpi/ic_notify_quicksettings_pressed.png
+++ b/packages/SystemUI/res/drawable-hdpi/ic_notify_quicksettings_pressed.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_notifications.png b/packages/SystemUI/res/drawable-mdpi/ic_notifications.png
deleted file mode 100644
index 612ab72..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_notifications.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_notifications2.png b/packages/SystemUI/res/drawable-mdpi/ic_notifications2.png
deleted file mode 100644
index 1d07cbf..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_notifications2.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_notifications_normal.png b/packages/SystemUI/res/drawable-mdpi/ic_notifications_normal.png
new file mode 100644
index 0000000..62afe76
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_notifications_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_notify_clear_normal.png b/packages/SystemUI/res/drawable-mdpi/ic_notify_clear_normal.png
index b44b527..5dacccb 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_notify_clear_normal.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_notify_clear_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_notify_clear_pressed.png b/packages/SystemUI/res/drawable-mdpi/ic_notify_clear_pressed.png
index 94c8165..f1f6b00 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_notify_clear_pressed.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_notify_clear_pressed.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_notify_open_normal.png b/packages/SystemUI/res/drawable-mdpi/ic_notify_open_normal.png
new file mode 100644
index 0000000..2ab0cd7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_notify_open_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_notify_open_pressed.png b/packages/SystemUI/res/drawable-mdpi/ic_notify_open_pressed.png
new file mode 100644
index 0000000..49ac94b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/ic_notify_open_pressed.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_notify_quicksettings_normal.png b/packages/SystemUI/res/drawable-mdpi/ic_notify_quicksettings_normal.png
index 6104424..09d2c55 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_notify_quicksettings_normal.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_notify_quicksettings_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_notify_quicksettings_pressed.png b/packages/SystemUI/res/drawable-mdpi/ic_notify_quicksettings_pressed.png
index 625da59..322d1a7 100644
--- a/packages/SystemUI/res/drawable-mdpi/ic_notify_quicksettings_pressed.png
+++ b/packages/SystemUI/res/drawable-mdpi/ic_notify_quicksettings_pressed.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_notifications.png b/packages/SystemUI/res/drawable-xhdpi/ic_notifications.png
deleted file mode 100644
index 28a902c..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_notifications.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_notifications2.png b/packages/SystemUI/res/drawable-xhdpi/ic_notifications2.png
deleted file mode 100644
index b02e7a1..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_notifications2.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_notifications_normal.png b/packages/SystemUI/res/drawable-xhdpi/ic_notifications_normal.png
new file mode 100644
index 0000000..983302c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_notifications_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_notify_clear_normal.png b/packages/SystemUI/res/drawable-xhdpi/ic_notify_clear_normal.png
index 870beb4..c882e9a 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_notify_clear_normal.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_notify_clear_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_notify_clear_pressed.png b/packages/SystemUI/res/drawable-xhdpi/ic_notify_clear_pressed.png
index 94a4646..992b50d 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_notify_clear_pressed.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_notify_clear_pressed.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_notify_open_normal.png b/packages/SystemUI/res/drawable-xhdpi/ic_notify_open_normal.png
new file mode 100644
index 0000000..b0e35a1
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_notify_open_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_notify_open_pressed.png b/packages/SystemUI/res/drawable-xhdpi/ic_notify_open_pressed.png
new file mode 100644
index 0000000..42bbbbc
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_notify_open_pressed.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_notify_quicksettings_normal.png b/packages/SystemUI/res/drawable-xhdpi/ic_notify_quicksettings_normal.png
index 477c067..2d445279 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_notify_quicksettings_normal.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_notify_quicksettings_normal.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_notify_quicksettings_pressed.png b/packages/SystemUI/res/drawable-xhdpi/ic_notify_quicksettings_pressed.png
index 6e5c4af..ddf2c7a 100644
--- a/packages/SystemUI/res/drawable-xhdpi/ic_notify_quicksettings_pressed.png
+++ b/packages/SystemUI/res/drawable-xhdpi/ic_notify_quicksettings_pressed.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable/ic_notifications.xml b/packages/SystemUI/res/drawable/ic_notifications.xml
index 2c8012e..68c4774 100644
--- a/packages/SystemUI/res/drawable/ic_notifications.xml
+++ b/packages/SystemUI/res/drawable/ic_notifications.xml
@@ -16,8 +16,8 @@
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_pressed="true"
-         android:drawable="@drawable/ic_notifications" />
+         android:drawable="@drawable/ic_notifications_normal" />
     <item
-         android:drawable="@drawable/ic_notifications" />
+         android:drawable="@drawable/ic_notifications_normal" />
 </selector>
 
diff --git a/packages/SystemUI/res/drawable/ic_notify_quicksettings.xml b/packages/SystemUI/res/drawable/ic_notify_quicksettings.xml
index d8ea524..7cf3175 100644
--- a/packages/SystemUI/res/drawable/ic_notify_quicksettings.xml
+++ b/packages/SystemUI/res/drawable/ic_notify_quicksettings.xml
@@ -16,7 +16,7 @@
 
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_pressed="true"
-         android:drawable="@drawable/ic_notify_quicksettings_pressed" />
+         android:drawable="@drawable/ic_notify_quicksettings_normal" />
     <item
          android:drawable="@drawable/ic_notify_quicksettings_normal" />
 </selector>
diff --git a/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml b/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
index 5a5769b..f7b1d78 100644
--- a/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
+++ b/packages/SystemUI/res/layout/quick_settings_brightness_dialog.xml
@@ -21,6 +21,8 @@
 
     <ImageView
         android:id="@+id/brightness_icon"
+	    android:layout_width="wrap_content"
+	    android:layout_height="wrap_content"
         android:layout_gravity="center_vertical"
         android:paddingRight="10dp"
         android:src="@drawable/ic_qs_brightness_auto_off"
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 5408f76..b71025e 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -63,7 +63,7 @@
             android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Network.EmergencyOnly"
             android:layout_height="wrap_content"
             android:layout_width="match_parent"
-            android:paddingBottom="4dp"
+            android:padding="4dp"
             android:gravity="center"
             android:visibility="gone"
             />
diff --git a/packages/SystemUI/res/layout/status_bar_expanded_header.xml b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
index c13405a..03f03e2 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
@@ -20,37 +20,40 @@
     xmlns:systemui="http://schemas.android.com/apk/res/com.android.systemui"
     android:id="@+id/header"
     android:layout_width="match_parent"
-    android:layout_height="wrap_content"
+    android:layout_height="@dimen/notification_panel_header_height"
     android:background="@drawable/notification_header_bg"
     android:orientation="horizontal"
     android:gravity="center_vertical"
     android:baselineAligned="false"
     >
-    <LinearLayout
+    <RelativeLayout
+        android:id="@+id/datetime"
         android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:orientation="horizontal"
+        android:layout_height="match_parent"
+        android:paddingLeft="8dp"
+        android:paddingRight="8dp"
+        android:background="@drawable/ic_notify_button_bg"
+        android:enabled="false"
         >
         <com.android.systemui.statusbar.policy.Clock
             android:id="@+id/clock"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_marginLeft="8dp"
+            android:layout_marginRight="8dp"
             android:singleLine="true"
             android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Clock"
-            android:gravity="bottom"
+            android:layout_centerVertical="true"
             />
 
         <com.android.systemui.statusbar.policy.DateView android:id="@+id/date"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:layout_marginLeft="8dp"
-            android:layout_marginRight="8dp"
             android:singleLine="true"
             android:textAppearance="@style/TextAppearance.StatusBar.Expanded.Date"
-            android:gravity="bottom"
+            android:layout_toRightOf="@id/clock"
+            android:layout_alignBaseline="@id/clock"
             />
-    </LinearLayout>
+    </RelativeLayout>
 
     <Space
         android:layout_width="0dp"
diff --git a/packages/SystemUI/res/layout/super_status_bar.xml b/packages/SystemUI/res/layout/super_status_bar.xml
index 07aca6c..2b56618 100644
--- a/packages/SystemUI/res/layout/super_status_bar.xml
+++ b/packages/SystemUI/res/layout/super_status_bar.xml
@@ -36,7 +36,6 @@
         android:id="@+id/panel_holder"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
-        android:layout_marginTop="@*android:dimen/status_bar_height"
         >
         <include layout="@layout/status_bar_expanded"
             android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/system_bar_notification_panel_title.xml b/packages/SystemUI/res/layout/system_bar_notification_panel_title.xml
index 2d1bda4..59544f4 100644
--- a/packages/SystemUI/res/layout/system_bar_notification_panel_title.xml
+++ b/packages/SystemUI/res/layout/system_bar_notification_panel_title.xml
@@ -170,7 +170,7 @@
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
                     android:src="@drawable/ic_sysbar_quicksettings"
-                    android:contentDescription="@string/accessibility_settings_button"
+                    android:contentDescription="@string/accessibility_desc_quick_settings"
                     />
 
                 <ImageView
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index f7f963e..da78d29 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -147,8 +147,7 @@
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"تم تجاهل الإشعار."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"مركز الإشعارات."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"الإعدادات السريعة."</string>
-    <!-- no translation found for accessibility_desc_recent_apps (9014032916410590027) -->
-    <skip />
+    <string name="accessibility_desc_recent_apps" msgid="9014032916410590027">"التطبيقات الحديثة"</string>
     <string name="accessibility_quick_settings_user" msgid="1104846699869476855">"المستخدم <xliff:g id="USER">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi" msgid="6099781031669728709">"<xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="NETWORK">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"الجوال <xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="TYPE">%2$s</xliff:g>. <xliff:g id="NETWORK">%3$s</xliff:g>."</string>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 4b8aad2..79bc53a 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -149,8 +149,7 @@
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Апавяшчэнне прапушчана."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Цень апавяшчэння.."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Хуткія налады."</string>
-    <!-- no translation found for accessibility_desc_recent_apps (9014032916410590027) -->
-    <skip />
+    <string name="accessibility_desc_recent_apps" msgid="9014032916410590027">"Апошнія прыкладанні."</string>
     <string name="accessibility_quick_settings_user" msgid="1104846699869476855">"Карыстальнік: <xliff:g id="USER">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi" msgid="6099781031669728709">"<xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="NETWORK">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"Мабiльны сiгнал: <xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="TYPE">%2$s</xliff:g>. <xliff:g id="NETWORK">%3$s</xliff:g>."</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index c05fc59..59ba693 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -147,8 +147,7 @@
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Известието е отхвърлено."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Падащ панел с известия."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Бързи настройки."</string>
-    <!-- no translation found for accessibility_desc_recent_apps (9014032916410590027) -->
-    <skip />
+    <string name="accessibility_desc_recent_apps" msgid="9014032916410590027">"Скорошни приложения."</string>
     <string name="accessibility_quick_settings_user" msgid="1104846699869476855">"Потребител: <xliff:g id="USER">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi" msgid="6099781031669728709">"<xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="NETWORK">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"Мобилно устройство: <xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="TYPE">%2$s</xliff:g>. <xliff:g id="NETWORK">%3$s</xliff:g>."</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 72fe18e..5e632fa 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -149,8 +149,7 @@
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Oznámení je zavřeno."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Panel oznámení."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Rychlé nastavení."</string>
-    <!-- no translation found for accessibility_desc_recent_apps (9014032916410590027) -->
-    <skip />
+    <string name="accessibility_desc_recent_apps" msgid="9014032916410590027">"Naposledy použité aplikace"</string>
     <string name="accessibility_quick_settings_user" msgid="1104846699869476855">"Uživatel <xliff:g id="USER">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi" msgid="6099781031669728709">"<xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="NETWORK">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"Mobil: <xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="TYPE">%2$s</xliff:g>. <xliff:g id="NETWORK">%3$s</xliff:g>."</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 2575d2c..3e767a0 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -149,8 +149,7 @@
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Benachrichtigung geschlossen"</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Benachrichtigungsleiste"</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Schnelleinstellungen"</string>
-    <!-- no translation found for accessibility_desc_recent_apps (9014032916410590027) -->
-    <skip />
+    <string name="accessibility_desc_recent_apps" msgid="9014032916410590027">"Kürzlich geöffnete Apps"</string>
     <string name="accessibility_quick_settings_user" msgid="1104846699869476855">"Nutzer: <xliff:g id="USER">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_wifi" msgid="6099781031669728709">"<xliff:g id="SIGNAL">%1$s</xliff:g>, <xliff:g id="NETWORK">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"Mobilfunkverbindung: <xliff:g id="SIGNAL">%1$s</xliff:g>, <xliff:g id="TYPE">%2$s</xliff:g>, <xliff:g id="NETWORK">%3$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 1460996..9bbd5d7 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -149,8 +149,7 @@
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notificación ignorada"</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Pantalla de notificaciones"</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Configuración rápida"</string>
-    <!-- no translation found for accessibility_desc_recent_apps (9014032916410590027) -->
-    <skip />
+    <string name="accessibility_desc_recent_apps" msgid="9014032916410590027">"Aplicaciones recientes"</string>
     <string name="accessibility_quick_settings_user" msgid="1104846699869476855">"Usuario <xliff:g id="USER">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_wifi" msgid="6099781031669728709">"<xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="NETWORK">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"Móvil <xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="TYPE">%2$s</xliff:g>. <xliff:g id="NETWORK">%3$s</xliff:g>."</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index d984bf8..6accc9f 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -147,8 +147,7 @@
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"اعلان ردشد."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"مجموعه اعلان."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"تنظیمات سریع."</string>
-    <!-- no translation found for accessibility_desc_recent_apps (9014032916410590027) -->
-    <skip />
+    <string name="accessibility_desc_recent_apps" msgid="9014032916410590027">"برنامه‌های اخیر"</string>
     <string name="accessibility_quick_settings_user" msgid="1104846699869476855">"کاربر <xliff:g id="USER">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi" msgid="6099781031669728709">"<xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="NETWORK">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"تلفن همراه <xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="TYPE">%2$s</xliff:g>. <xliff:g id="NETWORK">%3$s</xliff:g>."</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 9d28900..3bc0371 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -147,8 +147,7 @@
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Ilmoitus hylätty."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Ilmoitusalue."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Pika-asetukset."</string>
-    <!-- no translation found for accessibility_desc_recent_apps (9014032916410590027) -->
-    <skip />
+    <string name="accessibility_desc_recent_apps" msgid="9014032916410590027">"Viimeaikaiset sovellukset"</string>
     <string name="accessibility_quick_settings_user" msgid="1104846699869476855">"Käyttäjä: <xliff:g id="USER">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi" msgid="6099781031669728709">"<xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="NETWORK">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"Mobiiliverkkoyhteys: <xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="TYPE">%2$s</xliff:g>. <xliff:g id="NETWORK">%3$s</xliff:g>."</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index ab98d24..02eb529 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -149,8 +149,7 @@
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notification masquée"</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Volet des notifications"</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Paramètres rapides"</string>
-    <!-- no translation found for accessibility_desc_recent_apps (9014032916410590027) -->
-    <skip />
+    <string name="accessibility_desc_recent_apps" msgid="9014032916410590027">"Applications récentes"</string>
     <string name="accessibility_quick_settings_user" msgid="1104846699869476855">"Utilisateur <xliff:g id="USER">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_wifi" msgid="6099781031669728709">"<xliff:g id="SIGNAL">%1$s</xliff:g>, <xliff:g id="NETWORK">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"Signal mobile : <xliff:g id="SIGNAL">%1$s</xliff:g>, <xliff:g id="TYPE">%2$s</xliff:g>, <xliff:g id="NETWORK">%3$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 718d267..e2bc2c3 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -147,8 +147,7 @@
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"सूचना खारिज की गई."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"सूचना शेड."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"त्वरित सेटिंग."</string>
-    <!-- no translation found for accessibility_desc_recent_apps (9014032916410590027) -->
-    <skip />
+    <string name="accessibility_desc_recent_apps" msgid="9014032916410590027">"हाल ही के एप्‍लिकेशन."</string>
     <string name="accessibility_quick_settings_user" msgid="1104846699869476855">"उपयोगकर्ता <xliff:g id="USER">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi" msgid="6099781031669728709">"<xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="NETWORK">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"मोबाइल <xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="TYPE">%2$s</xliff:g>. <xliff:g id="NETWORK">%3$s</xliff:g>."</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index bd19a44..e318120 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -147,8 +147,7 @@
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Obavijest je odbačena."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Zaslon obavijesti."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Brze postavke."</string>
-    <!-- no translation found for accessibility_desc_recent_apps (9014032916410590027) -->
-    <skip />
+    <string name="accessibility_desc_recent_apps" msgid="9014032916410590027">"Nedavne aplikacije."</string>
     <string name="accessibility_quick_settings_user" msgid="1104846699869476855">"Korisnik <xliff:g id="USER">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi" msgid="6099781031669728709">"<xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="NETWORK">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"Mobitel <xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="TYPE">%2$s</xliff:g>. <xliff:g id="NETWORK">%3$s</xliff:g>."</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 96bb897..3dafd2b 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -147,8 +147,7 @@
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Értesítés elvetve."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Értesítési felület."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Gyorsbeállítások."</string>
-    <!-- no translation found for accessibility_desc_recent_apps (9014032916410590027) -->
-    <skip />
+    <string name="accessibility_desc_recent_apps" msgid="9014032916410590027">"Legutóbbi alkalmazások"</string>
     <string name="accessibility_quick_settings_user" msgid="1104846699869476855">"Felhasználó: <xliff:g id="USER">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi" msgid="6099781031669728709">"<xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="NETWORK">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"Mobil <xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="TYPE">%2$s</xliff:g>. <xliff:g id="NETWORK">%3$s</xliff:g>."</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index dce8076..c26cdce 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -147,8 +147,7 @@
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Pemberitahuan disingkirkan."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Bayangan pemberitahuan."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Setelan cepat."</string>
-    <!-- no translation found for accessibility_desc_recent_apps (9014032916410590027) -->
-    <skip />
+    <string name="accessibility_desc_recent_apps" msgid="9014032916410590027">"Aplikasi terkini."</string>
     <string name="accessibility_quick_settings_user" msgid="1104846699869476855">"Pengguna <xliff:g id="USER">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi" msgid="6099781031669728709">"<xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="NETWORK">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"Seluler <xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="TYPE">%2$s</xliff:g>. <xliff:g id="NETWORK">%3$s</xliff:g>."</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index a1e7aba..0481d63 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -147,8 +147,7 @@
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"הודעה נדחתה."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"תריס התראות."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"הגדרות מהירות."</string>
-    <!-- no translation found for accessibility_desc_recent_apps (9014032916410590027) -->
-    <skip />
+    <string name="accessibility_desc_recent_apps" msgid="9014032916410590027">"יישומים אחרונים"</string>
     <string name="accessibility_quick_settings_user" msgid="1104846699869476855">"משתמש <xliff:g id="USER">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi" msgid="6099781031669728709">"<xliff:g id="SIGNAL">%1$s</xliff:g>‏. <xliff:g id="NETWORK">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"נייד <xliff:g id="SIGNAL">%1$s</xliff:g>.‏ <xliff:g id="TYPE">%2$s</xliff:g>.‏ <xliff:g id="NETWORK">%3$s</xliff:g>.‏"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 23babd0..1b89e13 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -149,8 +149,7 @@
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"通知が削除されました。"</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"通知シェード"</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"クイック設定"</string>
-    <!-- no translation found for accessibility_desc_recent_apps (9014032916410590027) -->
-    <skip />
+    <string name="accessibility_desc_recent_apps" msgid="9014032916410590027">"最近使ったアプリです。"</string>
     <string name="accessibility_quick_settings_user" msgid="1104846699869476855">"ユーザー: <xliff:g id="USER">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_wifi" msgid="6099781031669728709">"<xliff:g id="SIGNAL">%1$s</xliff:g>、<xliff:g id="NETWORK">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"モバイル: <xliff:g id="SIGNAL">%1$s</xliff:g>、<xliff:g id="TYPE">%2$s</xliff:g>、<xliff:g id="NETWORK">%3$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index f01d7eb..71d305f 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -147,8 +147,7 @@
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"알림이 제거되었습니다."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"알림 세부정보"</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"빠른 설정"</string>
-    <!-- no translation found for accessibility_desc_recent_apps (9014032916410590027) -->
-    <skip />
+    <string name="accessibility_desc_recent_apps" msgid="9014032916410590027">"최근 앱"</string>
     <string name="accessibility_quick_settings_user" msgid="1104846699869476855">"사용자 <xliff:g id="USER">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_wifi" msgid="6099781031669728709">"<xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="NETWORK">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"모바일 <xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="TYPE">%2$s</xliff:g>. <xliff:g id="NETWORK">%3$s</xliff:g>."</string>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index a70c12e..01751b0 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -147,8 +147,7 @@
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Pemberitahuan diketepikan."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Bidai pemberitahuan."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Tetapan pantas."</string>
-    <!-- no translation found for accessibility_desc_recent_apps (9014032916410590027) -->
-    <skip />
+    <string name="accessibility_desc_recent_apps" msgid="9014032916410590027">"Apl terbaru."</string>
     <string name="accessibility_quick_settings_user" msgid="1104846699869476855">"Pengguna <xliff:g id="USER">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi" msgid="6099781031669728709">"<xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="NETWORK">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"Mudah Alih <xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="TYPE">%2$s</xliff:g>. <xliff:g id="NETWORK">%3$s</xliff:g>."</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index d3df443..98f13c7 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -147,8 +147,7 @@
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Zamknięto powiadomienie."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Obszar powiadomień."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Szybkie ustawienia."</string>
-    <!-- no translation found for accessibility_desc_recent_apps (9014032916410590027) -->
-    <skip />
+    <string name="accessibility_desc_recent_apps" msgid="9014032916410590027">"Ostatnii używane aplikacje."</string>
     <string name="accessibility_quick_settings_user" msgid="1104846699869476855">"Użytkownik: <xliff:g id="USER">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi" msgid="6099781031669728709">"<xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="NETWORK">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"Sieć komórkowa: <xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="TYPE">%2$s</xliff:g>. <xliff:g id="NETWORK">%3$s</xliff:g>."</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index a4a871e..9eeb01b 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -149,8 +149,7 @@
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notificação dispensada."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Aba de notificações."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Configurações rápidas."</string>
-    <!-- no translation found for accessibility_desc_recent_apps (9014032916410590027) -->
-    <skip />
+    <string name="accessibility_desc_recent_apps" msgid="9014032916410590027">"Aplicativos recentes."</string>
     <string name="accessibility_quick_settings_user" msgid="1104846699869476855">"Usuário <xliff:g id="USER">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi" msgid="6099781031669728709">"<xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="NETWORK">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"Celular <xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="TYPE">%2$s</xliff:g>. <xliff:g id="NETWORK">%3$s</xliff:g>."</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index a73ad1a..616ddb7 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -147,8 +147,7 @@
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Notificarea a fost închisă."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Fereastră pentru notificări."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Setări rapide."</string>
-    <!-- no translation found for accessibility_desc_recent_apps (9014032916410590027) -->
-    <skip />
+    <string name="accessibility_desc_recent_apps" msgid="9014032916410590027">"Aplicaţii recente"</string>
     <string name="accessibility_quick_settings_user" msgid="1104846699869476855">"Utilizatorul <xliff:g id="USER">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi" msgid="6099781031669728709">"<xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="NETWORK">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"Semnal mobil: <xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="TYPE">%2$s</xliff:g>. <xliff:g id="NETWORK">%3$s</xliff:g>."</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index a04d732..6e10de4 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -149,8 +149,7 @@
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Уведомление закрыто"</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Панель уведомлений"</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Быстрые настройки"</string>
-    <!-- no translation found for accessibility_desc_recent_apps (9014032916410590027) -->
-    <skip />
+    <string name="accessibility_desc_recent_apps" msgid="9014032916410590027">"Недавние приложения"</string>
     <string name="accessibility_quick_settings_user" msgid="1104846699869476855">"Пользователь <xliff:g id="USER">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_wifi" msgid="6099781031669728709">"<xliff:g id="NETWORK">%2$s</xliff:g>: <xliff:g id="SIGNAL">%1$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"Мобильная сеть: <xliff:g id="NETWORK">%3$s</xliff:g> (<xliff:g id="TYPE">%2$s</xliff:g>, <xliff:g id="SIGNAL">%1$s</xliff:g>)"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 6d126b1..9151512 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -149,8 +149,7 @@
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Upozornenie bolo zrušené."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Panel upozornení."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Rýchle nastavenia."</string>
-    <!-- no translation found for accessibility_desc_recent_apps (9014032916410590027) -->
-    <skip />
+    <string name="accessibility_desc_recent_apps" msgid="9014032916410590027">"Nedávne aplikácie"</string>
     <string name="accessibility_quick_settings_user" msgid="1104846699869476855">"Používateľ: <xliff:g id="USER">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi" msgid="6099781031669728709">"<xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="NETWORK">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"Mobil: <xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="TYPE">%2$s</xliff:g>. <xliff:g id="NETWORK">%3$s</xliff:g>."</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 2d4006b..7be851c 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -147,8 +147,7 @@
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Obvestilo je bilo odstranjeno."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Zaslon z obvestili."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Hitre nastavitve."</string>
-    <!-- no translation found for accessibility_desc_recent_apps (9014032916410590027) -->
-    <skip />
+    <string name="accessibility_desc_recent_apps" msgid="9014032916410590027">"Nedavne aplikacije."</string>
     <string name="accessibility_quick_settings_user" msgid="1104846699869476855">"Uporabnik: <xliff:g id="USER">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi" msgid="6099781031669728709">"<xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="NETWORK">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"Mobilni telefon: <xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="TYPE">%2$s</xliff:g>. <xliff:g id="NETWORK">%3$s</xliff:g>."</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index fce2c57..9d9da87 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -147,8 +147,7 @@
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Обавештење је одбачено."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Прозор са обавештењима."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Брза подешавања."</string>
-    <!-- no translation found for accessibility_desc_recent_apps (9014032916410590027) -->
-    <skip />
+    <string name="accessibility_desc_recent_apps" msgid="9014032916410590027">"Недавне апликације."</string>
     <string name="accessibility_quick_settings_user" msgid="1104846699869476855">"Корисник: <xliff:g id="USER">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi" msgid="6099781031669728709">"<xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="NETWORK">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"Мобилна мрежа: <xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="TYPE">%2$s</xliff:g>. <xliff:g id="NETWORK">%3$s</xliff:g>."</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 16b8316..bae649d 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -147,8 +147,7 @@
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Meddelandet ignorerades."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Meddelandepanel."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Snabbinställningar."</string>
-    <!-- no translation found for accessibility_desc_recent_apps (9014032916410590027) -->
-    <skip />
+    <string name="accessibility_desc_recent_apps" msgid="9014032916410590027">"Senaste apparna"</string>
     <string name="accessibility_quick_settings_user" msgid="1104846699869476855">"Användare <xliff:g id="USER">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi" msgid="6099781031669728709">"<xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="NETWORK">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"Mobil <xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="TYPE">%2$s</xliff:g>. <xliff:g id="NETWORK">%3$s</xliff:g>."</string>
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index df6ed19..fc80f5c 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -47,4 +47,8 @@
 
     <!-- Minimum fraction of the screen that should be taken up by the notification panel. -->
     <item type="dimen" name="notification_panel_min_height_frac">40%</item>
+
+    <!-- How far to slide the panel out when you touch it -->
+    <!-- On tablets this is just the close_handle_height -->
+    <dimen name="peek_height">@dimen/close_handle_height</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 646225d..668504e 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -147,8 +147,7 @@
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"ปิดการแจ้งเตือนแล้ว"</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"หน้าต่างแจ้งเตือน"</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"การตั้งค่าด่วน"</string>
-    <!-- no translation found for accessibility_desc_recent_apps (9014032916410590027) -->
-    <skip />
+    <string name="accessibility_desc_recent_apps" msgid="9014032916410590027">"แอปพลิเคชันล่าสุด"</string>
     <string name="accessibility_quick_settings_user" msgid="1104846699869476855">"ผู้ใช้ <xliff:g id="USER">%s</xliff:g>"</string>
     <string name="accessibility_quick_settings_wifi" msgid="6099781031669728709">"<xliff:g id="SIGNAL">%1$s</xliff:g> <xliff:g id="NETWORK">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"มือถือ <xliff:g id="SIGNAL">%1$s</xliff:g> <xliff:g id="TYPE">%2$s</xliff:g> <xliff:g id="NETWORK">%3$s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 7baad61..312d8fd 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -147,8 +147,7 @@
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Na-dismiss ang notification."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Notification shade."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Mga mabilisang setting."</string>
-    <!-- no translation found for accessibility_desc_recent_apps (9014032916410590027) -->
-    <skip />
+    <string name="accessibility_desc_recent_apps" msgid="9014032916410590027">"Kamakailang apps."</string>
     <string name="accessibility_quick_settings_user" msgid="1104846699869476855">"User na si <xliff:g id="USER">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi" msgid="6099781031669728709">"<xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="NETWORK">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"Mobile <xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="TYPE">%2$s</xliff:g>. <xliff:g id="NETWORK">%3$s</xliff:g>."</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index c6ba738..5012bc5 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -147,8 +147,7 @@
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Bildirim kapatıldı."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Bildirim gölgesi."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Hızlı ayarlar."</string>
-    <!-- no translation found for accessibility_desc_recent_apps (9014032916410590027) -->
-    <skip />
+    <string name="accessibility_desc_recent_apps" msgid="9014032916410590027">"Son uygulamalar."</string>
     <string name="accessibility_quick_settings_user" msgid="1104846699869476855">"Kullanıcı: <xliff:g id="USER">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi" msgid="6099781031669728709">"<xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="NETWORK">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"Mobil <xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="TYPE">%2$s</xliff:g>. <xliff:g id="NETWORK">%3$s</xliff:g>."</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 26ae34b..ba36be6 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -147,8 +147,7 @@
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Сповіщення відхилено."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Панель сповіщень."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Швидке налаштування."</string>
-    <!-- no translation found for accessibility_desc_recent_apps (9014032916410590027) -->
-    <skip />
+    <string name="accessibility_desc_recent_apps" msgid="9014032916410590027">"Нещодавні програми."</string>
     <string name="accessibility_quick_settings_user" msgid="1104846699869476855">"Користувач <xliff:g id="USER">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi" msgid="6099781031669728709">"<xliff:g id="SIGNAL">%1$s</xliff:g>, <xliff:g id="NETWORK">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"Мобільне передавання даних: <xliff:g id="SIGNAL">%1$s</xliff:g>, <xliff:g id="TYPE">%2$s</xliff:g>, <xliff:g id="NETWORK">%3$s</xliff:g>."</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 468375f..ce90afc 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -147,8 +147,7 @@
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"Đã loại bỏ thông báo."</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"Bóng thông báo."</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"Cài đặt nhanh."</string>
-    <!-- no translation found for accessibility_desc_recent_apps (9014032916410590027) -->
-    <skip />
+    <string name="accessibility_desc_recent_apps" msgid="9014032916410590027">"Ứng dụng gần đây."</string>
     <string name="accessibility_quick_settings_user" msgid="1104846699869476855">"Người dùng <xliff:g id="USER">%s</xliff:g>."</string>
     <string name="accessibility_quick_settings_wifi" msgid="6099781031669728709">"<xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="NETWORK">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"Di động <xliff:g id="SIGNAL">%1$s</xliff:g>. <xliff:g id="TYPE">%2$s</xliff:g>. <xliff:g id="NETWORK">%3$s</xliff:g>."</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 4cfb7d0..ba0d9c8 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -149,8 +149,7 @@
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"已关闭通知。"</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"通知栏。"</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"快速设置。"</string>
-    <!-- no translation found for accessibility_desc_recent_apps (9014032916410590027) -->
-    <skip />
+    <string name="accessibility_desc_recent_apps" msgid="9014032916410590027">"最近使用的应用。"</string>
     <string name="accessibility_quick_settings_user" msgid="1104846699869476855">"用户:<xliff:g id="USER">%s</xliff:g>。"</string>
     <string name="accessibility_quick_settings_wifi" msgid="6099781031669728709">"<xliff:g id="SIGNAL">%1$s</xliff:g>,<xliff:g id="NETWORK">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"移动数据连接:<xliff:g id="SIGNAL">%1$s</xliff:g>,<xliff:g id="TYPE">%2$s</xliff:g>,<xliff:g id="NETWORK">%3$s</xliff:g>。"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index d0323f0..a77dd8c 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -149,8 +149,7 @@
     <string name="accessibility_notification_dismissed" msgid="854211387186306927">"已關閉通知。"</string>
     <string name="accessibility_desc_notification_shade" msgid="4690274844447504208">"通知欄。"</string>
     <string name="accessibility_desc_quick_settings" msgid="6186378411582437046">"快速設定。"</string>
-    <!-- no translation found for accessibility_desc_recent_apps (9014032916410590027) -->
-    <skip />
+    <string name="accessibility_desc_recent_apps" msgid="9014032916410590027">"最近使用的應用程式。"</string>
     <string name="accessibility_quick_settings_user" msgid="1104846699869476855">"使用者:<xliff:g id="USER">%s</xliff:g>。"</string>
     <string name="accessibility_quick_settings_wifi" msgid="6099781031669728709">"<xliff:g id="SIGNAL">%1$s</xliff:g>,<xliff:g id="NETWORK">%2$s</xliff:g>"</string>
     <string name="accessibility_quick_settings_mobile" msgid="4876806564086241341">"行動數據連線:<xliff:g id="SIGNAL">%1$s</xliff:g>,<xliff:g id="TYPE">%2$s</xliff:g>,<xliff:g id="NETWORK">%3$s</xliff:g>。"</string>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 4de0891..ed08115 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -201,4 +201,8 @@
 
     <!-- The size of the gesture span needed to activate the "pull" notification expansion -->
     <dimen name="pull_span_min">25dp</dimen>
+
+    <!-- How far to slide the panel out when you touch it -->
+    <!-- For phones, this is close_handle_height + header_height -->
+    <dimen name="peek_height">84dp</dimen>
 </resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 18c1c34..1a59d6c 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -16,6 +16,24 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android">
 
+    <style name="RecentsStyle" parent="@android:style/Theme.Holo.Wallpaper.NoTitleBar">
+        <item name="android:windowAnimationStyle">@style/Animation.RecentsActivity</item>
+    </style>
+
+    <!-- Animations for a non-full-screen window or activity. -->
+    <style name="Animation.RecentsActivity" parent="@android:style/Animation.Activity">
+        <item name="android:activityOpenEnterAnimation">@anim/recents_launch_from_launcher_enter</item>
+        <item name="android:activityOpenExitAnimation">@anim/recents_launch_from_launcher_exit</item>
+        <item name="android:taskOpenEnterAnimation">@anim/recents_launch_from_launcher_enter</item>
+        <item name="android:taskOpenExitAnimation">@anim/recents_launch_from_launcher_exit</item>
+        <item name="android:taskToFrontEnterAnimation">@anim/recents_launch_from_launcher_enter</item>
+        <item name="android:taskToFrontExitAnimation">@anim/recents_launch_from_launcher_exit</item>
+        <item name="android:wallpaperOpenEnterAnimation">@anim/recents_launch_from_launcher_enter</item>
+        <item name="android:wallpaperOpenExitAnimation">@anim/recents_launch_from_launcher_exit</item>
+        <item name="android:wallpaperIntraOpenEnterAnimation">@anim/wallpaper_recents_launch_from_launcher_enter</item>
+        <item name="android:wallpaperIntraOpenExitAnimation">@anim/wallpaper_recents_launch_from_launcher_exit</item>
+    </style>
+
     <style name="TextAppearance.StatusBar.IntruderAlert"
         parent="@*android:style/TextAppearance.StatusBar">
     </style>
diff --git a/packages/SystemUI/src/com/android/systemui/BootReceiver.java b/packages/SystemUI/src/com/android/systemui/BootReceiver.java
index de005aa..d3ce30d 100644
--- a/packages/SystemUI/src/com/android/systemui/BootReceiver.java
+++ b/packages/SystemUI/src/com/android/systemui/BootReceiver.java
@@ -35,7 +35,7 @@
         try {
             // Start the load average overlay, if activated
             ContentResolver res = context.getContentResolver();
-            if (Settings.System.getInt(res, Settings.System.SHOW_PROCESSES, 0) != 0) {
+            if (Settings.Global.getInt(res, Settings.Global.SHOW_PROCESSES, 0) != 0) {
                 Intent loadavg = new Intent(context, com.android.systemui.LoadAverageService.class);
                 context.startService(loadavg);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
index 6877cba..0a7dd7c 100644
--- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
@@ -31,8 +31,10 @@
 import android.renderscript.Matrix4f;
 import android.service.wallpaper.WallpaperService;
 import android.util.Log;
+import android.view.Display;
 import android.view.MotionEvent;
 import android.view.SurfaceHolder;
+import android.view.WindowManager;
 
 import javax.microedition.khronos.egl.EGL10;
 import javax.microedition.khronos.egl.EGLConfig;
@@ -107,7 +109,8 @@
         private WallpaperObserver mReceiver;
 
         Bitmap mBackground;
-        int mBackgroundWidth = -1, mBackgroundHeight = -1;
+        int mLastSurfaceWidth = -1, mLastSurfaceHeight = -1;
+        int mLastRotation = -1;
         float mXOffset;
         float mYOffset;
 
@@ -153,10 +156,10 @@
                 }
 
                 synchronized (mLock) {
-                    mBackgroundWidth = mBackgroundHeight = -1;
+                    mLastSurfaceWidth = mLastSurfaceHeight = -1;
                     mBackground = null;
                     mRedrawNeeded = true;
-                    drawFrameLocked(false);
+                    drawFrameLocked();
                 }
             }
         }
@@ -169,6 +172,9 @@
         public void trimMemory(int level) {
             if (level >= ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW &&
                     mBackground != null && mIsHwAccelerated) {
+                if (DEBUG) {
+                    Log.d(TAG, "trimMemory");
+                }
                 mBackground.recycle();
                 mBackground = null;
                 mWallpaperManager.forgetLoadedWallpaper();
@@ -225,7 +231,7 @@
         @Override
         public void onVisibilityChanged(boolean visible) {
             if (DEBUG) {
-                Log.d(TAG, "onVisibilityChanged: visible=" + visible);
+                Log.d(TAG, "onVisibilityChanged: mVisible, visible=" + mVisible + ", " + visible);
             }
 
             synchronized (mLock) {
@@ -234,7 +240,7 @@
                         Log.d(TAG, "Visibility changed to visible=" + visible);
                     }
                     mVisible = visible;
-                    drawFrameLocked(false);
+                    drawFrameLocked();
                 }
             }
         }
@@ -263,7 +269,7 @@
                     mYOffset = yOffset;
                     mOffsetsChanged = true;
                 }
-                drawFrameLocked(false);
+                drawFrameLocked();
             }
         }
 
@@ -276,80 +282,101 @@
             super.onSurfaceChanged(holder, format, width, height);
 
             synchronized (mLock) {
-                mRedrawNeeded = true;
-                mBackgroundWidth = mBackgroundHeight = -1;
-                drawFrameLocked(true);
+                drawFrameLocked();
             }
         }
 
         @Override
+        public void onSurfaceDestroyed(SurfaceHolder holder) {
+            super.onSurfaceDestroyed(holder);
+            mLastSurfaceWidth = mLastSurfaceHeight = -1;
+        }
+
+        @Override
+        public void onSurfaceCreated(SurfaceHolder holder) {
+            super.onSurfaceCreated(holder);
+            mLastSurfaceWidth = mLastSurfaceHeight = -1;
+        }
+
+        @Override
         public void onSurfaceRedrawNeeded(SurfaceHolder holder) {
             if (DEBUG) {
-                Log.d(TAG, "onSurfaceRedrawNeeded:");
+                Log.d(TAG, "onSurfaceRedrawNeeded");
             }
             super.onSurfaceRedrawNeeded(holder);
 
             synchronized (mLock) {
-                mRedrawNeeded = true;
-                drawFrameLocked(false);
+                drawFrameLocked();
             }
         }
 
-        void drawFrameLocked(boolean force) {
-            if (!force) {
-                if (!mVisible) {
-                    if (DEBUG) {
-                        Log.d(TAG, "Suppressed drawFrame since wallpaper is not visible.");
-                    }
-                    return;
-                }
-                if (!mRedrawNeeded && !mOffsetsChanged) {
-                    if (DEBUG) {
-                        Log.d(TAG, "Suppressed drawFrame since redraw is not needed "
-                                + "and offsets have not changed.");
-                    }
-                    return;
-                }
-            }
-            // If we don't yet know the size of the wallpaper bitmap,
-            // we need to get it now.
-            boolean updateWallpaper = mBackgroundWidth < 0 || mBackgroundHeight < 0 ;
-
-            // If we somehow got to this point after we have last flushed
-            // the wallpaper, well we really need it to draw again.  So
-            // seems like we need to reload it.  Ouch.
-            updateWallpaper = updateWallpaper || mBackground == null;
-
-            if (updateWallpaper) {
-                updateWallpaperLocked();
-            }
-
+        void drawFrameLocked() {
             SurfaceHolder sh = getSurfaceHolder();
             final Rect frame = sh.getSurfaceFrame();
             final int dw = frame.width();
             final int dh = frame.height();
-            final int availw = dw - mBackgroundWidth;
-            final int availh = dh - mBackgroundHeight;
+            int newRotation = ((WindowManager) getSystemService(WINDOW_SERVICE)).
+                    getDefaultDisplay().getRotation();
+            boolean surfaceDimensionsChanged = dw != mLastSurfaceWidth || dh != mLastSurfaceHeight;
+
+            boolean redrawNeeded = surfaceDimensionsChanged || newRotation != mLastRotation;
+            if (!redrawNeeded && !mOffsetsChanged) {
+                if (DEBUG) {
+                    Log.d(TAG, "Suppressed drawFrame since redraw is not needed "
+                            + "and offsets have not changed.");
+                }
+                return;
+            }
+            mLastRotation = newRotation;
+
+            // Load bitmap if it is not yet loaded or if it was loaded at a different size
+            if (mBackground == null || surfaceDimensionsChanged) {
+                if (DEBUG) {
+                    Log.d(TAG, "Reloading bitmap: mBackground, bgw, bgh, dw, dh = " +
+                            mBackground + ", " +
+                            ((mBackground == null) ? 0 : mBackground.getWidth()) + ", " +
+                            ((mBackground == null) ? 0 : mBackground.getHeight()) + ", " +
+                            dw + ", " + dh);
+                }
+                updateWallpaperLocked();
+                if (mBackground == null) {
+                    if (DEBUG) {
+                        Log.d(TAG, "Unable to load bitmap");
+                    }
+                    return;
+                }
+                if (DEBUG) {
+                    if (dw != mBackground.getWidth() || dh != mBackground.getHeight()) {
+                        Log.d(TAG, "Surface != bitmap dimensions: surface w/h, bitmap w/h: " +
+                                dw + ", " + dh + ", " + mBackground.getWidth() + ", " +
+                                mBackground.getHeight());
+                    }
+                }
+            }
+
+            final int availw = dw - mBackground.getWidth();
+            final int availh = dh - mBackground.getHeight();
             int xPixels = availw < 0 ? (int)(availw * mXOffset + .5f) : (availw / 2);
             int yPixels = availh < 0 ? (int)(availh * mYOffset + .5f) : (availh / 2);
 
             mOffsetsChanged = false;
-            if (!force && !mRedrawNeeded
-                    && xPixels == mLastXTranslation && yPixels == mLastYTranslation) {
+            mRedrawNeeded = false;
+            if (surfaceDimensionsChanged) {
+                mLastSurfaceWidth = dw;
+                mLastSurfaceHeight = dh;
+            }
+            mLastXTranslation = xPixels;
+            mLastYTranslation = yPixels;
+            if (!redrawNeeded && xPixels == mLastXTranslation && yPixels == mLastYTranslation) {
                 if (DEBUG) {
                     Log.d(TAG, "Suppressed drawFrame since the image has not "
                             + "actually moved an integral number of pixels.");
                 }
                 return;
             }
-            mRedrawNeeded = false;
-            mLastXTranslation = xPixels;
-            mLastYTranslation = yPixels;
 
             if (DEBUG) {
-                Log.d(TAG, "drawFrameUnlocked(" + force + "): mBackgroundWxH=" + mBackgroundWidth + "x"
-                        + mBackgroundHeight + " SurfaceFrame=" + frame.toShortString()
-                        + " X,YOffset=" + mXOffset + "," + mYOffset);
+                Log.d(TAG, "Redrawing wallpaper");
             }
             if (mIsHwAccelerated) {
                 if (!drawWallpaperWithOpenGL(sh, availw, availh, xPixels, yPixels)) {
@@ -370,9 +397,10 @@
 
         }
 
-        void updateWallpaperLocked() {
+        private void updateWallpaperLocked() {
             Throwable exception = null;
             try {
+                mWallpaperManager.forgetLoadedWallpaper(); // force reload
                 mBackground = mWallpaperManager.getBitmap();
             } catch (RuntimeException e) {
                 exception = e;
@@ -393,9 +421,6 @@
                     Log.w(TAG, "Unable reset to default wallpaper!", ex);
                 }
             }
-
-            mBackgroundWidth = mBackground != null ? mBackground.getWidth() : 0;
-            mBackgroundHeight = mBackground != null ? mBackground.getHeight() : 0;
         }
 
         private void drawWallpaperWithCanvas(SurfaceHolder sh, int w, int h, int x, int y) {
@@ -409,7 +434,8 @@
                     c.translate(x, y);
                     if (w < 0 || h < 0) {
                         c.save(Canvas.CLIP_SAVE_FLAG);
-                        c.clipRect(0, 0, mBackgroundWidth, mBackgroundHeight, Op.DIFFERENCE);
+                        c.clipRect(0, 0, mBackground.getWidth(), mBackground.getHeight(),
+                                Op.DIFFERENCE);
                         c.drawColor(0xff000000);
                         c.restore();
                     }
@@ -425,11 +451,10 @@
         private boolean drawWallpaperWithOpenGL(SurfaceHolder sh, int w, int h, int left, int top) {
             if (!initGL(sh)) return false;
 
-            final float right = left + mBackgroundWidth;
-            final float bottom = top + mBackgroundHeight;
+            final float right = left + mBackground.getWidth();
+            final float bottom = top + mBackground.getHeight();
 
             final Rect frame = sh.getSurfaceFrame();
-
             final Matrix4f ortho = new Matrix4f();
             ortho.loadOrtho(0.0f, frame.width(), frame.height(), 0.0f, -1.0f, 1.0f);
 
@@ -437,7 +462,7 @@
 
             final int texture = loadTexture(mBackground);
             final int program = buildProgram(sSimpleVS, sSimpleFS);
-    
+
             final int attribPosition = glGetAttribLocation(program, "position");
             final int attribTexCoords = glGetAttribLocation(program, "texCoords");
             final int uniformTexture = glGetUniformLocation(program, "texture");
@@ -460,7 +485,7 @@
                 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
                 glClear(GL_COLOR_BUFFER_BIT);
             }
-    
+
             // drawQuad
             triangleVertices.position(TRIANGLE_VERTICES_DATA_POS_OFFSET);
             glVertexAttribPointer(attribPosition, 3, GL_FLOAT, false,
@@ -471,12 +496,12 @@
                     TRIANGLE_VERTICES_DATA_STRIDE_BYTES, triangleVertices);
 
             glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
-    
+
             if (!mEgl.eglSwapBuffers(mEglDisplay, mEglSurface)) {
                 throw new RuntimeException("Cannot swap buffers");
             }
             checkEglError();
-    
+
             finishGL();
 
             return true;
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
deleted file mode 100644
index c120690..0000000
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui;
-
-import android.app.Application;
-
-import com.android.systemui.recent.RecentTasksLoader;
-import com.android.systemui.recent.RecentsActivity;
-
-public class SystemUIApplication extends Application {
-    private RecentTasksLoader mRecentTasksLoader;
-    private boolean mWaitingForWinAnimStart;
-    private RecentsActivity.WindowAnimationStartListener mWinAnimStartListener;
-
-    public RecentTasksLoader getRecentTasksLoader() {
-        if (mRecentTasksLoader == null) {
-            mRecentTasksLoader = new RecentTasksLoader(this);
-        }
-        return mRecentTasksLoader;
-    }
-
-    public void setWaitingForWinAnimStart(boolean waiting) {
-        mWaitingForWinAnimStart = waiting;
-    }
-
-    public void setWindowAnimationStartListener(
-            RecentsActivity.WindowAnimationStartListener startListener) {
-        mWinAnimStartListener = startListener;
-    }
-
-    public RecentsActivity.WindowAnimationStartListener getWindowAnimationListener() {
-        return mWinAnimStartListener;
-    }
-
-    public void onWindowAnimationStart() {
-        if (mWinAnimStartListener != null) {
-            mWinAnimStartListener.onWindowAnimationStart();
-        }
-        mWaitingForWinAnimStart = false;
-    }
-
-    public boolean isWaitingForWindowAnimationStart() {
-        return mWaitingForWinAnimStart;
-    }
-}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index 07fd0ab..318448e 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -237,9 +237,9 @@
         }
 
         final ContentResolver cr = mContext.getContentResolver();
-        if (Settings.System.getInt(cr, Settings.System.POWER_SOUNDS_ENABLED, 1) == 1) {
-            final String soundPath = Settings.System.getString(cr,
-                    Settings.System.LOW_BATTERY_SOUND);
+        if (Settings.Global.getInt(cr, Settings.Global.POWER_SOUNDS_ENABLED, 1) == 1) {
+            final String soundPath = Settings.Global.getString(cr,
+                    Settings.Global.LOW_BATTERY_SOUND);
             if (soundPath != null) {
                 final Uri soundUri = Uri.parse("file://" + soundPath);
                 if (soundUri != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java b/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
index 7260844..9d6765a 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentTasksLoader.java
@@ -30,6 +30,7 @@
 import android.os.AsyncTask;
 import android.os.Handler;
 import android.os.Process;
+import android.os.UserHandle;
 import android.util.Log;
 import android.view.MotionEvent;
 import android.view.View;
@@ -52,6 +53,8 @@
 
     private Context mContext;
     private RecentsPanelView mRecentsPanel;
+
+    private Object mFirstTaskLock = new Object();
     private TaskDescription mFirstTask;
     private boolean mFirstTaskLoaded;
 
@@ -70,23 +73,16 @@
     private enum State { LOADING, LOADED, CANCELLED };
     private State mState = State.CANCELLED;
 
-    public TaskDescription getFirstTask() {
-        while (!mFirstTaskLoaded) {
-            if (mState == State.CANCELLED) {
-                loadTasksInBackground();
-            }
-            try {
-                if (mState == State.LOADED) {
-                    break;
-                }
-                Thread.sleep(5);
-            } catch (InterruptedException e) {
-            }
+
+    private static RecentTasksLoader sInstance;
+    public static RecentTasksLoader getInstance(Context context) {
+        if (sInstance == null) {
+            sInstance = new RecentTasksLoader(context);
         }
-        return mFirstTask;
+        return sInstance;
     }
 
-    public RecentTasksLoader(Context context) {
+    private RecentTasksLoader(Context context) {
         mContext = context;
         mHandler = new Handler();
 
@@ -295,8 +291,6 @@
             mThumbnailLoader = null;
         }
         mLoadedTasks = null;
-        mFirstTask = null;
-        mFirstTaskLoaded = false;
         if (mRecentsPanel != null) {
             mRecentsPanel.onTaskLoadingCancelled();
         }
@@ -304,6 +298,100 @@
         mState = State.CANCELLED;
     }
 
+    private void clearFirstTask() {
+        synchronized (mFirstTaskLock) {
+            mFirstTask = null;
+            mFirstTaskLoaded = false;
+        }
+    }
+
+    public void preloadFirstTask() {
+        Thread bgLoad = new Thread() {
+            public void run() {
+                TaskDescription first = loadFirstTask();
+                synchronized(mFirstTaskLock) {
+                    if (mCancelPreloadingFirstTask) {
+                        clearFirstTask();
+                    } else {
+                        mFirstTask = first;
+                        mFirstTaskLoaded = true;
+                    }
+                    mPreloadingFirstTask = false;
+                }
+            }
+        };
+        synchronized(mFirstTaskLock) {
+            if (!mPreloadingFirstTask) {
+                clearFirstTask();
+                mPreloadingFirstTask = true;
+                bgLoad.start();
+            }
+        }
+    }
+
+    public void cancelPreloadingFirstTask() {
+        synchronized(mFirstTaskLock) {
+            if (mPreloadingFirstTask) {
+                mCancelPreloadingFirstTask = true;
+            } else {
+                clearFirstTask();
+            }
+        }
+    }
+
+    boolean mPreloadingFirstTask;
+    boolean mCancelPreloadingFirstTask;
+    public TaskDescription getFirstTask() {
+        while(true) {
+            synchronized(mFirstTaskLock) {
+                if (mFirstTaskLoaded) {
+                    return mFirstTask;
+                } else if (!mFirstTaskLoaded && !mPreloadingFirstTask) {
+                    mFirstTask = loadFirstTask();
+                    mFirstTaskLoaded = true;
+                    return mFirstTask;
+                }
+            }
+            try {
+                Thread.sleep(3);
+            } catch (InterruptedException e) {
+            }
+        }
+    }
+
+    public TaskDescription loadFirstTask() {
+        final ActivityManager am = (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE);
+
+        final List<ActivityManager.RecentTaskInfo> recentTasks = am.getRecentTasksForUser(
+                1, ActivityManager.RECENT_IGNORE_UNAVAILABLE, UserHandle.CURRENT.getIdentifier());
+        TaskDescription item = null;
+        if (recentTasks.size() > 0) {
+            ActivityManager.RecentTaskInfo recentInfo = recentTasks.get(0);
+
+            Intent intent = new Intent(recentInfo.baseIntent);
+            if (recentInfo.origActivity != null) {
+                intent.setComponent(recentInfo.origActivity);
+            }
+
+            // Don't load the current home activity.
+            if (isCurrentHomeActivity(intent.getComponent(), null)) {
+                return null;
+            }
+
+            // Don't load ourselves
+            if (intent.getComponent().getPackageName().equals(mContext.getPackageName())) {
+                return null;
+            }
+
+            item = createTaskDescription(recentInfo.id,
+                    recentInfo.persistentId, recentInfo.baseIntent,
+                    recentInfo.origActivity, recentInfo.description);
+            loadThumbnailAndIcon(item);
+            return item;
+        }
+        return null;
+    }
+
     public void loadTasksInBackground() {
         loadTasksInBackground(false);
     }
@@ -367,9 +455,6 @@
 
                     // Don't load the current home activity.
                     if (isCurrentHomeActivity(intent.getComponent(), homeInfo)) {
-                        if (index == 0) {
-                            mFirstTaskLoaded = true;
-                        }
                         continue;
                     }
 
@@ -466,10 +551,6 @@
                     }
                     loadThumbnailAndIcon(td);
 
-                    if (!mFirstTaskLoaded) {
-                        mFirstTask = td;
-                        mFirstTaskLoaded = true;
-                    }
                     publishProgress(td);
                 }
 
@@ -477,8 +558,6 @@
                 return null;
             }
         };
-        mFirstTask = null;
-        mFirstTaskLoaded = false;
         mThumbnailLoader.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsActivity.java
index ef9f36e..676326a 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsActivity.java
@@ -30,14 +30,18 @@
 import android.view.WindowManager;
 
 import com.android.systemui.R;
-import com.android.systemui.SystemUIApplication;
 import com.android.systemui.statusbar.tablet.StatusBarPanel;
 
 import java.util.List;
 
 public class RecentsActivity extends Activity {
-    public static final String TOGGLE_RECENTS_INTENT = "com.android.systemui.TOGGLE_RECENTS";
-    public static final String CLOSE_RECENTS_INTENT = "com.android.systemui.CLOSE_RECENTS";
+    public static final String TOGGLE_RECENTS_INTENT = "com.android.systemui.recent.action.TOGGLE_RECENTS";
+    public static final String PRELOAD_INTENT = "com.android.systemui.recent.action.PRELOAD";
+    public static final String CANCEL_PRELOAD_INTENT = "com.android.systemui.recent.CANCEL_PRELOAD";
+    public static final String CLOSE_RECENTS_INTENT = "com.android.systemui.recent.action.CLOSE";
+    public static final String WINDOW_ANIMATION_START_INTENT = "com.android.systemui.recent.action.WINDOW_ANIMATION_START";
+    public static final String PRELOAD_PERMISSION = "com.android.systemui.recent.permission.PRELOAD";
+    public static final String WAITING_FOR_WINDOW_ANIMATION_PARAM = "com.android.systemui.recent.WAITING_FOR_WINDOW_ANIMATION";
     private static final String WAS_SHOWING = "was_showing";
 
     private RecentsPanelView mRecentsPanel;
@@ -48,19 +52,21 @@
     private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
-            if (mRecentsPanel != null && mRecentsPanel.isShowing()) {
-                if (mShowing && !mForeground) {
-                    // Captures the case right before we transition to another activity
-                    mRecentsPanel.show(false);
+            if (CLOSE_RECENTS_INTENT.equals(intent.getAction())) {
+                if (mRecentsPanel != null && mRecentsPanel.isShowing()) {
+                    if (mShowing && !mForeground) {
+                        // Captures the case right before we transition to another activity
+                        mRecentsPanel.show(false);
+                    }
+                }
+            } else if (WINDOW_ANIMATION_START_INTENT.equals(intent.getAction())) {
+                if (mRecentsPanel != null) {
+                    mRecentsPanel.onWindowAnimationStart();
                 }
             }
         }
     };
 
-    public static interface WindowAnimationStartListener {
-        void onWindowAnimationStart();
-    }
-
     public class TouchOutsideListener implements View.OnTouchListener {
         private StatusBarPanel mPanel;
 
@@ -107,10 +113,14 @@
         }
     }
 
+    public static boolean forceOpaqueBackground(Context context) {
+        return WallpaperManager.getInstance(context).getWallpaperInfo() != null;
+    }
+
     @Override
     public void onStart() {
         // Hide wallpaper if it's not a static image
-        if (WallpaperManager.getInstance(this).getWallpaperInfo() != null) {
+        if (forceOpaqueBackground(this)) {
             updateWallpaperVisibility(false);
         } else {
             updateWallpaperVisibility(true);
@@ -164,25 +174,23 @@
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
-        final SystemUIApplication app = (SystemUIApplication) getApplication();
-        final RecentTasksLoader recentTasksLoader = app.getRecentTasksLoader();
-
         setContentView(R.layout.status_bar_recent_panel);
         mRecentsPanel = (RecentsPanelView) findViewById(R.id.recents_root);
         mRecentsPanel.setOnTouchListener(new TouchOutsideListener(mRecentsPanel));
-        mRecentsPanel.setRecentTasksLoader(recentTasksLoader);
+
+        final RecentTasksLoader recentTasksLoader = RecentTasksLoader.getInstance(this);
         recentTasksLoader.setRecentsPanel(mRecentsPanel, mRecentsPanel);
         mRecentsPanel.setMinSwipeAlpha(
                 getResources().getInteger(R.integer.config_recent_item_min_alpha) / 100f);
 
         if (savedInstanceState == null ||
                 savedInstanceState.getBoolean(WAS_SHOWING)) {
-            handleIntent(getIntent());
+            handleIntent(getIntent(), (savedInstanceState == null));
         }
         mIntentFilter = new IntentFilter();
         mIntentFilter.addAction(CLOSE_RECENTS_INTENT);
+        mIntentFilter.addAction(WINDOW_ANIMATION_START_INTENT);
         registerReceiver(mIntentReceiver, mIntentFilter);
-        app.setWindowAnimationStartListener(mRecentsPanel);
         super.onCreate(savedInstanceState);
     }
 
@@ -193,20 +201,17 @@
 
     @Override
     protected void onDestroy() {
-        final SystemUIApplication app = (SystemUIApplication) getApplication();
-        final RecentTasksLoader recentTasksLoader = app.getRecentTasksLoader();
-        recentTasksLoader.setRecentsPanel(null, mRecentsPanel);
+        RecentTasksLoader.getInstance(this).setRecentsPanel(null, mRecentsPanel);
         unregisterReceiver(mIntentReceiver);
-        app.setWindowAnimationStartListener(null);
         super.onDestroy();
     }
 
     @Override
     protected void onNewIntent(Intent intent) {
-        handleIntent(intent);
+        handleIntent(intent, true);
     }
 
-    private void handleIntent(Intent intent) {
+    private void handleIntent(Intent intent, boolean checkWaitingForAnimationParam) {
         super.onNewIntent(intent);
 
         if (TOGGLE_RECENTS_INTENT.equals(intent.getAction())) {
@@ -214,10 +219,11 @@
                 if (mRecentsPanel.isShowing()) {
                     dismissAndGoBack();
                 } else {
-                    final SystemUIApplication app = (SystemUIApplication) getApplication();
-                    final RecentTasksLoader recentTasksLoader = app.getRecentTasksLoader();
+                    final RecentTasksLoader recentTasksLoader = RecentTasksLoader.getInstance(this);
+                    boolean waitingForWindowAnimation = checkWaitingForAnimationParam &&
+                            intent.getBooleanExtra(WAITING_FOR_WINDOW_ANIMATION_PARAM, false);
                     mRecentsPanel.show(true, recentTasksLoader.getLoadedTasks(),
-                            recentTasksLoader.isFirstScreenful());
+                            recentTasksLoader.isFirstScreenful(), waitingForWindowAnimation);
                 }
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index 57d2ed3..2008d0e 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -59,7 +59,6 @@
 import android.widget.TextView;
 
 import com.android.systemui.R;
-import com.android.systemui.SystemUIApplication;
 import com.android.systemui.statusbar.BaseStatusBar;
 import com.android.systemui.statusbar.phone.PhoneStatusBar;
 import com.android.systemui.statusbar.tablet.StatusBarPanel;
@@ -68,7 +67,7 @@
 import java.util.ArrayList;
 
 public class RecentsPanelView extends FrameLayout implements OnItemClickListener, RecentsCallback,
-        StatusBarPanel, Animator.AnimatorListener, RecentsActivity.WindowAnimationStartListener {
+        StatusBarPanel, Animator.AnimatorListener {
     static final String TAG = "RecentsPanelView";
     static final boolean DEBUG = TabletStatusBar.DEBUG || PhoneStatusBar.DEBUG || false;
     private PopupMenu mPopup;
@@ -81,6 +80,7 @@
     private boolean mWaitingToShow;
     private int mNumItemsWaitingForThumbnailsAndIcons;
     private ViewHolder mItemToAnimateInWhenWindowAnimationIsFinished;
+    private boolean mWaitingForWindowAnimation;
 
     private RecentTasksLoader mRecentTasksLoader;
     private ArrayList<TaskDescription> mRecentTaskDescriptions;
@@ -147,13 +147,9 @@
                     (ImageView) convertView.findViewById(R.id.app_thumbnail_image);
             // If we set the default thumbnail now, we avoid an onLayout when we update
             // the thumbnail later (if they both have the same dimensions)
-            if (mRecentTasksLoader != null) {
-                updateThumbnail(holder, mRecentTasksLoader.getDefaultThumbnail(), false, false);
-            }
+            updateThumbnail(holder, mRecentTasksLoader.getDefaultThumbnail(), false, false);
             holder.iconView = (ImageView) convertView.findViewById(R.id.app_icon);
-            if (mRecentTasksLoader != null) {
-                holder.iconView.setImageBitmap(mRecentTasksLoader.getDefaultIcon());
-            }
+            holder.iconView.setImageBitmap(mRecentTasksLoader.getDefaultIcon());
             holder.labelView = (TextView) convertView.findViewById(R.id.app_label);
             holder.calloutLine = convertView.findViewById(R.id.recents_callout_line);
             holder.descriptionView = (TextView) convertView.findViewById(R.id.app_description);
@@ -183,8 +179,17 @@
             }
             if (index == 0) {
                 final Activity activity = (Activity) RecentsPanelView.this.getContext();
-                final SystemUIApplication app = (SystemUIApplication) activity.getApplication();
-                if (app.isWaitingForWindowAnimationStart()) {
+                if (mWaitingForWindowAnimation) {
+                    if (mItemToAnimateInWhenWindowAnimationIsFinished != null) {
+                        for (View v :
+                            new View[] { holder.iconView, holder.labelView, holder.calloutLine }) {
+                            if (v != null) {
+                                v.setAlpha(1f);
+                                v.setTranslationX(0f);
+                                v.setTranslationY(0f);
+                            }
+                        }
+                    }
                     mItemToAnimateInWhenWindowAnimationIsFinished = holder;
                     final int translation = -getResources().getDimensionPixelSize(
                             R.dimen.status_bar_recents_app_icon_translate_distance);
@@ -237,6 +242,7 @@
                 defStyle, 0);
 
         mRecentItemLayoutId = a.getResourceId(R.styleable.RecentsPanelView_recentItemLayout, 0);
+        mRecentTasksLoader = RecentTasksLoader.getInstance(context);
         a.recycle();
     }
 
@@ -270,11 +276,12 @@
     }
 
     public void show(boolean show) {
-        show(show, null, false);
+        show(show, null, false, false);
     }
 
     public void show(boolean show, ArrayList<TaskDescription> recentTaskDescriptions,
-            boolean firstScreenful) {
+            boolean firstScreenful, boolean waitingForWindowAnimation) {
+        mWaitingForWindowAnimation = waitingForWindowAnimation;
         if (show) {
             mWaitingToShow = true;
             refreshRecentTasksList(recentTaskDescriptions, firstScreenful);
@@ -532,6 +539,7 @@
                 }
             }
             mItemToAnimateInWhenWindowAnimationIsFinished = null;
+            mWaitingForWindowAnimation = false;
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPreloadReceiver.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPreloadReceiver.java
new file mode 100644
index 0000000..eb5892007
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPreloadReceiver.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recent;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+public class RecentsPreloadReceiver extends BroadcastReceiver {
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        if (RecentsActivity.PRELOAD_INTENT.equals(intent.getAction())) {
+            RecentTasksLoader.getInstance(context).preloadRecentTasksList();
+        } else if (RecentsActivity.CANCEL_PRELOAD_INTENT.equals(intent.getAction())){
+            RecentTasksLoader.getInstance(context).cancelPreloadingRecentTasksList();
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 577b1f4..fe33b02 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -25,7 +25,6 @@
 import com.android.systemui.R;
 import com.android.systemui.SearchPanelView;
 import com.android.systemui.SystemUI;
-import com.android.systemui.SystemUIApplication;
 import com.android.systemui.recent.RecentTasksLoader;
 import com.android.systemui.recent.RecentsActivity;
 import com.android.systemui.recent.TaskDescription;
@@ -37,7 +36,6 @@
 import android.app.ActivityOptions;
 import android.app.KeyguardManager;
 import android.app.PendingIntent;
-import android.app.Service;
 import android.app.TaskStackBuilder;
 import android.content.ActivityNotFoundException;
 import android.content.BroadcastReceiver;
@@ -72,9 +70,9 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.WindowManagerGlobal;
 import android.view.ViewGroup.LayoutParams;
 import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 import android.widget.PopupMenu;
@@ -428,10 +426,6 @@
     protected abstract WindowManager.LayoutParams getSearchLayoutParams(
             LayoutParams layoutParams);
 
-    protected RecentTasksLoader getRecentTasksLoader() {
-        final SystemUIApplication app = (SystemUIApplication) ((Service) mContext).getApplication();
-        return app.getRecentTasksLoader();
-    }
 
     protected void updateSearchPanel() {
         // Search Panel
@@ -475,8 +469,8 @@
 
     protected void toggleRecentsActivity() {
         try {
-            final RecentTasksLoader recentTasksLoader = getRecentTasksLoader();
-            TaskDescription firstTask = recentTasksLoader.getFirstTask();
+
+            TaskDescription firstTask = RecentTasksLoader.getInstance(mContext).getFirstTask();
 
             Intent intent = new Intent(RecentsActivity.TOGGLE_RECENTS_INTENT);
             intent.setClassName("com.android.systemui",
@@ -485,11 +479,18 @@
                     | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
 
             if (firstTask == null) {
-                ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext,
-                        R.anim.recents_launch_from_launcher_enter,
-                        R.anim.recents_launch_from_launcher_exit);
-                mContext.startActivityAsUser(intent, opts.toBundle(), new UserHandle(
-                        UserHandle.USER_CURRENT));
+                if (RecentsActivity.forceOpaqueBackground(mContext)) {
+                    ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext,
+                            R.anim.recents_launch_from_launcher_enter,
+                            R.anim.recents_launch_from_launcher_exit);
+                    mContext.startActivityAsUser(intent, opts.toBundle(), new UserHandle(
+                            UserHandle.USER_CURRENT));
+                } else {
+                    // The correct window animation will be applied via the activity's style
+                    mContext.startActivityAsUser(intent, new UserHandle(
+                            UserHandle.USER_CURRENT));
+                }
+
             } else {
                 Bitmap first = firstTask.getThumbnail();
                 final Resources res = mContext.getResources();
@@ -576,17 +577,17 @@
                             + recentsItemTopPadding + thumbBgPadding + statusBarHeight);
                 }
 
-                final SystemUIApplication app =
-                        (SystemUIApplication) ((Service) mContext).getApplication();
-                app.setWaitingForWinAnimStart(true);
                 ActivityOptions opts = ActivityOptions.makeThumbnailScaleDownAnimation(
                         getStatusBarView(),
                         first, x, y,
                         new ActivityOptions.OnAnimationStartedListener() {
                             public void onAnimationStarted() {
-                                app.onWindowAnimationStart();
+                                Intent intent = new Intent(RecentsActivity.WINDOW_ANIMATION_START_INTENT);
+                                intent.setPackage("com.android.systemui");
+                                mContext.sendBroadcastAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
                             }
                         });
+                intent.putExtra(RecentsActivity.WAITING_FOR_WINDOW_ANIMATION_PARAM, true);
                 mContext.startActivityAsUser(intent, opts.toBundle(), new UserHandle(
                         UserHandle.USER_CURRENT));
             }
@@ -596,8 +597,49 @@
         }
     }
 
+    protected View.OnTouchListener mRecentsPreloadOnTouchListener = new View.OnTouchListener() {
+        // additional optimization when we have software system buttons - start loading the recent
+        // tasks on touch down
+        @Override
+        public boolean onTouch(View v, MotionEvent event) {
+            int action = event.getAction() & MotionEvent.ACTION_MASK;
+            if (action == MotionEvent.ACTION_DOWN) {
+                preloadRecentTasksList();
+            } else if (action == MotionEvent.ACTION_CANCEL) {
+                cancelPreloadingRecentTasksList();
+            } else if (action == MotionEvent.ACTION_UP) {
+                if (!v.isPressed()) {
+                    cancelPreloadingRecentTasksList();
+                }
+
+            }
+            return false;
+        }
+    };
+
+    protected void preloadRecentTasksList() {
+        if (DEBUG) Slog.d(TAG, "preloading recents");
+        Intent intent = new Intent(RecentsActivity.PRELOAD_INTENT);
+        intent.setClassName("com.android.systemui",
+                "com.android.systemui.recent.RecentsPreloadReceiver");
+        mContext.sendBroadcastAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
+
+        RecentTasksLoader.getInstance(mContext).preloadFirstTask();
+    }
+
+    protected void cancelPreloadingRecentTasksList() {
+        if (DEBUG) Slog.d(TAG, "cancel preloading recents");
+        Intent intent = new Intent(RecentsActivity.CANCEL_PRELOAD_INTENT);
+        intent.setClassName("com.android.systemui",
+                "com.android.systemui.recent.RecentsPreloadReceiver");
+        mContext.sendBroadcastAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
+
+        RecentTasksLoader.getInstance(mContext).cancelPreloadingFirstTask();
+    }
+
     protected class H extends Handler {
         public void handleMessage(Message m) {
+            Intent intent;
             switch (m.what) {
              case MSG_TOGGLE_RECENTS_PANEL:
                  if (DEBUG) Slog.d(TAG, "toggle recents panel");
@@ -605,17 +647,15 @@
                  break;
              case MSG_CLOSE_RECENTS_PANEL:
                  if (DEBUG) Slog.d(TAG, "closing recents panel");
-                 Intent intent = new Intent(RecentsActivity.CLOSE_RECENTS_INTENT);
+                 intent = new Intent(RecentsActivity.CLOSE_RECENTS_INTENT);
                  intent.setPackage("com.android.systemui");
                  mContext.sendBroadcastAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
                  break;
              case MSG_PRELOAD_RECENT_APPS:
-                  if (DEBUG) Slog.d(TAG, "preloading recents");
-                  getRecentTasksLoader().preloadRecentTasksList();
+                  preloadRecentTasksList();
                   break;
              case MSG_CANCEL_PRELOAD_RECENT_APPS:
-                  if (DEBUG) Slog.d(TAG, "cancel preloading recents");
-                  getRecentTasksLoader().cancelPreloadingRecentTasksList();
+                  cancelPreloadingRecentTasksList();
                   break;
              case MSG_OPEN_SEARCH_PANEL:
                  if (DEBUG) Slog.d(TAG, "opening search panel");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index c832fb8..248a516 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -21,6 +21,8 @@
 import android.graphics.Canvas;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
+import android.util.Slog;
+import android.view.MotionEvent;
 import android.view.View;
 
 import com.android.systemui.R;
@@ -31,11 +33,18 @@
     Drawable mHandleBar;
     float mHandleBarHeight;
     View mHandleView;
+    int mFingers;
+    PhoneStatusBar mStatusBar;
+    boolean mOkToFlip;
 
     public NotificationPanelView(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
 
+    public void setStatusBar(PhoneStatusBar bar) {
+        mStatusBar = bar;
+    }
+
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
@@ -79,4 +88,35 @@
         mHandleBar.draw(canvas);
         canvas.translate(0, -off);
     }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        if (PhoneStatusBar.SETTINGS_DRAG_SHORTCUT && mStatusBar.mHasFlipSettings) {
+            switch (event.getActionMasked()) {
+                case MotionEvent.ACTION_DOWN:
+                    mOkToFlip = getExpandedHeight() == 0;
+                    break;
+                case MotionEvent.ACTION_POINTER_DOWN:
+                    if (mOkToFlip) {
+                        float miny = event.getY(0);
+                        float maxy = miny;
+                        for (int i=1; i<event.getPointerCount(); i++) {
+                            final float y = event.getY(i);
+                            if (y < miny) miny = y;
+                            if (y > maxy) maxy = y;
+                        }
+                        if (maxy - miny < mHandleBarHeight) {
+                            if (getMeasuredHeight() < mHandleBarHeight) {
+                                mStatusBar.switchToSettings();
+                            } else {
+                                mStatusBar.flipToSettings();
+                            }
+                            mOkToFlip = false;
+                        }
+                    }
+                    break;
+            }
+        }
+        return mHandleView.dispatchTouchEvent(event);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
index d0fc340..c9a137c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelBar.java
@@ -102,7 +102,7 @@
             startOpeningPanel(panel);
         }
         final boolean result = mTouchingPanel != null
-                ? mTouchingPanel.getHandle().dispatchTouchEvent(event)
+                ? mTouchingPanel.onTouchEvent(event)
                 : true;
         return result;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index 7eb84e1..6184e30 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -98,7 +98,7 @@
         if (mPeekAnimator == null) {
             mPeekAnimator = ObjectAnimator.ofFloat(this, 
                     "expandedHeight", mPeekHeight)
-                .setDuration(300);
+                .setDuration(250);
         }
         mPeekAnimator.start();
     }
@@ -206,7 +206,7 @@
 
         mFlingGestureMaxOutputVelocityPx = res.getDimension(R.dimen.fling_gesture_max_output_velocity);
 
-        mPeekHeight = res.getDimension(R.dimen.close_handle_height) 
+        mPeekHeight = res.getDimension(R.dimen.peek_height) 
             + getPaddingBottom() // our window might have a dropshadow
             - (mHandleView == null ? 0 : mHandleView.getPaddingTop()); // the handle might have a topshadow
     }
@@ -250,6 +250,7 @@
                         case MotionEvent.ACTION_DOWN:
                             mTracking = true;
                             mHandleView.setPressed(true);
+                            postInvalidate(); // catch the press state change
                             mInitialTouchY = y;
                             mVelocityTracker = VelocityTracker.obtain();
                             trackMovement(event);
@@ -283,6 +284,7 @@
                             mFinalTouchY = y;
                             mTracking = false;
                             mHandleView.setPressed(false);
+                            postInvalidate(); // catch the press state change
                             mBar.onTrackingStopped(PanelView.this);
                             trackMovement(event);
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 64bce22..5bb9378 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -40,7 +40,6 @@
 import android.graphics.PorterDuff;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
-import android.graphics.drawable.NinePatchDrawable;
 import android.inputmethodservice.InputMethodService;
 import android.os.Handler;
 import android.os.IBinder;
@@ -110,6 +109,8 @@
 
     public static final boolean ENABLE_NOTIFICATION_PANEL_CLING = false;
 
+    public static final boolean SETTINGS_DRAG_SHORTCUT = true;
+
     // additional instrumentation for testing purposes; intended to be left on during development
     public static final boolean CHATTY = DEBUG;
 
@@ -180,7 +181,7 @@
     View mMoreIcon;
 
     // expanded notifications
-    PanelView mNotificationPanel; // the sliding/resizing panel within the notification window
+    NotificationPanelView mNotificationPanel; // the sliding/resizing panel within the notification window
     ScrollView mScrollView;
     View mExpandedContents;
     int mNotificationPanelGravity;
@@ -198,6 +199,8 @@
     int mSettingsPanelGravity;
 
     // top bar
+    View mNotificationPanelHeader;
+    View mDateTimeView; 
     View mClearButton;
     ImageView mSettingsButton, mNotificationButton;
 
@@ -295,7 +298,7 @@
             if (MULTIUSER_DEBUG) Slog.d(TAG, String.format("User setup changed: " +
                     "selfChange=%s userSetup=%s mUserSetup=%s",
                     selfChange, userSetup, mUserSetup));
-            if (mSettingsButton != null) {
+            if (mSettingsButton != null && !mHasSettingsPanel) {
                 mSettingsButton.setVisibility(userSetup ? View.VISIBLE : View.INVISIBLE);
             }
             if (mSettingsPanel != null) {
@@ -361,7 +364,8 @@
         PanelHolder holder = (PanelHolder) mStatusBarWindow.findViewById(R.id.panel_holder);
         mStatusBarView.setPanelHolder(holder);
 
-        mNotificationPanel = (PanelView) mStatusBarWindow.findViewById(R.id.notification_panel);
+        mNotificationPanel = (NotificationPanelView) mStatusBarWindow.findViewById(R.id.notification_panel);
+        mNotificationPanel.setStatusBar(this);
         mNotificationPanelIsFullScreenWidth =
             (mNotificationPanel.getLayoutParams().width == ViewGroup.LayoutParams.MATCH_PARENT);
 
@@ -420,6 +424,8 @@
         mPile.setLongPressListener(getNotificationLongClicker());
         mExpandedContents = mPile; // was: expanded.findViewById(R.id.notificationLinearLayout);
 
+        mNotificationPanelHeader = mStatusBarWindow.findViewById(R.id.header);
+
         mClearButton = mStatusBarWindow.findViewById(R.id.clear_all_button);
         mClearButton.setOnClickListener(mClearButtonListener);
         mClearButton.setAlpha(0f);
@@ -430,6 +436,12 @@
         mHasSettingsPanel = res.getBoolean(R.bool.config_hasSettingsPanel);
         mHasFlipSettings = res.getBoolean(R.bool.config_hasFlipSettingsPanel);
 
+        mDateTimeView = mNotificationPanelHeader.findViewById(R.id.datetime);
+        if (mHasFlipSettings) {
+            mDateTimeView.setOnClickListener(mClockClickListener);
+            mDateTimeView.setEnabled(true);
+        }
+
         mSettingsButton = (ImageView) mStatusBarWindow.findViewById(R.id.settings_button);
         if (mSettingsButton != null) {
             mSettingsButton.setOnClickListener(mSettingsButtonListener);
@@ -457,10 +469,12 @@
 
         mScrollView = (ScrollView)mStatusBarWindow.findViewById(R.id.scroll);
         mScrollView.setVerticalScrollBarEnabled(false); // less drawing during pulldowns
-        mScrollView.setSystemUiVisibility(
-                View.STATUS_BAR_DISABLE_NOTIFICATION_TICKER |
-                View.STATUS_BAR_DISABLE_NOTIFICATION_ICONS |
-                View.STATUS_BAR_DISABLE_CLOCK);
+        if (!mNotificationPanelIsFullScreenWidth) {
+            mScrollView.setSystemUiVisibility(
+                    View.STATUS_BAR_DISABLE_NOTIFICATION_TICKER |
+                    View.STATUS_BAR_DISABLE_NOTIFICATION_ICONS |
+                    View.STATUS_BAR_DISABLE_CLOCK);
+        }
 
         mTicker = new MyTicker(context, mStatusBarView);
 
@@ -488,6 +502,8 @@
         mEmergencyCallLabel = (TextView)mStatusBarWindow.findViewById(R.id.emergency_calls_only);
         if (mEmergencyCallLabel != null) {
             mNetworkController.addEmergencyLabelView(mEmergencyCallLabel);
+            mEmergencyCallLabel.setOnClickListener(new View.OnClickListener() {
+                public void onClick(View v) { }});
             mEmergencyCallLabel.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
                 @Override
                 public void onLayoutChange(View v, int left, int top, int right, int bottom,
@@ -541,8 +557,6 @@
                 }
 
                 if (mSettingsPanel != null) {
-                    mSettingsPanel.setBar(mStatusBarView);
-                    
                     if (!ActivityManager.isHighEndGfx()) {
                         mSettingsPanel.setBackground(new FastColorDrawable(context.getResources().getColor(
                                 R.color.notification_panel_solid_background)));
@@ -555,14 +569,16 @@
                     mStatusBarWindow.findViewById(R.id.quick_settings_container);
             if (mSettingsContainer != null) {
                 mQS = new QuickSettings(mContext, mSettingsContainer);
-                mSettingsContainer.setSystemUiVisibility(
-                        View.STATUS_BAR_DISABLE_NOTIFICATION_TICKER
-                        | View.STATUS_BAR_DISABLE_SYSTEM_INFO);
-
+                if (!mNotificationPanelIsFullScreenWidth) {
+                    mSettingsContainer.setSystemUiVisibility(
+                            View.STATUS_BAR_DISABLE_NOTIFICATION_TICKER
+                            | View.STATUS_BAR_DISABLE_SYSTEM_INFO);
+                }
                 if (mSettingsPanel != null) {
                     mSettingsPanel.setQuickSettings(mQS);
                 }
                 mQS.setService(this);
+                mQS.setBar(mStatusBarView);
                 mQS.setup(mNetworkController, mBluetoothController, mBatteryController,
                         mLocationController);
             } else {
@@ -736,7 +752,7 @@
         mNavigationBarView.reorient();
 
         mNavigationBarView.getRecentsButton().setOnClickListener(mRecentsClickListener);
-        mNavigationBarView.getRecentsButton().setOnTouchListener(getRecentTasksLoader());
+        mNavigationBarView.getRecentsButton().setOnTouchListener(mRecentsPreloadOnTouchListener);
         mNavigationBarView.getHomeButton().setOnTouchListener(mHomeSearchActionListener);
         updateSearchPanel();
     }
@@ -1065,7 +1081,13 @@
                     + " any=" + any + " clearable=" + clearable);
         }
 
-        if (mClearButton.isShown()) {
+        if (mHasFlipSettings 
+                && mFlipSettingsView != null 
+                && mFlipSettingsView.getVisibility() == View.VISIBLE
+                && mScrollView.getVisibility() != View.VISIBLE) {
+            // the flip settings panel is unequivocally showing; we should not be shown
+            mClearButton.setVisibility(View.INVISIBLE);
+        } else if (mClearButton.isShown()) {
             if (clearable != (mClearButton.getAlpha() == 1.0f)) {
                 ObjectAnimator clearAnimation = ObjectAnimator.ofFloat(
                         mClearButton, "alpha", clearable ? 1.0f : 0.0f).setDuration(250);
@@ -1266,6 +1288,10 @@
         }
     }
 
+    public Handler getHandler() {
+        return mHandler;
+    }
+
     View.OnFocusChangeListener mFocusChangeListener = new View.OnFocusChangeListener() {
         public void onFocusChange(View v, boolean hasFocus) {
             // Because 'v' is a ViewGroup, all its children will be (un)selected
@@ -1280,17 +1306,6 @@
             return;
         }
 
-        if (mHasFlipSettings && !mExpandedVisible) {
-            // reset things to their proper state
-            mScrollView.setScaleX(1f);
-            mScrollView.setVisibility(View.VISIBLE);
-            mSettingsButton.setAlpha(1f);
-            mSettingsButton.setVisibility(View.VISIBLE);
-            mNotificationPanel.setVisibility(View.GONE);
-            mFlipSettingsView.setVisibility(View.GONE);
-            mNotificationButton.setVisibility(View.GONE);
-        }
-
         mExpandedVisible = true;
         mPile.setLayoutTransitionsEnabled(true);
         if (mNavigationBarView != null)
@@ -1400,51 +1415,53 @@
         }
 
         mNotificationPanel.expand();
-        if (mHasFlipSettings) {
-            if (mScrollView.getVisibility() != View.VISIBLE) {
-                if (mFlipSettingsViewAnim != null) mFlipSettingsViewAnim.cancel();
-                if (mScrollViewAnim != null) mScrollViewAnim.cancel();
-                if (mSettingsButtonAnim != null) mSettingsButtonAnim.cancel();
-                if (mNotificationButtonAnim != null) mNotificationButtonAnim.cancel();
-                if (mClearButtonAnim != null) mClearButtonAnim.cancel();
-
-                mScrollView.setVisibility(View.VISIBLE);
-                mScrollViewAnim = start(
-                    startDelay(FLIP_DURATION_OUT,
-                        interpolator(mDecelerateInterpolator,
-                            ObjectAnimator.ofFloat(mScrollView, View.SCALE_X, 0f, 1f)
-                                .setDuration(FLIP_DURATION_IN)
-                            )));
-                mFlipSettingsViewAnim = start(
-                    setVisibilityWhenDone(
-                        interpolator(mAccelerateInterpolator,
-                                ObjectAnimator.ofFloat(mFlipSettingsView, View.SCALE_X, 1f, 0f)
-                                )
-                            .setDuration(FLIP_DURATION_OUT),
-                        mFlipSettingsView, View.INVISIBLE));
-                mNotificationButtonAnim = start(
-                    setVisibilityWhenDone(
-                        ObjectAnimator.ofFloat(mNotificationButton, View.ALPHA, 0f)
-                            .setDuration(FLIP_DURATION),
-                        mNotificationButton, View.INVISIBLE));
-                mSettingsButton.setVisibility(View.VISIBLE);
-                mSettingsButtonAnim = start(
-                    ObjectAnimator.ofFloat(mSettingsButton, View.ALPHA, 1f)
-                        .setDuration(FLIP_DURATION));
-                mClearButton.setVisibility(View.VISIBLE);
-                mClearButton.setAlpha(0f);
-                setAreThereNotifications(); // this will show/hide the button as necessary
-                mNotificationPanel.postDelayed(new Runnable() {
-                    public void run() {
-                        updateCarrierLabelVisibility(false);
-                    }
-                }, FLIP_DURATION - 150);
-            }
+        if (mHasFlipSettings && mScrollView.getVisibility() != View.VISIBLE) {
+            flipToNotifications();
         }
 
         if (false) postStartTracing();
     }
 
+    public void flipToNotifications() {
+        if (mFlipSettingsViewAnim != null) mFlipSettingsViewAnim.cancel();
+        if (mScrollViewAnim != null) mScrollViewAnim.cancel();
+        if (mSettingsButtonAnim != null) mSettingsButtonAnim.cancel();
+        if (mNotificationButtonAnim != null) mNotificationButtonAnim.cancel();
+        if (mClearButtonAnim != null) mClearButtonAnim.cancel();
+
+        mScrollView.setVisibility(View.VISIBLE);
+        mScrollViewAnim = start(
+            startDelay(FLIP_DURATION_OUT,
+                interpolator(mDecelerateInterpolator,
+                    ObjectAnimator.ofFloat(mScrollView, View.SCALE_X, 0f, 1f)
+                        .setDuration(FLIP_DURATION_IN)
+                    )));
+        mFlipSettingsViewAnim = start(
+            setVisibilityWhenDone(
+                interpolator(mAccelerateInterpolator,
+                        ObjectAnimator.ofFloat(mFlipSettingsView, View.SCALE_X, 1f, 0f)
+                        )
+                    .setDuration(FLIP_DURATION_OUT),
+                mFlipSettingsView, View.INVISIBLE));
+        mNotificationButtonAnim = start(
+            setVisibilityWhenDone(
+                ObjectAnimator.ofFloat(mNotificationButton, View.ALPHA, 0f)
+                    .setDuration(FLIP_DURATION),
+                mNotificationButton, View.INVISIBLE));
+        mSettingsButton.setVisibility(View.VISIBLE);
+        mSettingsButtonAnim = start(
+            ObjectAnimator.ofFloat(mSettingsButton, View.ALPHA, 1f)
+                .setDuration(FLIP_DURATION));
+        mClearButton.setVisibility(View.VISIBLE);
+        mClearButton.setAlpha(0f);
+        setAreThereNotifications(); // this will show/hide the button as necessary
+        mNotificationPanel.postDelayed(new Runnable() {
+            public void run() {
+                updateCarrierLabelVisibility(false);
+            }
+        }, FLIP_DURATION - 150);
+    }
+
     @Override
     public void animateExpandSettingsPanel() {
         if (SPEW) Slog.d(TAG, "animateExpand: mExpandedVisible=" + mExpandedVisible);
@@ -1455,46 +1472,7 @@
         if (mHasFlipSettings) {
             mNotificationPanel.expand();
             if (mFlipSettingsView.getVisibility() != View.VISIBLE) {
-                if (mFlipSettingsViewAnim != null) mFlipSettingsViewAnim.cancel();
-                if (mScrollViewAnim != null) mScrollViewAnim.cancel();
-                if (mSettingsButtonAnim != null) mSettingsButtonAnim.cancel();
-                if (mNotificationButtonAnim != null) mNotificationButtonAnim.cancel();
-                if (mClearButtonAnim != null) mClearButtonAnim.cancel();
-
-                mFlipSettingsView.setVisibility(View.VISIBLE);
-                mFlipSettingsView.setScaleX(0f);
-                mFlipSettingsViewAnim = start(
-                    startDelay(FLIP_DURATION_OUT,
-                        interpolator(mDecelerateInterpolator,
-                            ObjectAnimator.ofFloat(mFlipSettingsView, View.SCALE_X, 0f, 1f)
-                                .setDuration(FLIP_DURATION_IN)
-                            )));
-                mScrollViewAnim = start(
-                    setVisibilityWhenDone(
-                        interpolator(mAccelerateInterpolator,
-                                ObjectAnimator.ofFloat(mScrollView, View.SCALE_X, 1f, 0f)
-                                )
-                            .setDuration(FLIP_DURATION_OUT), 
-                        mScrollView, View.INVISIBLE));
-                mSettingsButtonAnim = start(
-                    setVisibilityWhenDone(
-                        ObjectAnimator.ofFloat(mSettingsButton, View.ALPHA, 0f)
-                            .setDuration(FLIP_DURATION),
-                            mScrollView, View.INVISIBLE));
-                mNotificationButton.setVisibility(View.VISIBLE);
-                mNotificationButtonAnim = start(
-                    ObjectAnimator.ofFloat(mNotificationButton, View.ALPHA, 1f)
-                        .setDuration(FLIP_DURATION));
-                mClearButtonAnim = start(
-                    setVisibilityWhenDone(
-                        ObjectAnimator.ofFloat(mClearButton, View.ALPHA, 0f)
-                        .setDuration(FLIP_DURATION),
-                        mClearButton, View.INVISIBLE));
-                mNotificationPanel.postDelayed(new Runnable() {
-                    public void run() {
-                        updateCarrierLabelVisibility(false);
-                    }
-                }, FLIP_DURATION - 150);
+                flipToSettings();
             }
         } else if (mSettingsPanel != null) {
             mSettingsPanel.expand();
@@ -1503,10 +1481,78 @@
         if (false) postStartTracing();
     }
 
+    public void switchToSettings() {
+        mFlipSettingsView.setScaleX(1f);
+        mFlipSettingsView.setVisibility(View.VISIBLE);
+        mSettingsButton.setVisibility(View.GONE);
+        mScrollView.setVisibility(View.GONE);
+        mScrollView.setScaleX(0f);
+        mNotificationButton.setVisibility(View.VISIBLE);
+        mNotificationButton.setAlpha(1f);
+        mClearButton.setVisibility(View.GONE);
+    }
+
+    public void flipToSettings() {
+        if (mFlipSettingsViewAnim != null) mFlipSettingsViewAnim.cancel();
+        if (mScrollViewAnim != null) mScrollViewAnim.cancel();
+        if (mSettingsButtonAnim != null) mSettingsButtonAnim.cancel();
+        if (mNotificationButtonAnim != null) mNotificationButtonAnim.cancel();
+        if (mClearButtonAnim != null) mClearButtonAnim.cancel();
+
+        mFlipSettingsView.setVisibility(View.VISIBLE);
+        mFlipSettingsView.setScaleX(0f);
+        mFlipSettingsViewAnim = start(
+            startDelay(FLIP_DURATION_OUT,
+                interpolator(mDecelerateInterpolator,
+                    ObjectAnimator.ofFloat(mFlipSettingsView, View.SCALE_X, 0f, 1f)
+                        .setDuration(FLIP_DURATION_IN)
+                    )));
+        mScrollViewAnim = start(
+            setVisibilityWhenDone(
+                interpolator(mAccelerateInterpolator,
+                        ObjectAnimator.ofFloat(mScrollView, View.SCALE_X, 1f, 0f)
+                        )
+                    .setDuration(FLIP_DURATION_OUT), 
+                mScrollView, View.INVISIBLE));
+        mSettingsButtonAnim = start(
+            setVisibilityWhenDone(
+                ObjectAnimator.ofFloat(mSettingsButton, View.ALPHA, 0f)
+                    .setDuration(FLIP_DURATION),
+                    mScrollView, View.INVISIBLE));
+        mNotificationButton.setVisibility(View.VISIBLE);
+        mNotificationButtonAnim = start(
+            ObjectAnimator.ofFloat(mNotificationButton, View.ALPHA, 1f)
+                .setDuration(FLIP_DURATION));
+        mClearButtonAnim = start(
+            setVisibilityWhenDone(
+                ObjectAnimator.ofFloat(mClearButton, View.ALPHA, 0f)
+                .setDuration(FLIP_DURATION),
+                mClearButton, View.INVISIBLE));
+        mNotificationPanel.postDelayed(new Runnable() {
+            public void run() {
+                updateCarrierLabelVisibility(false);
+            }
+        }, FLIP_DURATION - 150);
+    }
+
+    public void flipPanels() {
+        if (mHasFlipSettings) {
+            if (mFlipSettingsView.getVisibility() != View.VISIBLE) {
+                flipToSettings();
+            } else {
+                flipToNotifications();
+            }
+        }
+    }
+
     public void animateCollapseQuickSettings() {
         mStatusBarView.collapseAllPanels(true);
     }
 
+    void makeExpandedInvisibleSoon() {
+        mHandler.postDelayed(new Runnable() { public void run() { makeExpandedInvisible(); }}, 50);
+    }
+
     void makeExpandedInvisible() {
         if (SPEW) Slog.d(TAG, "makeExpandedInvisible: mExpandedVisible=" + mExpandedVisible
                 + " mExpandedVisible=" + mExpandedVisible);
@@ -1518,6 +1564,18 @@
         // Ensure the panel is fully collapsed (just in case; bug 6765842, 7260868)
         mStatusBarView.collapseAllPanels(/*animate=*/ false);
 
+        if (mHasFlipSettings) {
+            // reset things to their proper state
+            mScrollView.setScaleX(1f);
+            mScrollView.setVisibility(View.VISIBLE);
+            mSettingsButton.setAlpha(1f);
+            mSettingsButton.setVisibility(View.VISIBLE);
+            mNotificationPanel.setVisibility(View.GONE);
+            mFlipSettingsView.setVisibility(View.GONE);
+            mNotificationButton.setVisibility(View.GONE);
+            setAreThereNotifications(); // show the clear button
+        }
+
         mExpandedVisible = false;
         mPile.setLayoutTransitionsEnabled(false);
         if (mNavigationBarView != null)
@@ -2128,24 +2186,36 @@
         }
     };
 
+    public void startActivityDismissingKeyguard(Intent intent, boolean onlyProvisioned) {
+        if (onlyProvisioned && !isDeviceProvisioned()) return;
+        try {
+            // Dismiss the lock screen when Settings starts.
+            ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity();
+        } catch (RemoteException e) {
+        }
+        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+        mContext.startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
+        animateCollapsePanels();
+    }
+
     private View.OnClickListener mSettingsButtonListener = new View.OnClickListener() {
         public void onClick(View v) {
             if (mHasSettingsPanel) {
                 animateExpandSettingsPanel();
             } else {
-                try {
-                    // Dismiss the lock screen when Settings starts.
-                    ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity();
-                } catch (RemoteException e) {
-                }
-                Intent intent = new Intent(android.provider.Settings.ACTION_SETTINGS);
-                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
-                mContext.startActivityAsUser(intent, new UserHandle(UserHandle.USER_CURRENT));
-                animateCollapsePanels();
+                startActivityDismissingKeyguard(
+                        new Intent(android.provider.Settings.ACTION_SETTINGS), true);
             }
         }
     };
 
+    private View.OnClickListener mClockClickListener = new View.OnClickListener() {
+        public void onClick(View v) {
+            startActivityDismissingKeyguard(
+                    new Intent(Intent.ACTION_QUICK_CLOCK), true); // have fun, everyone
+        }
+    };
+
     private View.OnClickListener mNotificationButtonListener = new View.OnClickListener() {
         public void onClick(View v) {
             animateExpandNotificationsPanel();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index 3c2f0e6..af6a149 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -154,7 +154,8 @@
     @Override
     public void onAllPanelsCollapsed() {
         super.onAllPanelsCollapsed();
-        mBar.makeExpandedInvisible();
+        // give animations time to settle
+        mBar.makeExpandedInvisibleSoon();
         mFadingPanel = null;
         mLastFullyOpenedPanel = null;
     }
@@ -191,14 +192,34 @@
         if (panel == mFadingPanel && mScrimColor != 0 && ActivityManager.isHighEndGfx()) {
             if (mShouldFade) {
                 frac = mPanelExpandedFractionSum; // don't judge me
-                // woo, special effects
-                final float k = (float)(1f-0.5f*(1f-Math.cos(3.14159f * Math.pow(1f-frac, 2.2f))));
-                // attenuate background color alpha by k
-                final int color = (int) ((mScrimColor >>> 24) * k) << 24 | (mScrimColor & 0xFFFFFF);
-                mBar.mStatusBarWindow.setBackgroundColor(color);
+                // let's start this 20% of the way down the screen
+                frac = frac * 1.2f - 0.2f;
+                if (frac <= 0) {
+                    mBar.mStatusBarWindow.setBackgroundColor(0);
+                } else {
+                    // woo, special effects
+                    final float k = (float)(1f-0.5f*(1f-Math.cos(3.14159f * Math.pow(1f-frac, 2f))));
+                    // attenuate background color alpha by k
+                    final int color = (int) ((mScrimColor >>> 24) * k) << 24 | (mScrimColor & 0xFFFFFF);
+                    mBar.mStatusBarWindow.setBackgroundColor(color);
+                }
             }
         }
 
+        // fade out the panel as it gets buried into the status bar to avoid overdrawing the
+        // status bar on the last frame of a close animation
+        final int H = mBar.getStatusBarHeight();
+        final float ph = panel.getExpandedHeight() + panel.getPaddingBottom();
+        float alpha = 1f;
+        if (ph < 2*H) {
+            if (ph < H) alpha = 0f;
+            else alpha = (ph - H) / H;
+            alpha = alpha * alpha; // get there faster
+        }
+        if (panel.getAlpha() != alpha) {
+            panel.setAlpha(alpha);
+        }
+
         mBar.updateCarrierLabelVisibility(false);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
index 5b550c2..58e3a57 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickSettings.java
@@ -145,6 +145,7 @@
         IntentFilter filter = new IntentFilter();
         filter.addAction(DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED);
         filter.addAction(BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED);
+        filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);
         filter.addAction(Intent.ACTION_USER_SWITCHED);
         mContext.registerReceiver(mReceiver, filter);
 
@@ -321,7 +322,31 @@
         parent.addView(userTile);
         mDynamicSpannedTiles.add(userTile);
 
+        // Brightness
+        QuickSettingsTileView brightnessTile = (QuickSettingsTileView)
+                inflater.inflate(R.layout.quick_settings_tile, parent, false);
+        brightnessTile.setContent(R.layout.quick_settings_tile_brightness, inflater);
+        brightnessTile.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                mBar.collapseAllPanels(true);
+                showBrightnessDialog();
+            }
+        });
+        mModel.addBrightnessTile(brightnessTile, new QuickSettingsModel.RefreshCallback() {
+            @Override
+            public void refreshView(QuickSettingsTileView view, State state) {
+                TextView tv = (TextView) view.findViewById(R.id.brightness_textview);
+                tv.setCompoundDrawablesWithIntrinsicBounds(0, state.iconId, 0, 0);
+                tv.setText(state.label);
+                dismissBrightnessDialog(mBrightnessDialogShortTimeout);
+            }
+        });
+        parent.addView(brightnessTile);
+        mDynamicSpannedTiles.add(brightnessTile);
+
         // Time tile
+        /*
         QuickSettingsTileView timeTile = (QuickSettingsTileView)
                 inflater.inflate(R.layout.quick_settings_tile, parent, false);
         timeTile.setContent(R.layout.quick_settings_tile_time, inflater);
@@ -338,6 +363,7 @@
         });
         parent.addView(timeTile);
         mDynamicSpannedTiles.add(timeTile);
+        */
 
         // Settings tile
         QuickSettingsTileView settingsTile = (QuickSettingsTileView)
@@ -549,27 +575,6 @@
             parent.addView(bluetoothTile);
         }
 
-        // Brightness
-        QuickSettingsTileView brightnessTile = (QuickSettingsTileView)
-                inflater.inflate(R.layout.quick_settings_tile, parent, false);
-        brightnessTile.setContent(R.layout.quick_settings_tile_brightness, inflater);
-        brightnessTile.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                mBar.collapseAllPanels(true);
-                showBrightnessDialog();
-            }
-        });
-        mModel.addBrightnessTile(brightnessTile, new QuickSettingsModel.RefreshCallback() {
-            @Override
-            public void refreshView(QuickSettingsTileView view, State state) {
-                TextView tv = (TextView) view.findViewById(R.id.brightness_textview);
-                tv.setCompoundDrawablesWithIntrinsicBounds(0, state.iconId, 0, 0);
-                tv.setText(state.label);
-                dismissBrightnessDialog(mBrightnessDialogShortTimeout);
-            }
-        });
-        parent.addView(brightnessTile);
     }
 
     private void addTemporaryTiles(final ViewGroup parent, final LayoutInflater inflater) {
@@ -850,6 +855,11 @@
                         DisplayManager.EXTRA_WIFI_DISPLAY_STATUS);
                 mWifiDisplayStatus = status;
                 applyWifiDisplayStatus();
+            } else if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
+                int state = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE,
+                        BluetoothAdapter.ERROR);
+                mBluetoothState.enabled = (state == BluetoothAdapter.STATE_ON);
+                applyBluetoothStatus();
             } else if (BluetoothAdapter.ACTION_CONNECTION_STATE_CHANGED.equals(action)) {
                 int status = intent.getIntExtra(BluetoothAdapter.EXTRA_CONNECTION_STATE,
                         BluetoothAdapter.STATE_DISCONNECTED);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
index 97451ae..86c247a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tablet/TabletStatusBar.java
@@ -60,8 +60,6 @@
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.internal.statusbar.StatusBarNotification;
 import com.android.systemui.R;
-import com.android.systemui.recent.RecentTasksLoader;
-import com.android.systemui.recent.RecentsPanelView;
 import com.android.systemui.statusbar.BaseStatusBar;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.DoNotDisturb;
@@ -353,7 +351,7 @@
 
         mWindowManager.addView(mCompatModePanel, lp);
 
-        mRecentButton.setOnTouchListener(getRecentTasksLoader());
+        mRecentButton.setOnTouchListener(mRecentsPreloadOnTouchListener);
 
         mPile = (NotificationRowLayout)mNotificationPanel.findViewById(R.id.content);
         mPile.removeAllViews();
diff --git a/policy/src/com/android/internal/policy/impl/GlobalActions.java b/policy/src/com/android/internal/policy/impl/GlobalActions.java
index 9ea47f9..c215f1b 100644
--- a/policy/src/com/android/internal/policy/impl/GlobalActions.java
+++ b/policy/src/com/android/internal/policy/impl/GlobalActions.java
@@ -290,7 +290,7 @@
                                     }
                                 });
                         AlertDialog dialog = builder.create();
-                        dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
+                        dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
                         dialog.show();
                     }
 
@@ -339,7 +339,7 @@
                         return mAdapter.getItem(position).onLongPress();
                     }
         });
-        dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
+        dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
 
         dialog.setOnDismissListener(this);
 
@@ -390,11 +390,7 @@
         refreshSilentMode();
         mAirplaneModeOn.updateState(mAirplaneState);
         mAdapter.notifyDataSetChanged();
-        if (mKeyguardShowing) {
-            mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
-        } else {
-            mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
-        }
+        mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG);
         if (SHOW_SILENT_TOGGLE) {
             IntentFilter filter = new IntentFilter(AudioManager.RINGER_MODE_CHANGED_ACTION);
             mContext.registerReceiver(mRingerModeReceiver, filter);
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 72cb1dd..41d67bc 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -2867,8 +2867,6 @@
             mDecor = generateDecor();
             mDecor.setDescendantFocusability(ViewGroup.FOCUS_AFTER_DESCENDANTS);
             mDecor.setIsRootNamespace(true);
-            mDecor.setLayoutDirection(
-                    getContext().getResources().getConfiguration().getLayoutDirection());
             if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
                 mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
             }
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
index 91d5eaa..10b11bc 100755
--- a/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindowManager.java
@@ -299,6 +299,7 @@
     int mCarDockRotation;
     int mDeskDockRotation;
     int mHdmiRotation;
+    boolean mHdmiRotationLock;
 
     int mUserRotationMode = WindowManagerPolicy.USER_ROTATION_FREE;
     int mUserRotation = Surface.ROTATION_0;
@@ -1035,11 +1036,14 @@
             mCanHideNavigationBar = false;
         }
 
+        // For demo purposes, allow the rotation of the HDMI display to be controlled.
+        // By default, HDMI locks rotation to landscape.
         if ("portrait".equals(SystemProperties.get("persist.demo.hdmirotation"))) {
             mHdmiRotation = mPortraitRotation;
         } else {
             mHdmiRotation = mLandscapeRotation;
         }
+        mHdmiRotationLock = SystemProperties.getBoolean("persist.demo.hdmirotationlock", true);
     }
 
     public void updateSettings() {
@@ -1908,15 +1912,15 @@
                     Intent service = new Intent();
                     service.setClassName(mContext, "com.android.server.LoadAverageService");
                     ContentResolver res = mContext.getContentResolver();
-                    boolean shown = Settings.System.getInt(
-                            res, Settings.System.SHOW_PROCESSES, 0) != 0;
+                    boolean shown = Settings.Global.getInt(
+                            res, Settings.Global.SHOW_PROCESSES, 0) != 0;
                     if (!shown) {
                         mContext.startService(service);
                     } else {
                         mContext.stopService(service);
                     }
-                    Settings.System.putInt(
-                            res, Settings.System.SHOW_PROCESSES, shown ? 0 : 1);
+                    Settings.Global.putInt(
+                            res, Settings.Global.SHOW_PROCESSES, shown ? 0 : 1);
                     return -1;
                 }
             }
@@ -3873,7 +3877,7 @@
                 // enable 180 degree rotation while docked.
                 preferredRotation = mDeskDockEnablesAccelerometer
                         ? sensorRotation : mDeskDockRotation;
-            } else if (mHdmiPlugged) {
+            } else if (mHdmiPlugged && mHdmiRotationLock) {
                 // Ignore sensor when plugged into HDMI.
                 // Note that the dock orientation overrides the HDMI orientation.
                 preferredRotation = mHdmiRotation;
@@ -4538,5 +4542,7 @@
                 pw.print(" mSeascapeRotation="); pw.println(mSeascapeRotation);
         pw.print(prefix); pw.print("mPortraitRotation="); pw.print(mPortraitRotation);
                 pw.print(" mUpsideDownRotation="); pw.println(mUpsideDownRotation);
+        pw.print(prefix); pw.print("mHdmiRotation="); pw.print(mHdmiRotation);
+                pw.print(" mHdmiRotationLock="); pw.println(mHdmiRotationLock);
     }
 }
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardFaceUnlockView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardFaceUnlockView.java
index 78fdda3..04ab871 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardFaceUnlockView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardFaceUnlockView.java
@@ -75,7 +75,7 @@
     public void onDetachedFromWindow() {
         if (DEBUG) Log.d(TAG, "onDetachedFromWindow()");
         if (mBiometricUnlock != null) {
-            mBiometricUnlock.stopAndShowBackup();
+            mBiometricUnlock.stop();
         }
     }
 
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
index ebc54b32..b86e5b8 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardHostView.java
@@ -611,6 +611,7 @@
         int layoutId = getLayoutIdFor(securityMode);
         if (view == null && layoutId != 0) {
             final LayoutInflater inflater = LayoutInflater.from(mContext);
+            if (DEBUG) Log.v(TAG, "inflating id = " + layoutId);
             View v = inflater.inflate(layoutId, this, false);
             mSecurityViewContainer.addView(v);
             updateSecurityView(v);
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java
index 0ad2404..b66c883 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewManager.java
@@ -43,7 +43,7 @@
 
 /**
  * Manages creating, showing, hiding and resetting the keyguard.  Calls back
- * via {@link com.android.internal.policy.impl.KeyguardViewCallback} to poke
+ * via {@link KeyguardViewMediator.ViewMediatorCallback} to poke
  * the wake lock and report that the keyguard is done, which is in turn,
  * reported to this class by the current {@link KeyguardViewBase}.
  */
@@ -233,6 +233,7 @@
 
         if (mScreenOn) {
             mKeyguardView.show();
+            mKeyguardView.requestFocus();
         }
     }
 
@@ -314,22 +315,25 @@
 
             // Caller should wait for this window to be shown before turning
             // on the screen.
-            if (mKeyguardHost.getVisibility() == View.VISIBLE) {
-                // Keyguard may be in the process of being shown, but not yet
-                // updated with the window manager...  give it a chance to do so.
-                mKeyguardHost.post(new Runnable() {
-                    public void run() {
-                        if (mKeyguardHost.getVisibility() == View.VISIBLE) {
-                            showListener.onShown(mKeyguardHost.getWindowToken());
-                        } else {
-                            showListener.onShown(null);
+            if (showListener != null) {
+                if (mKeyguardHost.getVisibility() == View.VISIBLE) {
+                    // Keyguard may be in the process of being shown, but not yet
+                    // updated with the window manager...  give it a chance to do so.
+                    mKeyguardHost.post(new Runnable() {
+                        @Override
+                        public void run() {
+                            if (mKeyguardHost.getVisibility() == View.VISIBLE) {
+                                showListener.onShown(mKeyguardHost.getWindowToken());
+                            } else {
+                                showListener.onShown(null);
+                            }
                         }
-                    }
-                });
-            } else {
-                showListener.onShown(null);
+                    });
+                } else {
+                    showListener.onShown(null);
+                }
             }
-        } else {
+        } else if (showListener != null) {
             showListener.onShown(null);
         }
     }
@@ -356,10 +360,9 @@
         if (mKeyguardView != null) {
             mKeyguardView.wakeWhenReadyTq(keyCode);
             return true;
-        } else {
-            Log.w(TAG, "mKeyguardView is null in wakeWhenReadyTq");
-            return false;
         }
+        Log.w(TAG, "mKeyguardView is null in wakeWhenReadyTq");
+        return false;
     }
 
     /**
@@ -382,6 +385,7 @@
                 final KeyguardViewBase lastView = mKeyguardView;
                 mKeyguardView = null;
                 mKeyguardHost.postDelayed(new Runnable() {
+                    @Override
                     public void run() {
                         synchronized (KeyguardViewManager.this) {
                             lastView.cleanUp();
diff --git a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java
index 92f9dfd..ceb0325 100644
--- a/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java
+++ b/policy/src/com/android/internal/policy/impl/keyguard/KeyguardViewMediator.java
@@ -629,9 +629,7 @@
             mScreenOn = true;
             cancelDoKeyguardLaterLocked();
             if (DEBUG) Log.d(TAG, "onScreenTurnedOn, seq = " + mDelayedShowingSequence);
-            if (showListener != null) {
-                notifyScreenOnLocked(showListener);
-            }
+            notifyScreenOnLocked(showListener);
         }
         maybeSendUserPresentBroadcast();
     }
@@ -1365,7 +1363,7 @@
 
     /**
      * Handle message sent by {@link #verifyUnlock}
-     * @see #RESET
+     * @see #VERIFY_UNLOCK
      */
     private void handleVerifyUnlock() {
         synchronized (KeyguardViewMediator.this) {
diff --git a/services/java/com/android/server/AppWidgetService.java b/services/java/com/android/server/AppWidgetService.java
index e7e4f87..06d37dc 100644
--- a/services/java/com/android/server/AppWidgetService.java
+++ b/services/java/com/android/server/AppWidgetService.java
@@ -98,21 +98,19 @@
 
         IntentFilter userFilter = new IntentFilter();
         userFilter.addAction(Intent.ACTION_USER_REMOVED);
+        userFilter.addAction(Intent.ACTION_USER_STOPPING);
         mContext.registerReceiver(new BroadcastReceiver() {
             @Override
             public void onReceive(Context context, Intent intent) {
-                onUserRemoved(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1));
+                if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
+                    onUserRemoved(intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
+                            UserHandle.USER_NULL));
+                } else if (Intent.ACTION_USER_STOPPING.equals(intent.getAction())) {
+                    onUserStopping(intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
+                            UserHandle.USER_NULL));
+                }
             }
         }, userFilter);
-
-        IntentFilter userStopFilter = new IntentFilter();
-        userStopFilter.addAction(Intent.ACTION_USER_STOPPED);
-        mContext.registerReceiverAsUser(new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                onUserStopped(getSendingUserId());
-            }
-        }, UserHandle.ALL, userFilter, null, null);
     }
 
     /**
@@ -203,7 +201,7 @@
         synchronized (mAppWidgetServices) {
             AppWidgetServiceImpl impl = mAppWidgetServices.get(userId);
             mAppWidgetServices.remove(userId);
-    
+
             if (impl == null) {
                 AppWidgetServiceImpl.getSettingsFile(userId).delete();
             } else {
@@ -212,7 +210,15 @@
         }
     }
 
-    public void onUserStopped(int userId) {
+    public void onUserStopping(int userId) {
+        if (userId < 1) return;
+        synchronized (mAppWidgetServices) {
+            AppWidgetServiceImpl impl = mAppWidgetServices.get(userId);
+            if (impl != null) {
+                mAppWidgetServices.remove(userId);
+                impl.onUserStopping();
+            }
+        }
     }
 
     private AppWidgetServiceImpl getImplForUser(int userId) {
@@ -324,11 +330,11 @@
             String action = intent.getAction();
             // Slog.d(TAG, "received " + action);
             if (Intent.ACTION_BOOT_COMPLETED.equals(action)) {
-                int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
+                int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
                 if (userId >= 0) {
                     getImplForUser(userId).sendInitialBroadcasts();
                 } else {
-                    Slog.w(TAG, "Not user handle supplied in " + intent);
+                    Slog.w(TAG, "Incorrect user handle supplied in " + intent);
                 }
             } else if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
                 for (int i = 0; i < mAppWidgetServices.size(); i++) {
diff --git a/services/java/com/android/server/AppWidgetServiceImpl.java b/services/java/com/android/server/AppWidgetServiceImpl.java
index 9fea6f3..6a313a0 100644
--- a/services/java/com/android/server/AppWidgetServiceImpl.java
+++ b/services/java/com/android/server/AppWidgetServiceImpl.java
@@ -1778,13 +1778,16 @@
         return new AtomicFile(settingsFile);
     }
 
-    void onUserRemoved() {
+    void onUserStopping() {
         // prune the ones we don't want to keep
         int N = mInstalledProviders.size();
         for (int i = N - 1; i >= 0; i--) {
             Provider p = mInstalledProviders.get(i);
             cancelBroadcasts(p);
         }
+    }
+
+    void onUserRemoved() {
         getSettingsFile(mUserId).delete();
     }
 
diff --git a/services/java/com/android/server/BackupManagerService.java b/services/java/com/android/server/BackupManagerService.java
index 9f01eca..f241c80 100644
--- a/services/java/com/android/server/BackupManagerService.java
+++ b/services/java/com/android/server/BackupManagerService.java
@@ -1474,6 +1474,7 @@
             if (MORE_DEBUG) Slog.v(TAG, "  removing participant " + packageName);
             removeEverBackedUp(packageName);
             set.remove(packageName);
+            mPendingBackups.remove(packageName);
         }
     }
 
@@ -1625,6 +1626,7 @@
                         } catch (InterruptedException e) {
                             // just bail
                             if (DEBUG) Slog.w(TAG, "Interrupted: " + e);
+                            mActivityManager.clearPendingBackup();
                             return null;
                         }
                     }
@@ -1632,6 +1634,7 @@
                     // if we timed out with no connect, abort and move on
                     if (mConnecting == true) {
                         Slog.w(TAG, "Timeout waiting for agent " + app);
+                        mActivityManager.clearPendingBackup();
                         return null;
                     }
                     if (DEBUG) Slog.i(TAG, "got agent " + mConnectedAgent);
diff --git a/services/java/com/android/server/LocationManagerService.java b/services/java/com/android/server/LocationManagerService.java
index 6948927..37dee19 100644
--- a/services/java/com/android/server/LocationManagerService.java
+++ b/services/java/com/android/server/LocationManagerService.java
@@ -23,8 +23,11 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
+import android.content.pm.ResolveInfo;
+import android.content.pm.Signature;
 import android.content.res.Resources;
 import android.database.ContentObserver;
 import android.location.Address;
@@ -90,10 +93,13 @@
     private static final String WAKELOCK_KEY = TAG;
     private static final String THREAD_NAME = TAG;
 
-    private static final String ACCESS_FINE_LOCATION =
-            android.Manifest.permission.ACCESS_FINE_LOCATION;
-    private static final String ACCESS_COARSE_LOCATION =
-            android.Manifest.permission.ACCESS_COARSE_LOCATION;
+    // Location resolution level: no location data whatsoever
+    private static final int RESOLUTION_LEVEL_NONE = 0;
+    // Location resolution level: coarse location data only
+    private static final int RESOLUTION_LEVEL_COARSE = 1;
+    // Location resolution level: fine location data
+    private static final int RESOLUTION_LEVEL_FINE = 2;
+
     private static final String ACCESS_MOCK_LOCATION =
             android.Manifest.permission.ACCESS_MOCK_LOCATION;
     private static final String ACCESS_LOCATION_EXTRA_COMMANDS =
@@ -246,6 +252,74 @@
         updateProvidersLocked();
     }
 
+    private void ensureFallbackFusedProviderPresentLocked(ArrayList<String> pkgs) {
+        PackageManager pm = mContext.getPackageManager();
+        String systemPackageName = mContext.getPackageName();
+        ArrayList<HashSet<Signature>> sigSets = ServiceWatcher.getSignatureSets(mContext, pkgs);
+
+        List<ResolveInfo> rInfos = pm.queryIntentServicesAsUser(
+                new Intent(FUSED_LOCATION_SERVICE_ACTION),
+                PackageManager.GET_META_DATA, mCurrentUserId);
+        for (ResolveInfo rInfo : rInfos) {
+            String packageName = rInfo.serviceInfo.packageName;
+
+            // Check that the signature is in the list of supported sigs. If it's not in
+            // this list the standard provider binding logic won't bind to it.
+            try {
+                PackageInfo pInfo;
+                pInfo = pm.getPackageInfo(packageName, PackageManager.GET_SIGNATURES);
+                if (!ServiceWatcher.isSignatureMatch(pInfo.signatures, sigSets)) {
+                    Log.w(TAG, packageName + " resolves service " + FUSED_LOCATION_SERVICE_ACTION +
+                            ", but has wrong signature, ignoring");
+                    continue;
+                }
+            } catch (NameNotFoundException e) {
+                Log.e(TAG, "missing package: " + packageName);
+                continue;
+            }
+
+            // Get the version info
+            if (rInfo.serviceInfo.metaData == null) {
+                Log.w(TAG, "Found fused provider without metadata: " + packageName);
+                continue;
+            }
+
+            int version = rInfo.serviceInfo.metaData.getInt(
+                    ServiceWatcher.EXTRA_SERVICE_VERSION, -1);
+            if (version == 0) {
+                // This should be the fallback fused location provider.
+
+                // Make sure it's in the system partition.
+                if ((rInfo.serviceInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
+                    if (D) Log.d(TAG, "Fallback candidate not in /system: " + packageName);
+                    continue;
+                }
+
+                // Check that the fallback is signed the same as the OS
+                // as a proxy for coreApp="true"
+                if (pm.checkSignatures(systemPackageName, packageName)
+                        != PackageManager.SIGNATURE_MATCH) {
+                    if (D) Log.d(TAG, "Fallback candidate not signed the same as system: "
+                            + packageName);
+                    continue;
+                }
+
+                // Found a valid fallback.
+                if (D) Log.d(TAG, "Found fallback provider: " + packageName);
+                return;
+            } else {
+                if (D) Log.d(TAG, "Fallback candidate not version 0: " + packageName);
+            }
+        }
+
+        throw new IllegalStateException("Unable to find a fused location provider that is in the "
+                + "system partition with version 0 and signed with the platform certificate. "
+                + "Such a package is needed to provide a default fused location provider in the "
+                + "event that no other fused location provider has been installed or is currently "
+                + "available. For example, coreOnly boot mode when decrypting the data "
+                + "partition. The fallback must also be marked coreApp=\"true\" in the manifest");
+    }
+
     private void loadProvidersLocked() {
         // create a passive location provider, which is always enabled
         PassiveProvider passiveProvider = new PassiveProvider(this);
@@ -275,14 +349,13 @@
         */
         Resources resources = mContext.getResources();
         ArrayList<String> providerPackageNames = new ArrayList<String>();
-        String[] pkgs1 = resources.getStringArray(
+        String[] pkgs = resources.getStringArray(
                 com.android.internal.R.array.config_locationProviderPackageNames);
-        String[] pkgs2 = resources.getStringArray(
-                com.android.internal.R.array.config_overlay_locationProviderPackageNames);
-        if (D) Log.d(TAG, "built-in location providers: " + Arrays.toString(pkgs1));
-        if (D) Log.d(TAG, "overlay location providers: " + Arrays.toString(pkgs2));
-        if (pkgs1 != null) providerPackageNames.addAll(Arrays.asList(pkgs1));
-        if (pkgs2 != null) providerPackageNames.addAll(Arrays.asList(pkgs2));
+        if (D) Log.d(TAG, "certificates for location providers pulled from: " +
+                Arrays.toString(pkgs));
+        if (pkgs != null) providerPackageNames.addAll(Arrays.asList(pkgs));
+
+        ensureFallbackFusedProviderPresentLocked(providerPackageNames);
 
         // bind to network provider
         LocationProviderProxy networkProvider = LocationProviderProxy.createAndBind(
@@ -347,7 +420,7 @@
         final int mUid;  // uid of receiver
         final int mPid;  // pid of receiver
         final String mPackageName;  // package name of receiver
-        final String mPermission;  // best permission that receiver has
+        final int mAllowedResolutionLevel;  // resolution level allowed to receiver
 
         final ILocationListener mListener;
         final PendingIntent mPendingIntent;
@@ -366,7 +439,7 @@
             } else {
                 mKey = intent;
             }
-            mPermission = checkPermission();
+            mAllowedResolutionLevel = getAllowedResolutionLevel(pid, uid);
             mUid = uid;
             mPid = pid;
             mPackageName = packageName;
@@ -440,7 +513,7 @@
                         // synchronize to ensure incrementPendingBroadcastsLocked()
                         // is called before decrementPendingBroadcasts()
                         mPendingIntent.send(mContext, 0, statusChanged, this, mLocationHandler,
-                                mPermission);
+                                getResolutionPermission(mAllowedResolutionLevel));
                         // call this after broadcasting so we do not increment
                         // if we throw an exeption.
                         incrementPendingBroadcastsLocked();
@@ -474,7 +547,7 @@
                         // synchronize to ensure incrementPendingBroadcastsLocked()
                         // is called before decrementPendingBroadcasts()
                         mPendingIntent.send(mContext, 0, locationChanged, this, mLocationHandler,
-                                mPermission);
+                                getResolutionPermission(mAllowedResolutionLevel));
                         // call this after broadcasting so we do not increment
                         // if we throw an exeption.
                         incrementPendingBroadcastsLocked();
@@ -512,7 +585,7 @@
                         // synchronize to ensure incrementPendingBroadcastsLocked()
                         // is called before decrementPendingBroadcasts()
                         mPendingIntent.send(mContext, 0, providerIntent, this, mLocationHandler,
-                                mPermission);
+                                getResolutionPermission(mAllowedResolutionLevel));
                         // call this after broadcasting so we do not increment
                         // if we throw an exeption.
                         incrementPendingBroadcastsLocked();
@@ -609,51 +682,76 @@
     }
 
     /**
-     * Returns the best permission available to the caller.
+     * Returns the permission string associated with the specified resolution level.
+     *
+     * @param resolutionLevel the resolution level
+     * @return the permission string
      */
-    private String getBestCallingPermission() {
-        if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) ==
-                PackageManager.PERMISSION_GRANTED) {
-            return ACCESS_FINE_LOCATION;
-        } else if (mContext.checkCallingOrSelfPermission(ACCESS_COARSE_LOCATION) ==
-                PackageManager.PERMISSION_GRANTED) {
-            return ACCESS_COARSE_LOCATION;
+    private String getResolutionPermission(int resolutionLevel) {
+        switch (resolutionLevel) {
+            case RESOLUTION_LEVEL_FINE:
+                return android.Manifest.permission.ACCESS_FINE_LOCATION;
+            case RESOLUTION_LEVEL_COARSE:
+                return android.Manifest.permission.ACCESS_COARSE_LOCATION;
+            default:
+                return null;
         }
-        return null;
     }
 
     /**
-     * Throw SecurityException if caller has neither COARSE or FINE.
-     * Otherwise, return the best permission.
+     * Returns the resolution level allowed to the given PID/UID pair.
+     *
+     * @param pid the PID
+     * @param uid the UID
+     * @return resolution level allowed to the pid/uid pair
      */
-    private String checkPermission() {
-        String perm = getBestCallingPermission();
-        if (perm == null) {
-            throw new SecurityException("Location requires either ACCESS_COARSE_LOCATION or" +
-                    " ACCESS_FINE_LOCATION permission");
+    private int getAllowedResolutionLevel(int pid, int uid) {
+        if (mContext.checkPermission(android.Manifest.permission.ACCESS_FINE_LOCATION,
+                pid, uid) == PackageManager.PERMISSION_GRANTED) {
+            return RESOLUTION_LEVEL_FINE;
+        } else if (mContext.checkPermission(android.Manifest.permission.ACCESS_COARSE_LOCATION,
+                pid, uid) == PackageManager.PERMISSION_GRANTED) {
+            return RESOLUTION_LEVEL_COARSE;
+        } else {
+            return RESOLUTION_LEVEL_NONE;
         }
-        return perm;
     }
 
     /**
-     * Throw SecurityException if caller lacks permission to use Geofences.
+     * Returns the resolution level allowed to the caller
+     *
+     * @return resolution level allowed to caller
      */
-    private void checkGeofencePermission() {
-        if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) !=
-                PackageManager.PERMISSION_GRANTED) {
+    private int getCallerAllowedResolutionLevel() {
+        return getAllowedResolutionLevel(Binder.getCallingPid(), Binder.getCallingUid());
+    }
+
+    /**
+     * Throw SecurityException if specified resolution level is insufficient to use geofences.
+     *
+     * @param allowedResolutionLevel resolution level allowed to caller
+     */
+    private void checkResolutionLevelIsSufficientForGeofenceUse(int allowedResolutionLevel) {
+        if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
             throw new SecurityException("Geofence usage requires ACCESS_FINE_LOCATION permission");
         }
     }
 
-    private String getMinimumPermissionForProvider(String provider) {
+    /**
+     * Return the minimum resolution level required to use the specified location provider.
+     *
+     * @param provider the name of the location provider
+     * @return minimum resolution level required for provider
+     */
+    private int getMinimumResolutionLevelForProviderUse(String provider) {
         if (LocationManager.GPS_PROVIDER.equals(provider) ||
                 LocationManager.PASSIVE_PROVIDER.equals(provider)) {
             // gps and passive providers require FINE permission
-            return ACCESS_FINE_LOCATION;
+            return RESOLUTION_LEVEL_FINE;
         } else if (LocationManager.NETWORK_PROVIDER.equals(provider) ||
                 LocationManager.FUSED_PROVIDER.equals(provider)) {
             // network and fused providers are ok with COARSE or FINE
-            return ACCESS_COARSE_LOCATION;
+            return RESOLUTION_LEVEL_COARSE;
         } else {
             // mock providers
             LocationProviderInterface lp = mMockProviders.get(provider);
@@ -662,41 +760,38 @@
                 if (properties != null) {
                     if (properties.mRequiresSatellite) {
                         // provider requiring satellites require FINE permission
-                        return ACCESS_FINE_LOCATION;
+                        return RESOLUTION_LEVEL_FINE;
                     } else if (properties.mRequiresNetwork || properties.mRequiresCell) {
                         // provider requiring network and or cell require COARSE or FINE
-                        return ACCESS_COARSE_LOCATION;
+                        return RESOLUTION_LEVEL_COARSE;
                     }
                 }
             }
         }
-
-        return null;
+        return RESOLUTION_LEVEL_FINE; // if in doubt, require FINE
     }
 
-    private boolean isPermissionSufficient(String perm, String minPerm) {
-        if (ACCESS_FINE_LOCATION.equals(minPerm)) {
-            return ACCESS_FINE_LOCATION.equals(perm);
-        } else if (ACCESS_COARSE_LOCATION.equals(minPerm)) {
-            return ACCESS_FINE_LOCATION.equals(perm) ||
-                    ACCESS_COARSE_LOCATION.equals(perm);
-        } else {
-            return false;
-        }
-    }
-
-    private void checkPermissionForProvider(String perm, String provider) {
-        String minPerm = getMinimumPermissionForProvider(provider);
-        if (!isPermissionSufficient(perm, minPerm)) {
-            if (ACCESS_FINE_LOCATION.equals(minPerm)) {
-                throw new SecurityException("Location provider \"" + provider +
-                        "\" requires ACCESS_FINE_LOCATION permission.");
-            } else if (ACCESS_COARSE_LOCATION.equals(minPerm)) {
-                throw new SecurityException("Location provider \"" + provider +
-                        "\" requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission.");                
-            } else {
-                throw new SecurityException("Insufficient permission for location provider \"" +
-                        provider + "\".");
+    /**
+     * Throw SecurityException if specified resolution level is insufficient to use the named
+     * location provider.
+     *
+     * @param allowedResolutionLevel resolution level allowed to caller
+     * @param providerName the name of the location provider
+     */
+    private void checkResolutionLevelIsSufficientForProviderUse(int allowedResolutionLevel,
+            String providerName) {
+        int requiredResolutionLevel = getMinimumResolutionLevelForProviderUse(providerName);
+        if (allowedResolutionLevel < requiredResolutionLevel) {
+            switch (requiredResolutionLevel) {
+                case RESOLUTION_LEVEL_FINE:
+                    throw new SecurityException("\"" + providerName + "\" location provider " +
+                            "requires ACCESS_FINE_LOCATION permission.");
+                case RESOLUTION_LEVEL_COARSE:
+                    throw new SecurityException("\"" + providerName + "\" location provider " +
+                            "requires ACCESS_COARSE_LOCATION or ACCESS_FINE_LOCATION permission.");
+                default:
+                    throw new SecurityException("Insufficient permission for \"" + providerName +
+                            "\" location provider.");
             }
         }
     }
@@ -731,8 +826,8 @@
      */
     @Override
     public List<String> getProviders(Criteria criteria, boolean enabledOnly) {
+        int allowedResolutionLevel = getCallerAllowedResolutionLevel();
         ArrayList<String> out;
-        String perm = getBestCallingPermission();
         int callingUserId = UserHandle.getCallingUserId();
         long identity = Binder.clearCallingIdentity();
         try {
@@ -743,7 +838,7 @@
                     if (LocationManager.FUSED_PROVIDER.equals(name)) {
                         continue;
                     }
-                    if (isPermissionSufficient(perm, getMinimumPermissionForProvider(name))) {
+                    if (allowedResolutionLevel >= getMinimumResolutionLevelForProviderUse(name)) {
                         if (enabledOnly && !isAllowedBySettingsLocked(name, callingUserId)) {
                             continue;
                         }
@@ -803,8 +898,6 @@
 
     @Override
     public boolean providerMeetsCriteria(String provider, Criteria criteria) {
-        checkPermission();
-
         LocationProviderInterface p = mProvidersByName.get(provider);
         if (p == null) {
             throw new IllegalArgumentException("provider=" + provider);
@@ -1010,33 +1103,41 @@
         return receiver;
     }
 
-    private String checkPermissionAndRequest(LocationRequest request) {
-        String perm = getBestCallingPermission();
-        String provider = request.getProvider();
-        checkPermissionForProvider(perm, provider);
-
-        if (ACCESS_COARSE_LOCATION.equals(perm)) {
-            switch (request.getQuality()) {
+    /**
+     * Creates a LocationRequest based upon the supplied LocationRequest that to meets resolution
+     * and consistency requirements.
+     *
+     * @param request the LocationRequest from which to create a sanitized version
+     * @param shouldBeCoarse whether the sanitized version should be held to coarse resolution
+     * constraints
+     * @param fastestCoarseIntervalMS minimum interval allowed for coarse resolution
+     * @return a version of request that meets the given resolution and consistency requirements
+     * @hide
+     */
+    private LocationRequest createSanitizedRequest(LocationRequest request, int resolutionLevel) {
+        LocationRequest sanitizedRequest = new LocationRequest(request);
+        if (resolutionLevel < RESOLUTION_LEVEL_FINE) {
+            switch (sanitizedRequest.getQuality()) {
                 case LocationRequest.ACCURACY_FINE:
-                    request.setQuality(LocationRequest.ACCURACY_BLOCK);
+                    sanitizedRequest.setQuality(LocationRequest.ACCURACY_BLOCK);
                     break;
                 case LocationRequest.POWER_HIGH:
-                    request.setQuality(LocationRequest.POWER_LOW);
+                    sanitizedRequest.setQuality(LocationRequest.POWER_LOW);
                     break;
             }
             // throttle
-            if (request.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
-                request.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
+            if (sanitizedRequest.getInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
+                sanitizedRequest.setInterval(LocationFudger.FASTEST_INTERVAL_MS);
             }
-            if (request.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
-                request.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
+            if (sanitizedRequest.getFastestInterval() < LocationFudger.FASTEST_INTERVAL_MS) {
+                sanitizedRequest.setFastestInterval(LocationFudger.FASTEST_INTERVAL_MS);
             }
         }
         // make getFastestInterval() the minimum of interval and fastest interval
-        if (request.getFastestInterval() > request.getInterval()) {
+        if (sanitizedRequest.getFastestInterval() > sanitizedRequest.getInterval()) {
             request.setFastestInterval(request.getInterval());
         }
-        return perm;
+        return sanitizedRequest;
     }
 
     private void checkPackageName(String packageName) {
@@ -1079,7 +1180,10 @@
             PendingIntent intent, String packageName) {
         if (request == null) request = DEFAULT_LOCATION_REQUEST;
         checkPackageName(packageName);
-        checkPermissionAndRequest(request);
+        int allowedResolutionLevel = getCallerAllowedResolutionLevel();
+        checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
+                request.getProvider());
+        LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
 
         final int pid = Binder.getCallingPid();
         final int uid = Binder.getCallingUid();
@@ -1089,7 +1193,7 @@
         long identity = Binder.clearCallingIdentity();
         try {
             synchronized (mLock) {
-                requestLocationUpdatesLocked(request, recevier, pid, uid, packageName);
+                requestLocationUpdatesLocked(sanitizedRequest, recevier, pid, uid, packageName);
             }
         } finally {
             Binder.restoreCallingIdentity(identity);
@@ -1132,7 +1236,7 @@
     public void removeUpdates(ILocationListener listener, PendingIntent intent,
             String packageName) {
         checkPackageName(packageName);
-        checkPermission();
+
         final int pid = Binder.getCallingPid();
         final int uid = Binder.getCallingUid();
         Receiver receiver = checkListenerOrIntent(listener, intent, pid, uid, packageName);
@@ -1188,8 +1292,11 @@
     public Location getLastLocation(LocationRequest request, String packageName) {
         if (D) Log.d(TAG, "getLastLocation: " + request);
         if (request == null) request = DEFAULT_LOCATION_REQUEST;
-        String perm = checkPermissionAndRequest(request);
+        int allowedResolutionLevel = getCallerAllowedResolutionLevel();
         checkPackageName(packageName);
+        checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
+                request.getProvider());
+        // no need to sanitize this request, as only the provider name is used
 
         long identity = Binder.clearCallingIdentity();
         try {
@@ -1213,13 +1320,13 @@
                 if (location == null) {
                     return null;
                 }
-                if (ACCESS_FINE_LOCATION.equals(perm)) {
-                    return location;
-                } else {
+                if (allowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
                     Location noGPSLocation = location.getExtraLocation(Location.EXTRA_NO_GPS_LOCATION);
                     if (noGPSLocation != null) {
                         return mLocationFudger.getOrCreate(noGPSLocation);
                     }
+                } else {
+                    return location;
                 }
             }
             return null;
@@ -1232,18 +1339,21 @@
     public void requestGeofence(LocationRequest request, Geofence geofence, PendingIntent intent,
             String packageName) {
         if (request == null) request = DEFAULT_LOCATION_REQUEST;
-        checkGeofencePermission();
-        checkPermissionAndRequest(request);
+        int allowedResolutionLevel = getCallerAllowedResolutionLevel();
+        checkResolutionLevelIsSufficientForGeofenceUse(allowedResolutionLevel);
         checkPendingIntent(intent);
         checkPackageName(packageName);
+        checkResolutionLevelIsSufficientForProviderUse(allowedResolutionLevel,
+                request.getProvider());
+        LocationRequest sanitizedRequest = createSanitizedRequest(request, allowedResolutionLevel);
 
-        if (D) Log.d(TAG, "requestGeofence: " + request + " " + geofence + " " + intent);
+        if (D) Log.d(TAG, "requestGeofence: " + sanitizedRequest + " " + geofence + " " + intent);
 
         // geo-fence manager uses the public location API, need to clear identity
         int uid = Binder.getCallingUid();
         long identity = Binder.clearCallingIdentity();
         try {
-            mGeofenceManager.addFence(request, geofence, intent, uid, packageName);
+            mGeofenceManager.addFence(sanitizedRequest, geofence, intent, uid, packageName);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
@@ -1251,7 +1361,7 @@
 
     @Override
     public void removeGeofence(Geofence geofence, PendingIntent intent, String packageName) {
-        checkGeofencePermission();
+        checkResolutionLevelIsSufficientForGeofenceUse(getCallerAllowedResolutionLevel());
         checkPendingIntent(intent);
         checkPackageName(packageName);
 
@@ -1272,10 +1382,8 @@
         if (mGpsStatusProvider == null) {
             return false;
         }
-        if (mContext.checkCallingOrSelfPermission(ACCESS_FINE_LOCATION) !=
-                PackageManager.PERMISSION_GRANTED) {
-            throw new SecurityException("Requires ACCESS_FINE_LOCATION permission");
-        }
+        checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
+                LocationManager.GPS_PROVIDER);
 
         try {
             mGpsStatusProvider.addGpsStatusListener(listener);
@@ -1303,8 +1411,9 @@
             // throw NullPointerException to remain compatible with previous implementation
             throw new NullPointerException();
         }
+        checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
+                provider);
 
-        checkPermission();
         // and check for ACCESS_LOCATION_EXTRA_COMMANDS
         if ((mContext.checkCallingOrSelfPermission(ACCESS_LOCATION_EXTRA_COMMANDS)
                 != PackageManager.PERMISSION_GRANTED)) {
@@ -1340,7 +1449,12 @@
      */
     @Override
     public ProviderProperties getProviderProperties(String provider) {
-        checkPermissionForProvider(getBestCallingPermission(), provider);
+        if (mProvidersByName.get(provider) == null) {
+          return null;
+        }
+
+        checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
+                provider);
 
         LocationProviderInterface p;
         synchronized (mLock) {
@@ -1353,7 +1467,8 @@
 
     @Override
     public boolean isProviderEnabled(String provider) {
-        checkPermissionForProvider(getBestCallingPermission(), provider);
+        checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
+                provider);
         if (LocationManager.FUSED_PROVIDER.equals(provider)) return false;
 
         long identity = Binder.clearCallingIdentity();
@@ -1518,10 +1633,10 @@
             }
 
             Location notifyLocation = null;
-            if (ACCESS_FINE_LOCATION.equals(receiver.mPermission)) {
-                notifyLocation = lastLocation;  // use fine location
+            if (receiver.mAllowedResolutionLevel < RESOLUTION_LEVEL_FINE) {
+                notifyLocation = coarseLocation;  // use coarse location
             } else {
-                notifyLocation = coarseLocation;  // use coarse location if available
+                notifyLocation = lastLocation;  // use fine location
             }
             if (notifyLocation != null) {
                 Location lastLoc = r.mLastFixBroadcast;
diff --git a/services/java/com/android/server/ServiceWatcher.java b/services/java/com/android/server/ServiceWatcher.java
index 5598b0a..2e7c6d1 100644
--- a/services/java/com/android/server/ServiceWatcher.java
+++ b/services/java/com/android/server/ServiceWatcher.java
@@ -43,7 +43,7 @@
  */
 public class ServiceWatcher implements ServiceConnection {
     private static final boolean D = false;
-    private static final String EXTRA_VERSION = "version";
+    public static final String EXTRA_SERVICE_VERSION = "serviceVersion";
 
     private final String mTag;
     private final Context mContext;
@@ -58,9 +58,27 @@
     // all fields below synchronized on mLock
     private IBinder mBinder;   // connected service
     private String mPackageName;  // current best package
-    private int mVersion;  // current best version
+    private int mVersion = Integer.MIN_VALUE;  // current best version
     private int mCurrentUserId;
 
+    public static ArrayList<HashSet<Signature>> getSignatureSets(Context context,
+            List<String> initialPackageNames) {
+        PackageManager pm = context.getPackageManager();
+        ArrayList<HashSet<Signature>> sigSets = new ArrayList<HashSet<Signature>>();
+        for (int i = 0, size = initialPackageNames.size(); i < size; i++) {
+            String pkg = initialPackageNames.get(i);
+            try {
+                HashSet<Signature> set = new HashSet<Signature>();
+                Signature[] sigs = pm.getPackageInfo(pkg, PackageManager.GET_SIGNATURES).signatures;
+                set.addAll(Arrays.asList(sigs));
+                sigSets.add(set);
+            } catch (NameNotFoundException e) {
+                Log.w("ServiceWatcher", pkg + " not found");
+            }
+        }
+        return sigSets;
+    }
+
     public ServiceWatcher(Context context, String logTag, String action,
             List<String> initialPackageNames, Runnable newServiceWork, Handler handler, int userId) {
         mContext = context;
@@ -71,20 +89,7 @@
         mHandler = handler;
         mCurrentUserId = userId;
 
-        mSignatureSets = new ArrayList<HashSet<Signature>>();
-        for (int i=0; i < initialPackageNames.size(); i++) {
-            String pkg = initialPackageNames.get(i);
-            HashSet<Signature> set = new HashSet<Signature>();
-            try {
-                Signature[] sigs =
-                        mPm.getPackageInfo(pkg, PackageManager.GET_SIGNATURES).signatures;
-                set.addAll(Arrays.asList(sigs));
-                mSignatureSets.add(set);
-            } catch (NameNotFoundException e) {
-                Log.w(logTag, pkg + " not found");
-            }
-        }
-
+        mSignatureSets = getSignatureSets(context, initialPackageNames);
     }
 
     public boolean start() {
@@ -132,15 +137,16 @@
             // check version
             int version = 0;
             if (rInfo.serviceInfo.metaData != null) {
-                version = rInfo.serviceInfo.metaData.getInt(EXTRA_VERSION, 0);
+                version = rInfo.serviceInfo.metaData.getInt(EXTRA_SERVICE_VERSION, 0);
             }
+
             if (version > mVersion) {
                 bestVersion = version;
                 bestPackage = packageName;
             }
         }
 
-        if (D) Log.d(mTag, String.format("bindBestPackage %s found %d, %s",
+        if (D) Log.d(mTag, String.format("bindBestPackage for %s : %s found %d, %s", mAction,
                 (justCheckThisPackage == null ? "" : "(" + justCheckThisPackage + ") "),
                 rInfos.size(),
                 (bestPackage == null ? "no new best package" : "new best packge: " + bestPackage)));
@@ -174,7 +180,8 @@
                 | Context.BIND_ALLOW_OOM_MANAGEMENT | Context.BIND_NOT_VISIBLE, mCurrentUserId);
     }
 
-    private boolean isSignatureMatch(Signature[] signatures) {
+    public static boolean isSignatureMatch(Signature[] signatures,
+            List<HashSet<Signature>> sigSets) {
         if (signatures == null) return false;
 
         // build hashset of input to test against
@@ -184,7 +191,7 @@
         }
 
         // test input against each of the signature sets
-        for (HashSet<Signature> referenceSet : mSignatureSets) {
+        for (HashSet<Signature> referenceSet : sigSets) {
             if (referenceSet.equals(inputSet)) {
                 return true;
             }
@@ -192,6 +199,10 @@
         return false;
     }
 
+    private boolean isSignatureMatch(Signature[] signatures) {
+        return isSignatureMatch(signatures, mSignatureSets);
+    }
+
     private final PackageMonitor mPackageMonitor = new PackageMonitor() {
         /**
          * Called when package has been reinstalled
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index eaaf33f..e46afd3 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -737,7 +737,7 @@
             }
             
             if (context.getResources().getBoolean(
-                    com.android.internal.R.bool.config_enableDreams)) {
+                    com.android.internal.R.bool.config_dreamsSupported)) {
                 try {
                     Slog.i(TAG, "Dreams Service");
                     // Dreams (interactive idle-time views, a/k/a screen savers)
diff --git a/services/java/com/android/server/WallpaperManagerService.java b/services/java/com/android/server/WallpaperManagerService.java
index e0f3814..a02fc8d 100644
--- a/services/java/com/android/server/WallpaperManagerService.java
+++ b/services/java/com/android/server/WallpaperManagerService.java
@@ -458,15 +458,21 @@
 
         IntentFilter userFilter = new IntentFilter();
         userFilter.addAction(Intent.ACTION_USER_REMOVED);
+        userFilter.addAction(Intent.ACTION_USER_STOPPING);
         mContext.registerReceiver(new BroadcastReceiver() {
             @Override
             public void onReceive(Context context, Intent intent) {
                 String action = intent.getAction();
                 if (Intent.ACTION_USER_REMOVED.equals(action)) {
-                    removeUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
+                    onRemoveUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
+                            UserHandle.USER_NULL));
+                } else if (Intent.ACTION_USER_STOPPING.equals(action)) {
+                    onStoppingUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
+                            UserHandle.USER_NULL));
                 }
             }
         }, userFilter);
+
         try {
             ActivityManagerNative.getDefault().registerUserSwitchObserver(
                     new IUserSwitchObserver.Stub() {
@@ -491,13 +497,24 @@
         }
     }
 
-    void removeUser(int userId) {
+    void onStoppingUser(int userId) {
+        if (userId < 1) return;
         synchronized (mLock) {
             WallpaperData wallpaper = mWallpaperMap.get(userId);
             if (wallpaper != null) {
-                wallpaper.wallpaperObserver.stopWatching();
+                if (wallpaper.wallpaperObserver != null) {
+                    wallpaper.wallpaperObserver.stopWatching();
+                    wallpaper.wallpaperObserver = null;
+                }
                 mWallpaperMap.remove(userId);
             }
+        }
+    }
+
+    void onRemoveUser(int userId) {
+        if (userId < 1) return;
+        synchronized (mLock) {
+            onStoppingUser(userId);
             File wallpaperFile = new File(getWallpaperDir(userId), WALLPAPER);
             wallpaperFile.delete();
             File wallpaperInfoFile = new File(getWallpaperDir(userId), WALLPAPER_INFO);
diff --git a/services/java/com/android/server/accessibility/ScreenMagnifier.java b/services/java/com/android/server/accessibility/ScreenMagnifier.java
index c8931f4..482bff5 100644
--- a/services/java/com/android/server/accessibility/ScreenMagnifier.java
+++ b/services/java/com/android/server/accessibility/ScreenMagnifier.java
@@ -38,7 +38,9 @@
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.SystemClock;
 import android.provider.Settings;
+import android.text.TextUtils;
 import android.util.Property;
 import android.util.Slog;
 import android.view.Display;
@@ -70,6 +72,7 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.Locale;
 
 /**
  * This class handles the screen magnification when accessibility is enabled.
@@ -173,6 +176,8 @@
     private PointerCoords[] mTempPointerCoords;
     private PointerProperties[] mTempPointerProperties;
 
+    private long mDelegatingStateDownTime;
+
     public ScreenMagnifier(Context context) {
         mContext = context;
         mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
@@ -262,10 +267,15 @@
 
     private void handleMotionEventStateDelegating(MotionEvent event,
             MotionEvent rawEvent, int policyFlags) {
-        if (event.getActionMasked() == MotionEvent.ACTION_UP) {
-            if (mDetectingStateHandler.mDelayedEventQueue == null) {
-                transitionToState(STATE_DETECTING);
-            }
+        switch (event.getActionMasked()) {
+            case MotionEvent.ACTION_DOWN: {
+                mDelegatingStateDownTime = event.getDownTime();
+            } break;
+            case MotionEvent.ACTION_UP: {
+                if (mDetectingStateHandler.mDelayedEventQueue == null) {
+                    transitionToState(STATE_DETECTING);
+                }
+            } break;
         }
         if (mNext != null) {
             // If the event is within the magnified portion of the screen we have
@@ -292,6 +302,13 @@
                         coords, 0, 0, 1.0f, 1.0f, event.getDeviceId(), 0, event.getSource(),
                         event.getFlags());
             }
+            // We cache some events to see if the user wants to trigger magnification.
+            // If no magnification is triggered we inject these events with adjusted
+            // time and down time to prevent subsequent transformations being confused
+            // by stale events. After the cached events, which always have a down, are
+            // injected we need to also update the down time of all subsequent non cached
+            // events. All delegated events cached and non-cached are delivered here.
+            event.setDownTime(mDelegatingStateDownTime);
             mNext.onMotionEvent(event, rawEvent, policyFlags);
         }
     }
@@ -662,12 +679,33 @@
             while (mDelayedEventQueue != null) {
                 MotionEventInfo info = mDelayedEventQueue;
                 mDelayedEventQueue = info.mNext;
-                ScreenMagnifier.this.onMotionEvent(info.mEvent, info.mRawEvent,
-                        info.mPolicyFlags);
+                final long offset = SystemClock.uptimeMillis() - info.mCachedTimeMillis;
+                MotionEvent event = obtainEventWithOffsetTimeAndDownTime(info.mEvent, offset);
+                MotionEvent rawEvent = obtainEventWithOffsetTimeAndDownTime(info.mRawEvent, offset);
+                ScreenMagnifier.this.onMotionEvent(event, rawEvent, info.mPolicyFlags);
+                event.recycle();
+                rawEvent.recycle();
                 info.recycle();
             }
         }
 
+        private MotionEvent obtainEventWithOffsetTimeAndDownTime(MotionEvent event, long offset) {
+            final int pointerCount = event.getPointerCount();
+            PointerCoords[] coords = getTempPointerCoordsWithMinSize(pointerCount);
+            PointerProperties[] properties = getTempPointerPropertiesWithMinSize(pointerCount);
+            for (int i = 0; i < pointerCount; i++) {
+                event.getPointerCoords(i, coords[i]);
+                event.getPointerProperties(i, properties[i]);
+            }
+            final long downTime = event.getDownTime() + offset;
+            final long eventTime = event.getEventTime() + offset;
+            return MotionEvent.obtain(downTime, eventTime,
+                    event.getAction(), pointerCount, properties, coords,
+                    event.getMetaState(), event.getButtonState(),
+                    1.0f, 1.0f, event.getDeviceId(), event.getEdgeFlags(),
+                    event.getSource(), event.getFlags());
+        }
+
         private void clearDelayedMotionEvents() {
             while (mDelayedEventQueue != null) {
                 MotionEventInfo info = mDelayedEventQueue;
@@ -746,6 +784,7 @@
         public MotionEvent mEvent;
         public MotionEvent mRawEvent;
         public int mPolicyFlags;
+        public long mCachedTimeMillis;
 
         public static MotionEventInfo obtain(MotionEvent event, MotionEvent rawEvent,
                 int policyFlags) {
@@ -770,6 +809,7 @@
             mEvent = MotionEvent.obtain(event);
             mRawEvent = MotionEvent.obtain(rawEvent);
             mPolicyFlags = policyFlags;
+            mCachedTimeMillis = SystemClock.uptimeMillis();
         }
 
         public void recycle() {
@@ -793,6 +833,7 @@
             mRawEvent.recycle();
             mRawEvent = null;
             mPolicyFlags = 0;
+            mCachedTimeMillis = 0;
         }
     }
 
@@ -850,6 +891,7 @@
         private static final int MESSAGE_ON_RECTANGLE_ON_SCREEN_REQUESTED = 3;
         private static final int MESSAGE_ON_WINDOW_TRANSITION = 4;
         private static final int MESSAGE_ON_ROTATION_CHANGED = 5;
+        private static final int MESSAGE_ON_WINDOW_LAYERS_CHANGED = 6;
 
         private final Handler mHandler = new MyHandler();
 
@@ -880,24 +922,8 @@
             mDisplayContentChangeListener = new IDisplayContentChangeListener.Stub() {
                 @Override
                 public void onWindowTransition(int displayId, int transition, WindowInfo info) {
-                    Message message = mHandler.obtainMessage(MESSAGE_ON_WINDOW_TRANSITION,
-                            transition, 0, WindowInfo.obtain(info));
-                    // TODO: This makes me quite unhappy but for the time being the
-                    //       least risky fix for cases where the keyguard is removed but
-                    //       the windows it force hides are not made visible yet. Hence,
-                    //       we would compute the magnified frame before we have a stable
-                    //       state. One more reason to move the magnified frame computation
-                    //       in the window manager!
-                    if (info.type == WindowManager.LayoutParams.TYPE_KEYGUARD
-                                || info.type == WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG
-                            && (transition == WindowManagerPolicy.TRANSIT_EXIT
-                                || transition == WindowManagerPolicy.TRANSIT_HIDE)) {
-                        final long delay = (long) (2 * mLongAnimationDuration
-                                * mWindowAnimationScale);
-                        mHandler.sendMessageDelayed(message, delay);
-                    } else {
-                        message.sendToTarget();
-                    }
+                    mHandler.obtainMessage(MESSAGE_ON_WINDOW_TRANSITION,
+                            transition, 0, WindowInfo.obtain(info)).sendToTarget();
                 }
 
                 @Override
@@ -917,6 +943,11 @@
                     mHandler.obtainMessage(MESSAGE_ON_ROTATION_CHANGED, rotation, 0)
                             .sendToTarget();
                 }
+
+                @Override
+                public void onWindowLayersChanged(int displayId) throws RemoteException {
+                    mHandler.sendEmptyMessage(MESSAGE_ON_WINDOW_LAYERS_CHANGED);
+                }
             };
 
             try {
@@ -985,45 +1016,44 @@
                             mViewport.recomputeBounds(mMagnificationController.isMagnifying());
                         } break;
                     }
-                } else {
-                    switch (transition) {
-                        case WindowManagerPolicy.TRANSIT_ENTER:
-                        case WindowManagerPolicy.TRANSIT_SHOW: {
-                            if (!magnifying || !isScreenMagnificationAutoUpdateEnabled(mContext)) {
-                                break;
-                            }
-                            final int type = info.type;
-                            switch (type) {
-                                // TODO: Are these all the windows we want to make
-                                //       visible when they appear on the screen?
-                                //       Do we need to take some of them out?
-                                case WindowManager.LayoutParams.TYPE_APPLICATION:
-                                case WindowManager.LayoutParams.TYPE_APPLICATION_PANEL:
-                                case WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA:
-                                case WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL:
-                                case WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG:
-                                case WindowManager.LayoutParams.TYPE_SEARCH_BAR:
-                                case WindowManager.LayoutParams.TYPE_PHONE:
-                                case WindowManager.LayoutParams.TYPE_SYSTEM_ALERT:
-                                case WindowManager.LayoutParams.TYPE_TOAST:
-                                case WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY:
-                                case WindowManager.LayoutParams.TYPE_PRIORITY_PHONE:
-                                case WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG:
-                                case WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG:
-                                case WindowManager.LayoutParams.TYPE_SYSTEM_ERROR:
-                                case WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY:
-                                case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL:
-                                case WindowManager.LayoutParams.TYPE_RECENTS_OVERLAY: {
-                                    Rect magnifiedRegionBounds = mMagnificationController
-                                            .getMagnifiedRegionBounds();
-                                    Rect touchableRegion = info.touchableRegion;
-                                    if (!magnifiedRegionBounds.intersect(touchableRegion)) {
-                                        ensureRectangleInMagnifiedRegionBounds(
-                                                magnifiedRegionBounds, touchableRegion);
-                                    }
-                                } break;
-                            } break;
+                }
+                switch (transition) {
+                    case WindowManagerPolicy.TRANSIT_ENTER:
+                    case WindowManagerPolicy.TRANSIT_SHOW: {
+                        if (!magnifying || !isScreenMagnificationAutoUpdateEnabled(mContext)) {
+                            break;
                         }
+                        final int type = info.type;
+                        switch (type) {
+                            // TODO: Are these all the windows we want to make
+                            //       visible when they appear on the screen?
+                            //       Do we need to take some of them out?
+                            case WindowManager.LayoutParams.TYPE_APPLICATION:
+                            case WindowManager.LayoutParams.TYPE_APPLICATION_PANEL:
+                            case WindowManager.LayoutParams.TYPE_APPLICATION_MEDIA:
+                            case WindowManager.LayoutParams.TYPE_APPLICATION_SUB_PANEL:
+                            case WindowManager.LayoutParams.TYPE_APPLICATION_ATTACHED_DIALOG:
+                            case WindowManager.LayoutParams.TYPE_SEARCH_BAR:
+                            case WindowManager.LayoutParams.TYPE_PHONE:
+                            case WindowManager.LayoutParams.TYPE_SYSTEM_ALERT:
+                            case WindowManager.LayoutParams.TYPE_TOAST:
+                            case WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY:
+                            case WindowManager.LayoutParams.TYPE_PRIORITY_PHONE:
+                            case WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG:
+                            case WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG:
+                            case WindowManager.LayoutParams.TYPE_SYSTEM_ERROR:
+                            case WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY:
+                            case WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL:
+                            case WindowManager.LayoutParams.TYPE_RECENTS_OVERLAY: {
+                                Rect magnifiedRegionBounds = mMagnificationController
+                                        .getMagnifiedRegionBounds();
+                                Rect touchableRegion = info.touchableRegion;
+                                if (!magnifiedRegionBounds.intersect(touchableRegion)) {
+                                    ensureRectangleInMagnifiedRegionBounds(
+                                            magnifiedRegionBounds, touchableRegion);
+                                }
+                            } break;
+                        } break;
                     }
                 }
             } finally {
@@ -1052,7 +1082,12 @@
             final float scrollX;
             final float scrollY;
             if (rectangle.width() > magnifiedRegionBounds.width()) {
-                scrollX = rectangle.left - magnifiedRegionBounds.left;
+                final int direction = TextUtils.getLayoutDirectionFromLocale(Locale.getDefault());
+                if (direction == View.LAYOUT_DIRECTION_LTR) {
+                    scrollX = rectangle.left - magnifiedRegionBounds.left;
+                } else {
+                    scrollX = rectangle.right - magnifiedRegionBounds.right;
+                }
             } else if (rectangle.left < magnifiedRegionBounds.left) {
                 scrollX = rectangle.left - magnifiedRegionBounds.left;
             } else if (rectangle.right > magnifiedRegionBounds.right) {
@@ -1192,6 +1227,9 @@
                         final int rotation = message.arg1;
                         handleOnRotationChanged(rotation);
                     } break;
+                    case MESSAGE_ON_WINDOW_LAYERS_CHANGED: {
+                        mViewport.recomputeBounds(mMagnificationController.isMagnifying());
+                    } break;
                     default: {
                         throw new IllegalArgumentException("Unknown message: " + action);
                     }
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 29245bc..9640386 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -7253,11 +7253,11 @@
         // care about.
         if (persistent) {
             final ContentResolver resolver = mContext.getContentResolver();
-            Settings.System.putString(
-                resolver, Settings.System.DEBUG_APP,
+            Settings.Global.putString(
+                resolver, Settings.Global.DEBUG_APP,
                 packageName);
-            Settings.System.putInt(
-                resolver, Settings.System.WAIT_FOR_DEBUGGER,
+            Settings.Global.putInt(
+                resolver, Settings.Global.WAIT_FOR_DEBUGGER,
                 waitForDebugger ? 1 : 0);
         }
 
@@ -7319,9 +7319,9 @@
         enforceCallingPermission(android.Manifest.permission.SET_ALWAYS_FINISH,
                 "setAlwaysFinish()");
 
-        Settings.System.putInt(
+        Settings.Global.putInt(
                 mContext.getContentResolver(),
-                Settings.System.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
+                Settings.Global.ALWAYS_FINISH_ACTIVITIES, enabled ? 1 : 0);
         
         synchronized (this) {
             mAlwaysFinishActivities = enabled;
@@ -7598,12 +7598,12 @@
 
     private void retrieveSettings() {
         final ContentResolver resolver = mContext.getContentResolver();
-        String debugApp = Settings.System.getString(
-            resolver, Settings.System.DEBUG_APP);
-        boolean waitForDebugger = Settings.System.getInt(
-            resolver, Settings.System.WAIT_FOR_DEBUGGER, 0) != 0;
-        boolean alwaysFinishActivities = Settings.System.getInt(
-            resolver, Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
+        String debugApp = Settings.Global.getString(
+            resolver, Settings.Global.DEBUG_APP);
+        boolean waitForDebugger = Settings.Global.getInt(
+            resolver, Settings.Global.WAIT_FOR_DEBUGGER, 0) != 0;
+        boolean alwaysFinishActivities = Settings.Global.getInt(
+            resolver, Settings.Global.ALWAYS_FINISH_ACTIVITIES, 0) != 0;
 
         Configuration configuration = new Configuration();
         Settings.System.getConfiguration(resolver, configuration);
@@ -11121,8 +11121,8 @@
     // instantiated.  The backup agent will invoke backupAgentCreated() on the
     // activity manager to announce its creation.
     public boolean bindBackupAgent(ApplicationInfo app, int backupMode) {
-        if (DEBUG_BACKUP) Slog.v(TAG, "startBackupAgent: app=" + app + " mode=" + backupMode);
-        enforceCallingPermission("android.permission.BACKUP", "startBackupAgent");
+        if (DEBUG_BACKUP) Slog.v(TAG, "bindBackupAgent: app=" + app + " mode=" + backupMode);
+        enforceCallingPermission("android.permission.BACKUP", "bindBackupAgent");
 
         synchronized(this) {
             // !!! TODO: currently no check here that we're already bound
@@ -11183,6 +11183,17 @@
         return true;
     }
 
+    @Override
+    public void clearPendingBackup() {
+        if (DEBUG_BACKUP) Slog.v(TAG, "clearPendingBackup");
+        enforceCallingPermission("android.permission.BACKUP", "clearPendingBackup");
+
+        synchronized (this) {
+            mBackupTarget = null;
+            mBackupAppName = null;
+        }
+    }
+
     // A backup agent has just come up                    
     public void backupAgentCreated(String agentPackageName, IBinder agent) {
         if (DEBUG_BACKUP) Slog.v(TAG, "backupAgentCreated: " + agentPackageName
@@ -11219,32 +11230,34 @@
         }
 
         synchronized(this) {
-            if (mBackupAppName == null) {
-                Slog.w(TAG, "Unbinding backup agent with no active backup");
-                return;
-            }
-
-            if (!mBackupAppName.equals(appInfo.packageName)) {
-                Slog.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
-                return;
-            }
-
-            ProcessRecord proc = mBackupTarget.app;
-            mBackupTarget = null;
-            mBackupAppName = null;
-
-            // Not backing this app up any more; reset its OOM adjustment
-            updateOomAdjLocked(proc);
-
-            // If the app crashed during backup, 'thread' will be null here
-            if (proc.thread != null) {
-                try {
-                    proc.thread.scheduleDestroyBackupAgent(appInfo,
-                            compatibilityInfoForPackageLocked(appInfo));
-                } catch (Exception e) {
-                    Slog.e(TAG, "Exception when unbinding backup agent:");
-                    e.printStackTrace();
+            try {
+                if (mBackupAppName == null) {
+                    Slog.w(TAG, "Unbinding backup agent with no active backup");
+                    return;
                 }
+
+                if (!mBackupAppName.equals(appInfo.packageName)) {
+                    Slog.e(TAG, "Unbind of " + appInfo + " but is not the current backup target");
+                    return;
+                }
+
+                // Not backing this app up any more; reset its OOM adjustment
+                final ProcessRecord proc = mBackupTarget.app;
+                updateOomAdjLocked(proc);
+
+                // If the app crashed during backup, 'thread' will be null here
+                if (proc.thread != null) {
+                    try {
+                        proc.thread.scheduleDestroyBackupAgent(appInfo,
+                                compatibilityInfoForPackageLocked(appInfo));
+                    } catch (Exception e) {
+                        Slog.e(TAG, "Exception when unbinding backup agent:");
+                        e.printStackTrace();
+                    }
+                }
+            } finally {
+                mBackupTarget = null;
+                mBackupAppName = null;
             }
         }
     }
diff --git a/services/java/com/android/server/display/DisplayAdapter.java b/services/java/com/android/server/display/DisplayAdapter.java
index abc1d32..b411a0d 100644
--- a/services/java/com/android/server/display/DisplayAdapter.java
+++ b/services/java/com/android/server/display/DisplayAdapter.java
@@ -42,6 +42,7 @@
     public static final int DISPLAY_DEVICE_EVENT_CHANGED = 2;
     public static final int DISPLAY_DEVICE_EVENT_REMOVED = 3;
 
+    // Called with SyncRoot lock held.
     public DisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
             Context context, Handler handler, Listener listener, String name) {
         mSyncRoot = syncRoot;
diff --git a/services/java/com/android/server/display/DisplayDeviceInfo.java b/services/java/com/android/server/display/DisplayDeviceInfo.java
index b4dab86..e76bf44 100644
--- a/services/java/com/android/server/display/DisplayDeviceInfo.java
+++ b/services/java/com/android/server/display/DisplayDeviceInfo.java
@@ -17,6 +17,7 @@
 package com.android.server.display;
 
 import android.util.DisplayMetrics;
+import android.view.Surface;
 
 import libcore.util.Objects;
 
@@ -31,11 +32,21 @@
     public static final int FLAG_DEFAULT_DISPLAY = 1 << 0;
 
     /**
-     * Flag: Indicates that this display device can rotate to show contents in a
-     * different orientation.  Otherwise the rotation is assumed to be fixed in the
-     * natural orientation and the display manager should transform the content to fit.
+     * Flag: Indicates that the orientation of this display device is coupled to the
+     * rotation of its associated logical display.
+     * <p>
+     * This flag should be applied to the default display to indicate that the user
+     * physically rotates the display when content is presented in a different orientation.
+     * The display manager will apply a coordinate transformation assuming that the
+     * physical orientation of the display matches the logical orientation of its content.
+     * </p><p>
+     * The flag should not be set when the display device is mounted in a fixed orientation
+     * such as on a desk.  The display manager will apply a coordinate transformation
+     * such as a scale and translation to letterbox or pillarbox format under the
+     * assumption that the physical orientation of the display is invariant.
+     * </p>
      */
-    public static final int FLAG_SUPPORTS_ROTATION = 1 << 1;
+    public static final int FLAG_ROTATES_WITH_CONTENT = 1 << 1;
 
     /**
      * Flag: Indicates that this display device has secure video output, such as HDCP.
@@ -116,6 +127,17 @@
      */
     public int touch;
 
+    /**
+     * The additional rotation to apply to all content presented on the display device
+     * relative to its physical coordinate system.  Default is {@link Surface#ROTATION_0}.
+     * <p>
+     * This field can be used to compensate for the fact that the display has been
+     * physically rotated relative to its natural orientation such as an HDMI monitor
+     * that has been mounted sideways to appear to be portrait rather than landscape.
+     * </p>
+     */
+    public int rotation = Surface.ROTATION_0;
+
     public void setAssumedDensityForExternalDisplay(int width, int height) {
         densityDpi = Math.min(width, height) * DisplayMetrics.DENSITY_XHIGH / 1080;
         // Technically, these values should be smaller than the apparent density
@@ -139,7 +161,8 @@
                 && xDpi == other.xDpi
                 && yDpi == other.yDpi
                 && flags == other.flags
-                && touch == other.touch;
+                && touch == other.touch
+                && rotation == other.rotation;
     }
 
     @Override
@@ -157,14 +180,18 @@
         yDpi = other.yDpi;
         flags = other.flags;
         touch = other.touch;
+        rotation = other.rotation;
     }
 
     // For debugging purposes
     @Override
     public String toString() {
-        return "DisplayDeviceInfo{\"" + name + "\": " + width + " x " + height + ", " + refreshRate + " fps, "
+        return "DisplayDeviceInfo{\"" + name + "\": " + width + " x " + height + ", "
+                + refreshRate + " fps, "
                 + "density " + densityDpi + ", " + xDpi + " x " + yDpi + " dpi"
-                + ", touch " + touchToString(touch) + flagsToString(flags) + "}";
+                + ", touch " + touchToString(touch) + flagsToString(flags)
+                + ", rotation " + rotation
+                + "}";
     }
 
     private static String touchToString(int touch) {
@@ -185,8 +212,8 @@
         if ((flags & FLAG_DEFAULT_DISPLAY) != 0) {
             msg.append(", FLAG_DEFAULT_DISPLAY");
         }
-        if ((flags & FLAG_SUPPORTS_ROTATION) != 0) {
-            msg.append(", FLAG_SUPPORTS_ROTATION");
+        if ((flags & FLAG_ROTATES_WITH_CONTENT) != 0) {
+            msg.append(", FLAG_ROTATES_WITH_CONTENT");
         }
         if ((flags & FLAG_SECURE) != 0) {
             msg.append(", FLAG_SECURE");
diff --git a/services/java/com/android/server/display/DisplayManagerService.java b/services/java/com/android/server/display/DisplayManagerService.java
index 0a42528..e58a0a5cb 100644
--- a/services/java/com/android/server/display/DisplayManagerService.java
+++ b/services/java/com/android/server/display/DisplayManagerService.java
@@ -127,6 +127,13 @@
     // services should be started.  This option may disable certain display adapters.
     public boolean mOnlyCore;
 
+    // True if the display manager service should pretend there is only one display
+    // and only tell applications about the existence of the default logical display.
+    // The display manager can still mirror content to secondary displays but applications
+    // cannot present unique content on those displays.
+    // Used for demonstration purposes only.
+    private final boolean mSingleDisplayDemoMode;
+
     // All callback records indexed by calling process id.
     public final SparseArray<CallbackRecord> mCallbacks =
             new SparseArray<CallbackRecord>();
@@ -182,6 +189,7 @@
         mHandler = new DisplayManagerHandler(mainHandler.getLooper());
         mUiHandler = uiHandler;
         mDisplayAdapterListener = new DisplayAdapterListener();
+        mSingleDisplayDemoMode = SystemProperties.getBoolean("persist.demo.singledisplay", false);
 
         mHandler.sendEmptyMessage(MSG_REGISTER_DEFAULT_DISPLAY_ADAPTER);
     }
@@ -305,6 +313,8 @@
                     DisplayDevice device = mDisplayDevices.get(i);
                     device.blankLocked();
                 }
+
+                scheduleTraversalLocked(false);
             }
         }
     }
@@ -322,6 +332,8 @@
                     DisplayDevice device = mDisplayDevices.get(i);
                     device.unblankLocked();
                 }
+
+                scheduleTraversalLocked(false);
             }
         }
     }
@@ -627,6 +639,12 @@
             isDefault = false;
         }
 
+        if (!isDefault && mSingleDisplayDemoMode) {
+            Slog.i(TAG, "Not creating a logical display for a secondary display "
+                    + " because single display demo mode is enabled: " + deviceInfo);
+            return;
+        }
+
         final int displayId = assignDisplayIdLocked(isDefault);
         final int layerStack = assignLayerStackLocked(displayId);
 
@@ -755,7 +773,9 @@
                     + device.getDisplayDeviceInfoLocked());
             return;
         } else {
-            display.configureDisplayInTransactionLocked(device);
+            boolean isBlanked = (mAllDisplayBlankStateFromPowerManager
+                    == DISPLAY_BLANK_STATE_BLANKED);
+            display.configureDisplayInTransactionLocked(device, isBlanked);
         }
 
         // Update the viewports if needed.
@@ -851,6 +871,7 @@
             pw.println("  mNextNonDefaultDisplayId=" + mNextNonDefaultDisplayId);
             pw.println("  mDefaultViewport=" + mDefaultViewport);
             pw.println("  mExternalTouchViewport=" + mExternalTouchViewport);
+            pw.println("  mSingleDisplayDemoMode=" + mSingleDisplayDemoMode);
 
             IndentingPrintWriter ipw = new IndentingPrintWriter(pw, "    ");
             ipw.increaseIndent();
diff --git a/services/java/com/android/server/display/HeadlessDisplayAdapter.java b/services/java/com/android/server/display/HeadlessDisplayAdapter.java
index 7ec537f..919733d 100644
--- a/services/java/com/android/server/display/HeadlessDisplayAdapter.java
+++ b/services/java/com/android/server/display/HeadlessDisplayAdapter.java
@@ -29,6 +29,7 @@
 final class HeadlessDisplayAdapter extends DisplayAdapter {
     private static final String TAG = "HeadlessDisplayAdapter";
 
+    // Called with SyncRoot lock held.
     public HeadlessDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
             Context context, Handler handler, Listener listener) {
         super(syncRoot, context, handler, listener, TAG);
diff --git a/services/java/com/android/server/display/LocalDisplayAdapter.java b/services/java/com/android/server/display/LocalDisplayAdapter.java
index d780006..d6c5248 100644
--- a/services/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/java/com/android/server/display/LocalDisplayAdapter.java
@@ -20,6 +20,7 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
+import android.os.SystemProperties;
 import android.util.SparseArray;
 import android.view.DisplayEventReceiver;
 import android.view.Surface;
@@ -43,21 +44,21 @@
 
     private final SparseArray<LocalDisplayDevice> mDevices =
             new SparseArray<LocalDisplayDevice>();
-    private final HotplugDisplayEventReceiver mHotplugReceiver;
+    private HotplugDisplayEventReceiver mHotplugReceiver;
 
     private final PhysicalDisplayInfo mTempPhys = new PhysicalDisplayInfo();
 
+    // Called with SyncRoot lock held.
     public LocalDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
             Context context, Handler handler, Listener listener) {
         super(syncRoot, context, handler, listener, TAG);
-        mHotplugReceiver = new HotplugDisplayEventReceiver(handler.getLooper());
     }
 
     @Override
     public void registerLocked() {
-        // TODO: listen for notifications from Surface Flinger about
-        // built-in displays being added or removed and rescan as needed.
         super.registerLocked();
+
+        mHotplugReceiver = new HotplugDisplayEventReceiver(getHandler().getLooper());
         scanDisplaysLocked();
     }
 
@@ -135,7 +136,7 @@
                     mInfo.name = getContext().getResources().getString(
                             com.android.internal.R.string.display_manager_built_in_display_name);
                     mInfo.flags |= DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY
-                            | DisplayDeviceInfo.FLAG_SUPPORTS_ROTATION;
+                            | DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT;
                     mInfo.densityDpi = (int)(mPhys.density * 160 + 0.5f);
                     mInfo.xDpi = mPhys.xDpi;
                     mInfo.yDpi = mPhys.yDpi;
@@ -145,6 +146,12 @@
                             com.android.internal.R.string.display_manager_hdmi_display_name);
                     mInfo.touch = DisplayDeviceInfo.TOUCH_EXTERNAL;
                     mInfo.setAssumedDensityForExternalDisplay(mPhys.width, mPhys.height);
+
+                    // For demonstration purposes, allow rotation of the external display.
+                    // In the future we might allow the user to configure this directly.
+                    if ("portrait".equals(SystemProperties.get("persist.demo.hdmirotation"))) {
+                        mInfo.rotation = Surface.ROTATION_270;
+                    }
                 }
             }
             return mInfo;
diff --git a/services/java/com/android/server/display/LogicalDisplay.java b/services/java/com/android/server/display/LogicalDisplay.java
index c4b749c..aa7ea82 100644
--- a/services/java/com/android/server/display/LogicalDisplay.java
+++ b/services/java/com/android/server/display/LogicalDisplay.java
@@ -55,6 +55,10 @@
 final class LogicalDisplay {
     private final DisplayInfo mBaseDisplayInfo = new DisplayInfo();
 
+    // The layer stack we use when the display has been blanked to prevent any
+    // of its content from appearing.
+    private static final int BLANK_LAYER_STACK = -1;
+
     private final int mDisplayId;
     private final int mLayerStack;
     private DisplayInfo mOverrideDisplayInfo; // set by the window manager
@@ -217,13 +221,15 @@
      * where the display is being mirrored.
      *
      * @param device The display device to modify.
+     * @param isBlanked True if the device is being blanked.
      */
-    public void configureDisplayInTransactionLocked(DisplayDevice device) {
+    public void configureDisplayInTransactionLocked(DisplayDevice device,
+            boolean isBlanked) {
         final DisplayInfo displayInfo = getDisplayInfoLocked();
         final DisplayDeviceInfo displayDeviceInfo = device.getDisplayDeviceInfoLocked();
 
         // Set the layer stack.
-        device.setLayerStackInTransactionLocked(mLayerStack);
+        device.setLayerStackInTransactionLocked(isBlanked ? BLANK_LAYER_STACK : mLayerStack);
 
         // Set the viewport.
         // This is the area of the logical display that we intend to show on the
@@ -235,10 +241,13 @@
         // is rotated when the contents of the logical display are rendered.
         int orientation = Surface.ROTATION_0;
         if (device == mPrimaryDisplayDevice
-                && (displayDeviceInfo.flags & DisplayDeviceInfo.FLAG_SUPPORTS_ROTATION) != 0) {
+                && (displayDeviceInfo.flags & DisplayDeviceInfo.FLAG_ROTATES_WITH_CONTENT) != 0) {
             orientation = displayInfo.rotation;
         }
 
+        // Apply the physical rotation of the display device itself.
+        orientation = (orientation + displayDeviceInfo.rotation) % 4;
+
         // Set the frame.
         // The frame specifies the rotated physical coordinates into which the viewport
         // is mapped.  We need to take care to preserve the aspect ratio of the viewport.
diff --git a/services/java/com/android/server/display/OverlayDisplayAdapter.java b/services/java/com/android/server/display/OverlayDisplayAdapter.java
index dfacf2a..937ebcf 100644
--- a/services/java/com/android/server/display/OverlayDisplayAdapter.java
+++ b/services/java/com/android/server/display/OverlayDisplayAdapter.java
@@ -64,6 +64,7 @@
             new ArrayList<OverlayDisplayHandle>();
     private String mCurrentOverlaySetting = "";
 
+    // Called with SyncRoot lock held.
     public OverlayDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
             Context context, Handler handler, Listener listener, Handler uiHandler) {
         super(syncRoot, context, handler, listener, TAG);
diff --git a/services/java/com/android/server/display/WifiDisplayAdapter.java b/services/java/com/android/server/display/WifiDisplayAdapter.java
index c441b02..f9d58af 100644
--- a/services/java/com/android/server/display/WifiDisplayAdapter.java
+++ b/services/java/com/android/server/display/WifiDisplayAdapter.java
@@ -16,17 +16,28 @@
 
 package com.android.server.display;
 
+import com.android.internal.R;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.IndentingPrintWriter;
 
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.res.Resources;
 import android.hardware.display.DisplayManager;
 import android.hardware.display.WifiDisplay;
 import android.hardware.display.WifiDisplayStatus;
 import android.media.RemoteDisplay;
 import android.os.Handler;
 import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.UserHandle;
+import android.provider.Settings;
 import android.util.Slog;
 import android.view.Surface;
 
@@ -52,8 +63,18 @@
 
     private static final boolean DEBUG = false;
 
+    private static final int MSG_SEND_STATUS_CHANGE_BROADCAST = 1;
+    private static final int MSG_UPDATE_NOTIFICATION = 2;
+
+    private static final String ACTION_DISCONNECT = "android.server.display.wfd.DISCONNECT";
+
+    private final WifiDisplayHandler mHandler;
     private final PersistentDataStore mPersistentDataStore;
     private final boolean mSupportsProtectedBuffers;
+    private final NotificationManager mNotificationManager;
+
+    private PendingIntent mSettingsPendingIntent;
+    private PendingIntent mDisconnectPendingIntent;
 
     private WifiDisplayController mDisplayController;
     private WifiDisplayDevice mDisplayDevice;
@@ -67,14 +88,19 @@
     private WifiDisplay[] mRememberedDisplays = WifiDisplay.EMPTY_ARRAY;
 
     private boolean mPendingStatusChangeBroadcast;
+    private boolean mPendingNotificationUpdate;
 
+    // Called with SyncRoot lock held.
     public WifiDisplayAdapter(DisplayManagerService.SyncRoot syncRoot,
             Context context, Handler handler, Listener listener,
             PersistentDataStore persistentDataStore) {
         super(syncRoot, context, handler, listener, TAG);
+        mHandler = new WifiDisplayHandler(handler.getLooper());
         mPersistentDataStore = persistentDataStore;
         mSupportsProtectedBuffers = context.getResources().getBoolean(
                 com.android.internal.R.bool.config_wifiDisplaySupportsProtectedBuffers);
+        mNotificationManager = (NotificationManager)context.getSystemService(
+                Context.NOTIFICATION_SERVICE);
     }
 
     @Override
@@ -89,6 +115,7 @@
         pw.println("mAvailableDisplays=" + Arrays.toString(mAvailableDisplays));
         pw.println("mRememberedDisplays=" + Arrays.toString(mRememberedDisplays));
         pw.println("mPendingStatusChangeBroadcast=" + mPendingStatusChangeBroadcast);
+        pw.println("mPendingNotificationUpdate=" + mPendingNotificationUpdate);
         pw.println("mSupportsProtectedBuffers=" + mSupportsProtectedBuffers);
 
         // Try to dump the controller state.
@@ -113,6 +140,9 @@
             public void run() {
                 mDisplayController = new WifiDisplayController(
                         getContext(), getHandler(), mWifiDisplayListener);
+
+                getContext().registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL,
+                        new IntentFilter(ACTION_DISCONNECT), null, mHandler);
             }
         });
     }
@@ -266,6 +296,8 @@
         mDisplayDevice = new WifiDisplayDevice(displayToken, name, width, height,
                 refreshRate, deviceFlags, surface);
         sendDisplayDeviceEventLocked(mDisplayDevice, DISPLAY_DEVICE_EVENT_ADDED);
+
+        scheduleUpdateNotificationLocked();
     }
 
     private void handleDisconnectLocked() {
@@ -273,6 +305,8 @@
             mDisplayDevice.clearSurfaceLocked();
             sendDisplayDeviceEventLocked(mDisplayDevice, DISPLAY_DEVICE_EVENT_REMOVED);
             mDisplayDevice = null;
+
+            scheduleUpdateNotificationLocked();
         }
     }
 
@@ -280,28 +314,100 @@
         mCurrentStatus = null;
         if (!mPendingStatusChangeBroadcast) {
             mPendingStatusChangeBroadcast = true;
-            getHandler().post(mStatusChangeBroadcast);
+            mHandler.sendEmptyMessage(MSG_SEND_STATUS_CHANGE_BROADCAST);
         }
     }
 
-    private final Runnable mStatusChangeBroadcast = new Runnable() {
-        @Override
-        public void run() {
-            final Intent intent;
-            synchronized (getSyncRoot()) {
-                if (!mPendingStatusChangeBroadcast) {
-                    return;
-                }
+    private void scheduleUpdateNotificationLocked() {
+        if (!mPendingNotificationUpdate) {
+            mPendingNotificationUpdate = true;
+            mHandler.sendEmptyMessage(MSG_UPDATE_NOTIFICATION);
+        }
+    }
 
-                mPendingStatusChangeBroadcast = false;
-                intent = new Intent(DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED);
-                intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
-                intent.putExtra(DisplayManager.EXTRA_WIFI_DISPLAY_STATUS,
-                        getWifiDisplayStatusLocked());
+    // Runs on the handler.
+    private void handleSendStatusChangeBroadcast() {
+        final Intent intent;
+        synchronized (getSyncRoot()) {
+            if (!mPendingStatusChangeBroadcast) {
+                return;
             }
 
-            // Send protected broadcast about wifi display status to registered receivers.
-            getContext().sendBroadcast(intent);
+            mPendingStatusChangeBroadcast = false;
+            intent = new Intent(DisplayManager.ACTION_WIFI_DISPLAY_STATUS_CHANGED);
+            intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+            intent.putExtra(DisplayManager.EXTRA_WIFI_DISPLAY_STATUS,
+                    getWifiDisplayStatusLocked());
+        }
+
+        // Send protected broadcast about wifi display status to registered receivers.
+        getContext().sendBroadcastAsUser(intent, UserHandle.ALL);
+    }
+
+    // Runs on the handler.
+    private void handleUpdateNotification() {
+        final boolean isConnected;
+        synchronized (getSyncRoot()) {
+            if (!mPendingNotificationUpdate) {
+                return;
+            }
+
+            mPendingNotificationUpdate = false;
+            isConnected = (mDisplayDevice != null);
+        }
+
+        // Cancel the old notification if there is one.
+        mNotificationManager.cancelAsUser(null,
+                R.string.wifi_display_notification_title, UserHandle.ALL);
+
+        if (isConnected) {
+            Context context = getContext();
+
+            // Initialize pending intents for the notification outside of the lock because
+            // creating a pending intent requires a call into the activity manager.
+            if (mSettingsPendingIntent == null) {
+                Intent settingsIntent = new Intent(Settings.ACTION_WIFI_DISPLAY_SETTINGS);
+                settingsIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
+                        | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
+                        | Intent.FLAG_ACTIVITY_CLEAR_TOP);
+                mSettingsPendingIntent = PendingIntent.getActivityAsUser(
+                        context, 0, settingsIntent, 0, null, UserHandle.CURRENT);
+            }
+
+            if (mDisconnectPendingIntent == null) {
+                Intent disconnectIntent = new Intent(ACTION_DISCONNECT);
+                mDisconnectPendingIntent = PendingIntent.getBroadcastAsUser(
+                        context, 0, disconnectIntent, 0, UserHandle.CURRENT);
+            }
+
+            // Post the notification.
+            Resources r = context.getResources();
+            Notification notification = new Notification.Builder(context)
+                    .setContentTitle(r.getString(
+                            R.string.wifi_display_notification_title))
+                    .setContentText(r.getString(
+                            R.string.wifi_display_notification_message))
+                    .setContentIntent(mSettingsPendingIntent)
+                    .setSmallIcon(R.drawable.ic_notify_wifidisplay)
+                    .setOngoing(true)
+                    .addAction(android.R.drawable.ic_menu_close_clear_cancel,
+                            r.getString(R.string.wifi_display_notification_disconnect),
+                            mDisconnectPendingIntent)
+                    .build();
+            mNotificationManager.notifyAsUser(null,
+                    R.string.wifi_display_notification_title,
+                    notification, UserHandle.ALL);
+        }
+    }
+
+    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (intent.getAction().equals(ACTION_DISCONNECT)) {
+                synchronized (getSyncRoot()) {
+                    requestDisconnectLocked();
+                }
+            }
         }
     };
 
@@ -454,4 +560,23 @@
             return mInfo;
         }
     }
+
+    private final class WifiDisplayHandler extends Handler {
+        public WifiDisplayHandler(Looper looper) {
+            super(looper, null, true /*async*/);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_SEND_STATUS_CHANGE_BROADCAST:
+                    handleSendStatusChangeBroadcast();
+                    break;
+
+                case MSG_UPDATE_NOTIFICATION:
+                    handleUpdateNotification();
+                    break;
+            }
+        }
+    }
 }
diff --git a/services/java/com/android/server/pm/UserManagerService.java b/services/java/com/android/server/pm/UserManagerService.java
index 4f9375a..072dd33 100644
--- a/services/java/com/android/server/pm/UserManagerService.java
+++ b/services/java/com/android/server/pm/UserManagerService.java
@@ -62,6 +62,8 @@
 
     private static final String LOG_TAG = "UserManagerService";
 
+    private static final boolean DBG = false;
+
     private static final String TAG_NAME = "name";
     private static final String ATTR_FLAGS = "flags";
     private static final String ATTR_ICON_PATH = "icon";
@@ -97,6 +99,9 @@
     private int[] mUserIds;
     private boolean mGuestEnabled;
     private int mNextSerialNumber;
+    // This resets on a reboot. Otherwise it keeps incrementing so that user ids are
+    // not reused in quick succession
+    private int mNextUserId = MIN_USER_ID;
 
     private static UserManagerService sInstance;
 
@@ -149,7 +154,7 @@
                         -1, -1);
                 mUserListFile = new File(mUsersDir, USER_LIST_FILENAME);
                 readUserListLocked();
-                // Prune out any partially created users.
+                // Prune out any partially created/partially removed users.
                 ArrayList<UserInfo> partials = new ArrayList<UserInfo>();
                 for (int i = 0; i < mUsers.size(); i++) {
                     UserInfo ui = mUsers.valueAt(i);
@@ -199,7 +204,8 @@
      */
     private UserInfo getUserInfoLocked(int userId) {
         UserInfo ui = mUsers.get(userId);
-        if (ui != null && ui.partial) {
+        // If it is partial and not in the process of being removed, return as unknown user.
+        if (ui != null && ui.partial && !mRemovingUserIds.contains(userId)) {
             Slog.w(LOG_TAG, "getUserInfo: unknown user #" + userId);
             return null;
         }
@@ -459,7 +465,7 @@
     private void fallbackToSingleUserLocked() {
         // Create the primary user
         UserInfo primary = new UserInfo(0, "Primary", null,
-                UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY);
+                UserInfo.FLAG_ADMIN | UserInfo.FLAG_PRIMARY | UserInfo.FLAG_INITIALIZED);
         mUsers.put(0, primary);
         mNextSerialNumber = MIN_USER_ID;
         updateUserIdsLocked();
@@ -668,6 +674,7 @@
                     long now = System.currentTimeMillis();
                     userInfo.creationTime = (now > EPOCH_PLUS_30_YEARS) ? now : 0;
                     userInfo.partial = true;
+                    Environment.getUserSystemDirectory(userInfo.id).mkdirs();
                     mUsers.put(userId, userInfo);
                     writeUserListLocked();
                     writeUserLocked(userInfo);
@@ -703,8 +710,13 @@
                 return false;
             }
             mRemovingUserIds.add(userHandle);
+            // Set this to a partially created user, so that the user will be purged
+            // on next startup, in case the runtime stops now before stopping and
+            // removing the user completely.
+            user.partial = true;
+            writeUserLocked(user);
         }
-
+        if (DBG) Slog.i(LOG_TAG, "Stopping user " + userHandle);
         int res;
         try {
             res = ActivityManagerNative.getDefault().stopUser(userHandle,
@@ -725,12 +737,13 @@
     }
 
     void finishRemoveUser(int userHandle) {
+        if (DBG) Slog.i(LOG_TAG, "finishRemoveUser " + userHandle);
         synchronized (mInstallLock) {
             synchronized (mPackagesLock) {
                 removeUserStateLocked(userHandle);
             }
         }
-
+        if (DBG) Slog.i(LOG_TAG, "Removed user " + userHandle + ", sending broadcast");
         // Let other services shutdown any activity
         long ident = Binder.clearCallingIdentity();
         try {
@@ -799,10 +812,11 @@
                 num++;
             }
         }
-        int[] newUsers = new int[num];
+        final int[] newUsers = new int[num];
+        int n = 0;
         for (int i = 0; i < mUsers.size(); i++) {
             if (!mUsers.valueAt(i).partial) {
-                newUsers[i] = mUsers.keyAt(i);
+                newUsers[n++] = mUsers.keyAt(i);
             }
         }
         mUserIds = newUsers;
@@ -835,13 +849,14 @@
      */
     private int getNextAvailableIdLocked() {
         synchronized (mPackagesLock) {
-            int i = MIN_USER_ID;
+            int i = mNextUserId;
             while (i < Integer.MAX_VALUE) {
                 if (mUsers.indexOfKey(i) < 0 && !mRemovingUserIds.contains(i)) {
                     break;
                 }
                 i++;
             }
+            mNextUserId = i + 1;
             return i;
         }
     }
diff --git a/services/java/com/android/server/power/DisplayPowerController.java b/services/java/com/android/server/power/DisplayPowerController.java
index 1561dba..661b949 100644
--- a/services/java/com/android/server/power/DisplayPowerController.java
+++ b/services/java/com/android/server/power/DisplayPowerController.java
@@ -128,28 +128,33 @@
     private static final float TYPICAL_PROXIMITY_THRESHOLD = 5.0f;
 
     // Light sensor event rate in microseconds.
-    private static final int LIGHT_SENSOR_RATE = 1000000;
+    private static final int LIGHT_SENSOR_RATE = 500 * 1000;
 
     // Brightness animation ramp rate in brightness units per second.
     private static final int BRIGHTNESS_RAMP_RATE_FAST = 200;
-    private static final int BRIGHTNESS_RAMP_RATE_SLOW = 40;
+    private static final int BRIGHTNESS_RAMP_RATE_SLOW = 30;
 
-    // Filter time constant in milliseconds for computing a moving
-    // average of light samples.  Different constants are used
-    // to calculate the average light level when adapting to brighter or
-    // dimmer environments.
-    // This parameter only controls the filtering of light samples.
-    private static final long BRIGHTENING_LIGHT_TIME_CONSTANT = 600;
-    private static final long DIMMING_LIGHT_TIME_CONSTANT = 4000;
+    // IIR filter time constants in milliseconds for computing two moving averages of
+    // the light samples.  One is a long-term average and the other is a short-term average.
+    // We can use these filters to assess trends in ambient brightness.
+    // The short term average gives us a filtered but relatively low latency measurement.
+    // The long term average informs us about the overall trend.
+    private static final long SHORT_TERM_AVERAGE_LIGHT_TIME_CONSTANT = 1000;
+    private static final long LONG_TERM_AVERAGE_LIGHT_TIME_CONSTANT = 8000;
 
     // Stability requirements in milliseconds for accepting a new brightness
     // level.  This is used for debouncing the light sensor.  Different constants
-    // are used to debounce the light sensor when adapting to brighter or dimmer
-    // environments.
+    // are used to debounce the light sensor when adapting to brighter or darker environments.
     // This parameter controls how quickly brightness changes occur in response to
-    // an observed change in light level.
-    private static final long BRIGHTENING_LIGHT_DEBOUNCE = 2500;
-    private static final long DIMMING_LIGHT_DEBOUNCE = 10000;
+    // an observed change in light level following a previous change in the opposite direction.
+    private static final long BRIGHTENING_LIGHT_DEBOUNCE = 5000;
+    private static final long DARKENING_LIGHT_DEBOUNCE = 15000;
+
+    // Hysteresis constraints for brightening or darkening.
+    // The recent lux must have changed by at least this fraction relative to the
+    // current ambient lux before a change will be considered.
+    private static final float BRIGHTENING_LIGHT_HYSTERESIS = 0.10f;
+    private static final float DARKENING_LIGHT_HYSTERESIS = 0.20f;
 
     private final Object mLock = new Object();
 
@@ -284,39 +289,28 @@
     // The time when the light sensor was enabled.
     private long mLightSensorEnableTime;
 
-    // The currently accepted average light sensor value.
-    private float mLightMeasurement;
+    // The currently accepted nominal ambient light level.
+    private float mAmbientLux;
 
-    // True if the light sensor measurement is valid.
-    private boolean mLightMeasurementValid;
+    // True if mAmbientLux holds a valid value.
+    private boolean mAmbientLuxValid;
 
-    // The number of light sensor samples that have been collected since the
-    // last time a light sensor reading was accepted.
-    private int mRecentLightSamples;
-
-    // The moving average of recent light sensor values.
-    private float mRecentLightAverage;
-
-    // True if recent light samples are getting brighter than the previous
-    // stable light measurement.
-    private boolean mRecentLightBrightening;
-
-    // The time constant to use for filtering based on whether the
-    // light appears to be brightening or dimming.
-    private long mRecentLightTimeConstant;
+    // The time when the ambient lux was last brightened or darkened.
+    private long mLastAmbientBrightenTime;
+    private long mLastAmbientDarkenTime;
 
     // The most recent light sample.
-    private float mLastLightSample;
+    private float mLastObservedLux;
 
     // The time of the most light recent sample.
-    private long mLastLightSampleTime;
+    private long mLastObservedLuxTime;
 
-    // The time when we accumulated the first recent light sample into mRecentLightSamples.
-    private long mFirstRecentLightSampleTime;
+    // The number of light samples collected since the light sensor was enabled.
+    private int mRecentLightSamples;
 
-    // The upcoming debounce light sensor time.
-    // This is only valid when mLightMeasurementValue && mRecentLightSamples >= 1.
-    private long mPendingLightSensorDebounceTime;
+    // The long-term and short-term filtered light measurements.
+    private float mRecentShortTermAverageLux;
+    private float mRecentLongTermAverageLux;
 
     // The screen brightness level that has been chosen by the auto-brightness
     // algorithm.  The actual brightness should ramp towards this value.
@@ -873,7 +867,8 @@
         } else {
             if (mLightSensorEnabled) {
                 mLightSensorEnabled = false;
-                mLightMeasurementValid = false;
+                mAmbientLuxValid = false;
+                mRecentLightSamples = 0;
                 mHandler.removeMessages(MSG_LIGHT_SENSOR_DEBOUNCED);
                 mSensorManager.unregisterListener(mLightSensorListener);
             }
@@ -884,114 +879,99 @@
     }
 
     private void handleLightSensorEvent(long time, float lux) {
-        // Take the first few readings during the warm-up period and apply them
-        // immediately without debouncing.
-        if (!mLightMeasurementValid
-                || (time - mLightSensorEnableTime) < mLightSensorWarmUpTimeConfig) {
-            mLightMeasurement = lux;
-            mLightMeasurementValid = true;
-            mRecentLightSamples = 0;
-            updateAutoBrightness(true);
-        }
-
-        // Update our moving average.
-        if (lux != mLightMeasurement && (mRecentLightSamples == 0
-                || (lux < mLightMeasurement && mRecentLightBrightening)
-                || (lux > mLightMeasurement && !mRecentLightBrightening))) {
-            // If the newest light sample doesn't seem to be going in the
-            // same general direction as recent samples, then start over.
-            setRecentLight(time, lux, lux > mLightMeasurement);
-        } else if (mRecentLightSamples >= 1) {
-            // Add the newest light sample to the moving average.
-            accumulateRecentLight(time, lux);
-        }
-        if (DEBUG) {
-            Slog.d(TAG, "handleLightSensorEvent: lux=" + lux
-                    + ", mLightMeasurementValid=" + mLightMeasurementValid
-                    + ", mLightMeasurement=" + mLightMeasurement
-                    + ", mRecentLightSamples=" + mRecentLightSamples
-                    + ", mRecentLightAverage=" + mRecentLightAverage
-                    + ", mRecentLightBrightening=" + mRecentLightBrightening
-                    + ", mRecentLightTimeConstant=" + mRecentLightTimeConstant
-                    + ", mFirstRecentLightSampleTime="
-                            + TimeUtils.formatUptime(mFirstRecentLightSampleTime)
-                    + ", mPendingLightSensorDebounceTime="
-                            + TimeUtils.formatUptime(mPendingLightSensorDebounceTime));
-        }
-
-        // Debounce.
-        mHandler.removeMessages(MSG_LIGHT_SENSOR_DEBOUNCED);
-        debounceLightSensor();
-    }
-
-    private void setRecentLight(long time, float lux, boolean brightening) {
-        mRecentLightBrightening = brightening;
-        mRecentLightTimeConstant = brightening ?
-                BRIGHTENING_LIGHT_TIME_CONSTANT : DIMMING_LIGHT_TIME_CONSTANT;
-        mRecentLightSamples = 1;
-        mRecentLightAverage = lux;
-        mLastLightSample = lux;
-        mLastLightSampleTime = time;
-        mFirstRecentLightSampleTime = time;
-        mPendingLightSensorDebounceTime = time + (brightening ?
-                BRIGHTENING_LIGHT_DEBOUNCE : DIMMING_LIGHT_DEBOUNCE);
-    }
-
-    private void accumulateRecentLight(long time, float lux) {
-        final long timeDelta = time - mLastLightSampleTime;
+        // Update our filters.
         mRecentLightSamples += 1;
-        mRecentLightAverage += (lux - mRecentLightAverage) *
-                timeDelta / (mRecentLightTimeConstant + timeDelta);
-        mLastLightSample = lux;
-        mLastLightSampleTime = time;
+        if (mRecentLightSamples == 1) {
+            mRecentShortTermAverageLux = lux;
+            mRecentLongTermAverageLux = lux;
+        } else {
+            final long timeDelta = time - mLastObservedLuxTime;
+            mRecentShortTermAverageLux += (lux - mRecentShortTermAverageLux)
+                    * timeDelta / (SHORT_TERM_AVERAGE_LIGHT_TIME_CONSTANT + timeDelta);
+            mRecentLongTermAverageLux += (lux - mRecentLongTermAverageLux)
+                    * timeDelta / (LONG_TERM_AVERAGE_LIGHT_TIME_CONSTANT + timeDelta);
+        }
+
+        // Remember this sample value.
+        mLastObservedLux = lux;
+        mLastObservedLuxTime = time;
+
+        // Update the ambient lux level.
+        mHandler.removeMessages(MSG_LIGHT_SENSOR_DEBOUNCED);
+        updateAmbientLux(time);
     }
 
-    private void debounceLightSensor() {
-        if (mLightMeasurementValid && mRecentLightSamples >= 1) {
-            final long now = SystemClock.uptimeMillis();
-            if (mPendingLightSensorDebounceTime <= now) {
-                accumulateRecentLight(now, mLastLightSample);
-                mLightMeasurement = mRecentLightAverage;
+    private void updateAmbientLux(long time) {
+        // If the light sensor was just turned on then immediately update our initial
+        // estimate of the current ambient light level.
+        if (!mAmbientLuxValid
+                || (time - mLightSensorEnableTime) < mLightSensorWarmUpTimeConfig) {
+            if (DEBUG) {
+                Slog.d(TAG, "updateAmbientLux: Initializing, "
+                        + "mAmbientLux=" + (mAmbientLuxValid ? mAmbientLux : -1)
+                        + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
+                        + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux);
+            }
+            mAmbientLux = mRecentShortTermAverageLux;
+            mAmbientLuxValid = true;
+            mLastAmbientBrightenTime = time;
+            mLastAmbientDarkenTime = time;
+            updateAutoBrightness(true);
+            return;
+        }
 
+        // Determine whether the ambient environment appears to be brightening.
+        float minAmbientLux = mAmbientLux * (1.0f + BRIGHTENING_LIGHT_HYSTERESIS);
+        if (mRecentShortTermAverageLux > minAmbientLux
+                && mRecentLongTermAverageLux > minAmbientLux) {
+            long debounceTime = mLastAmbientDarkenTime + BRIGHTENING_LIGHT_DEBOUNCE;
+            if (time >= debounceTime) {
                 if (DEBUG) {
-                    Slog.d(TAG, "debounceLightSensor: Accepted new measurement "
-                            + mLightMeasurement + " after "
-                            + (now - mFirstRecentLightSampleTime) + " ms based on "
-                            + mRecentLightSamples + " recent samples.");
+                    Slog.d(TAG, "updateAmbientLux: Brightened: "
+                            + "mAmbientLux=" + mAmbientLux
+                            + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
+                            + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux);
                 }
-
+                mLastAmbientBrightenTime = time;
+                mAmbientLux = mRecentShortTermAverageLux;
                 updateAutoBrightness(true);
-
-                // Now that we have debounced the light sensor data, we have the
-                // option of either leaving the sensor in a debounced state or
-                // restarting the debounce cycle by setting mRecentLightSamples to 0.
-                //
-                // If we leave the sensor debounced, then new average light measurements
-                // may be accepted immediately as long as they are trending in the same
-                // direction as they were before.  If the measurements start
-                // jittering or trending in the opposite direction then the debounce
-                // cycle will automatically be restarted.  The benefit is that the
-                // auto-brightness control can be more responsive to changes over a
-                // broad range.
-                //
-                // For now, we choose to be more responsive and leave the following line
-                // commented out.
-                //
-                // mRecentLightSamples = 0;
             } else {
-                Message msg = mHandler.obtainMessage(MSG_LIGHT_SENSOR_DEBOUNCED);
-                msg.setAsynchronous(true);
-                mHandler.sendMessageAtTime(msg, mPendingLightSensorDebounceTime);
+                mHandler.sendEmptyMessageAtTime(MSG_LIGHT_SENSOR_DEBOUNCED, debounceTime);
+            }
+            return;
+        }
+
+        // Determine whether the ambient environment appears to be darkening.
+        float maxAmbientLux = mAmbientLux * (1.0f - DARKENING_LIGHT_HYSTERESIS);
+        if (mRecentShortTermAverageLux < maxAmbientLux
+                && mRecentLongTermAverageLux < maxAmbientLux) {
+            long debounceTime = mLastAmbientBrightenTime + DARKENING_LIGHT_DEBOUNCE;
+            if (time >= debounceTime) {
+                if (DEBUG) {
+                    Slog.d(TAG, "updateAmbientLux: Darkened: "
+                            + "mAmbientLux=" + mAmbientLux
+                            + ", mRecentShortTermAverageLux=" + mRecentShortTermAverageLux
+                            + ", mRecentLongTermAverageLux=" + mRecentLongTermAverageLux);
+                }
+                mLastAmbientDarkenTime = time;
+                mAmbientLux = mRecentShortTermAverageLux;
+                updateAutoBrightness(true);
+            } else {
+                mHandler.sendEmptyMessageAtTime(MSG_LIGHT_SENSOR_DEBOUNCED, debounceTime);
             }
         }
     }
 
+    private void debounceLightSensor() {
+        updateAmbientLux(SystemClock.uptimeMillis());
+    }
+
     private void updateAutoBrightness(boolean sendUpdate) {
-        if (!mLightMeasurementValid) {
+        if (!mAmbientLuxValid) {
             return;
         }
 
-        float value = mScreenAutoBrightnessSpline.interpolate(mLightMeasurement);
+        float value = mScreenAutoBrightnessSpline.interpolate(mAmbientLux);
         float gamma = 1.0f;
 
         if (USE_SCREEN_AUTO_BRIGHTNESS_ADJUSTMENT
@@ -1031,7 +1011,7 @@
         }
 
         int newScreenAutoBrightness = clampScreenBrightness(
-                (int)Math.round(value * PowerManager.BRIGHTNESS_ON));
+                Math.round(value * PowerManager.BRIGHTNESS_ON));
         if (mScreenAutoBrightness != newScreenAutoBrightness) {
             if (DEBUG) {
                 Slog.d(TAG, "updateAutoBrightness: mScreenAutoBrightness="
@@ -1152,19 +1132,18 @@
         pw.println("  mLightSensorEnabled=" + mLightSensorEnabled);
         pw.println("  mLightSensorEnableTime="
                 + TimeUtils.formatUptime(mLightSensorEnableTime));
-        pw.println("  mLightMeasurement=" + mLightMeasurement);
-        pw.println("  mLightMeasurementValid=" + mLightMeasurementValid);
-        pw.println("  mLastLightSample=" + mLastLightSample);
-        pw.println("  mLastLightSampleTime="
-                + TimeUtils.formatUptime(mLastLightSampleTime));
+        pw.println("  mAmbientLux=" + mAmbientLux);
+        pw.println("  mAmbientLuxValid=" + mAmbientLuxValid);
+        pw.println("  mLastAmbientBrightenTime="
+                + TimeUtils.formatUptime(mLastAmbientBrightenTime));
+        pw.println("  mLastAmbientDimTime="
+                + TimeUtils.formatUptime(mLastAmbientDarkenTime));
+        pw.println("  mLastObservedLux=" + mLastObservedLux);
+        pw.println("  mLastObservedLuxTime="
+                + TimeUtils.formatUptime(mLastObservedLuxTime));
         pw.println("  mRecentLightSamples=" + mRecentLightSamples);
-        pw.println("  mRecentLightAverage=" + mRecentLightAverage);
-        pw.println("  mRecentLightBrightening=" + mRecentLightBrightening);
-        pw.println("  mRecentLightTimeConstant=" + mRecentLightTimeConstant);
-        pw.println("  mFirstRecentLightSampleTime="
-                + TimeUtils.formatUptime(mFirstRecentLightSampleTime));
-        pw.println("  mPendingLightSensorDebounceTime="
-                + TimeUtils.formatUptime(mPendingLightSensorDebounceTime));
+        pw.println("  mRecentShortTermAverageLux=" + mRecentShortTermAverageLux);
+        pw.println("  mRecentLongTermAverageLux=" + mRecentLongTermAverageLux);
         pw.println("  mScreenAutoBrightness=" + mScreenAutoBrightness);
         pw.println("  mUsingScreenAutoBrightness=" + mUsingScreenAutoBrightness);
         pw.println("  mLastScreenAutoBrightnessGamma=" + mLastScreenAutoBrightnessGamma);
diff --git a/services/java/com/android/server/power/PhotonicModulator.java b/services/java/com/android/server/power/PhotonicModulator.java
index c9b5d90..648c0c5 100644
--- a/services/java/com/android/server/power/PhotonicModulator.java
+++ b/services/java/com/android/server/power/PhotonicModulator.java
@@ -16,6 +16,8 @@
 
 package com.android.server.power;
 
+import android.util.Slog;
+
 import com.android.server.LightsService;
 
 import java.util.concurrent.Executor;
@@ -27,6 +29,9 @@
  * setting the backlight brightness is especially slow.
  */
 final class PhotonicModulator {
+    private static final String TAG = "PhotonicModulator";
+    private static final boolean DEBUG = false;
+
     private static final int UNKNOWN_LIGHT_VALUE = -1;
 
     private final Object mLock = new Object();
@@ -58,6 +63,9 @@
         synchronized (mLock) {
             if (lightValue != mPendingLightValue) {
                 mPendingLightValue = lightValue;
+                if (DEBUG) {
+                    Slog.d(TAG, "Enqueuing request to change brightness to " + lightValue);
+                }
                 if (!mPendingChange) {
                     mPendingChange = true;
                     mSuspendBlocker.acquire();
@@ -91,6 +99,9 @@
                     }
                     mActualLightValue = newLightValue;
                 }
+                if (DEBUG) {
+                    Slog.d(TAG, "Setting brightness to " + newLightValue);
+                }
                 mLight.setBrightness(newLightValue);
             }
         }
diff --git a/services/java/com/android/server/power/PowerManagerService.java b/services/java/com/android/server/power/PowerManagerService.java
index 4e692a2..bf81a90 100644
--- a/services/java/com/android/server/power/PowerManagerService.java
+++ b/services/java/com/android/server/power/PowerManagerService.java
@@ -107,6 +107,8 @@
     private static final int DIRTY_PROXIMITY_POSITIVE = 1 << 9;
     // Dirty bit: screen on blocker state became held or unheld
     private static final int DIRTY_SCREEN_ON_BLOCKER_RELEASED = 1 << 10;
+    // Dirty bit: dock state changed
+    private static final int DIRTY_DOCK_STATE = 1 << 11;
 
     // Wakefulness: The device is asleep and can only be awoken by a call to wakeUp().
     // The screen should be off or in the process of being turned off by the display controller.
@@ -269,18 +271,33 @@
     // draining faster than it is charging and the user activity timeout has expired.
     private int mBatteryLevelWhenDreamStarted;
 
+    // The current dock state.
+    private int mDockState = Intent.EXTRA_DOCK_STATE_UNDOCKED;
+
     // True if the device should wake up when plugged or unplugged.
     private boolean mWakeUpWhenPluggedOrUnpluggedConfig;
 
     // True if dreams are supported on this device.
     private boolean mDreamsSupportedConfig;
 
+    // Default value for dreams enabled
+    private boolean mDreamsEnabledByDefaultConfig;
+
+    // Default value for dreams activate-on-sleep
+    private boolean mDreamsActivatedOnSleepByDefaultConfig;
+
+    // Default value for dreams activate-on-dock
+    private boolean mDreamsActivatedOnDockByDefaultConfig;
+
     // True if dreams are enabled by the user.
     private boolean mDreamsEnabledSetting;
 
     // True if dreams should be activated on sleep.
     private boolean mDreamsActivateOnSleepSetting;
 
+    // True if dreams should be activated on dock.
+    private boolean mDreamsActivateOnDockSetting;
+
     // The screen off timeout setting value in milliseconds.
     private int mScreenOffTimeoutSetting;
 
@@ -440,6 +457,10 @@
             filter.addAction(Intent.ACTION_USER_SWITCHED);
             mContext.registerReceiver(new UserSwitchedReceiver(), filter, null, mHandler);
 
+            filter = new IntentFilter();
+            filter.addAction(Intent.ACTION_DOCK_EVENT);
+            mContext.registerReceiver(new DockReceiver(), filter, null, mHandler);
+
             // Register for settings changes.
             final ContentResolver resolver = mContext.getContentResolver();
             resolver.registerContentObserver(Settings.Secure.getUriFor(
@@ -448,6 +469,9 @@
             resolver.registerContentObserver(Settings.Secure.getUriFor(
                     Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP),
                     false, mSettingsObserver, UserHandle.USER_ALL);
+            resolver.registerContentObserver(Settings.Secure.getUriFor(
+                    Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK),
+                    false, mSettingsObserver, UserHandle.USER_ALL);
             resolver.registerContentObserver(Settings.System.getUriFor(
                     Settings.System.SCREEN_OFF_TIMEOUT),
                     false, mSettingsObserver, UserHandle.USER_ALL);
@@ -475,17 +499,29 @@
         mWakeUpWhenPluggedOrUnpluggedConfig = resources.getBoolean(
                 com.android.internal.R.bool.config_unplugTurnsOnScreen);
         mDreamsSupportedConfig = resources.getBoolean(
-                com.android.internal.R.bool.config_enableDreams);
+                com.android.internal.R.bool.config_dreamsSupported);
+        mDreamsEnabledByDefaultConfig = resources.getBoolean(
+                com.android.internal.R.bool.config_dreamsEnabledByDefault);
+        mDreamsActivatedOnSleepByDefaultConfig = resources.getBoolean(
+                com.android.internal.R.bool.config_dreamsActivatedOnSleepByDefault);
+        mDreamsActivatedOnDockByDefaultConfig = resources.getBoolean(
+                com.android.internal.R.bool.config_dreamsActivatedOnDockByDefault);
     }
 
     private void updateSettingsLocked() {
         final ContentResolver resolver = mContext.getContentResolver();
 
         mDreamsEnabledSetting = (Settings.Secure.getIntForUser(resolver,
-                Settings.Secure.SCREENSAVER_ENABLED, 0,
+                Settings.Secure.SCREENSAVER_ENABLED,
+                mDreamsEnabledByDefaultConfig ? 1 : 0,
                 UserHandle.USER_CURRENT) != 0);
         mDreamsActivateOnSleepSetting = (Settings.Secure.getIntForUser(resolver,
-                Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP, 0,
+                Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP,
+                mDreamsActivatedOnSleepByDefaultConfig ? 1 : 0,
+                UserHandle.USER_CURRENT) != 0);
+        mDreamsActivateOnDockSetting = (Settings.Secure.getIntForUser(resolver,
+                Settings.Secure.SCREENSAVER_ACTIVATE_ON_DOCK,
+                mDreamsActivatedOnDockByDefaultConfig ? 1 : 0,
                 UserHandle.USER_CURRENT) != 0);
         mScreenOffTimeoutSetting = Settings.System.getIntForUser(resolver,
                 Settings.System.SCREEN_OFF_TIMEOUT, DEFAULT_SCREEN_OFF_TIMEOUT,
@@ -1339,13 +1375,14 @@
     private boolean updateWakefulnessLocked(int dirty) {
         boolean changed = false;
         if ((dirty & (DIRTY_WAKE_LOCKS | DIRTY_USER_ACTIVITY | DIRTY_BOOT_COMPLETED
-                | DIRTY_WAKEFULNESS | DIRTY_STAY_ON | DIRTY_PROXIMITY_POSITIVE)) != 0) {
+                | DIRTY_WAKEFULNESS | DIRTY_STAY_ON | DIRTY_PROXIMITY_POSITIVE
+                | DIRTY_DOCK_STATE)) != 0) {
             if (mWakefulness == WAKEFULNESS_AWAKE && isItBedTimeYetLocked()) {
                 if (DEBUG_SPEW) {
                     Slog.d(TAG, "updateWakefulnessLocked: Bed time...");
                 }
                 final long time = SystemClock.uptimeMillis();
-                if (mDreamsActivateOnSleepSetting) {
+                if (shouldNapAtBedTimeLocked()) {
                     changed = napNoUpdateLocked(time);
                 } else {
                     changed = goToSleepNoUpdateLocked(time,
@@ -1357,6 +1394,16 @@
     }
 
     /**
+     * Returns true if the device should automatically nap and start dreaming when the user
+     * activity timeout has expired and it's bedtime.
+     */
+    private boolean shouldNapAtBedTimeLocked() {
+        return mDreamsActivateOnSleepSetting
+                || (mDreamsActivateOnDockSetting
+                        && mDockState != Intent.EXTRA_DOCK_STATE_UNDOCKED);
+    }
+
+    /**
      * Returns true if the device should go to sleep now.
      * Also used when exiting a dream to determine whether we should go back
      * to being fully awake or else go to sleep for good.
@@ -2124,6 +2171,7 @@
             pw.println("  mPlugType=" + mPlugType);
             pw.println("  mBatteryLevel=" + mBatteryLevel);
             pw.println("  mBatteryLevelWhenDreamStarted=" + mBatteryLevelWhenDreamStarted);
+            pw.println("  mDockState=" + mDockState);
             pw.println("  mStayOn=" + mStayOn);
             pw.println("  mProximityPositive=" + mProximityPositive);
             pw.println("  mBootCompleted=" + mBootCompleted);
@@ -2149,6 +2197,7 @@
             pw.println("  mDreamsSupportedConfig=" + mDreamsSupportedConfig);
             pw.println("  mDreamsEnabledSetting=" + mDreamsEnabledSetting);
             pw.println("  mDreamsActivateOnSleepSetting=" + mDreamsActivateOnSleepSetting);
+            pw.println("  mDreamsActivateOnDockSetting=" + mDreamsActivateOnDockSetting);
             pw.println("  mScreenOffTimeoutSetting=" + mScreenOffTimeoutSetting);
             pw.println("  mMaximumScreenOffTimeoutFromDeviceAdmin="
                     + mMaximumScreenOffTimeoutFromDeviceAdmin + " (enforced="
@@ -2267,6 +2316,21 @@
         }
     }
 
+    private final class DockReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            synchronized (mLock) {
+                int dockState = intent.getIntExtra(Intent.EXTRA_DOCK_STATE,
+                        Intent.EXTRA_DOCK_STATE_UNDOCKED);
+                if (mDockState != dockState) {
+                    mDockState = dockState;
+                    mDirty |= DIRTY_DOCK_STATE;
+                    updatePowerStateLocked();
+                }
+            }
+        }
+    }
+
     private final class SettingsObserver extends ContentObserver {
         public SettingsObserver(Handler handler) {
             super(handler);
diff --git a/services/java/com/android/server/wm/DisplayContent.java b/services/java/com/android/server/wm/DisplayContent.java
index 3898ebc..68cdbfc 100644
--- a/services/java/com/android/server/wm/DisplayContent.java
+++ b/services/java/com/android/server/wm/DisplayContent.java
@@ -66,14 +66,17 @@
     int mBaseDisplayWidth = 0;
     int mBaseDisplayHeight = 0;
     int mBaseDisplayDensity = 0;
-    final DisplayInfo mDisplayInfo = new DisplayInfo();
-    final Display mDisplay;
+    private final DisplayInfo mDisplayInfo = new DisplayInfo();
+    private final Display mDisplay;
 
     // Accessed directly by all users.
     boolean layoutNeeded;
     int pendingLayoutChanges;
     final boolean isDefaultDisplay;
 
+    /**
+     * @param display May not be null.
+     */
     DisplayContent(Display display) {
         mDisplay = display;
         mDisplayId = display.getDisplayId();
diff --git a/services/java/com/android/server/wm/DragState.java b/services/java/com/android/server/wm/DragState.java
index 545fce5..72fc180 100644
--- a/services/java/com/android/server/wm/DragState.java
+++ b/services/java/com/android/server/wm/DragState.java
@@ -190,9 +190,11 @@
         }
 
         final WindowList windows = mService.getWindowListLocked(mDisplay);
-        final int N = windows.size();
-        for (int i = 0; i < N; i++) {
-            sendDragStartedLw(windows.get(i), touchX, touchY, mDataDescription);
+        if (windows != null) {
+            final int N = windows.size();
+            for (int i = 0; i < N; i++) {
+                sendDragStartedLw(windows.get(i), touchX, touchY, mDataDescription);
+            }
         }
     }
 
@@ -393,6 +395,9 @@
         final int y = (int) yf;
 
         final WindowList windows = mService.getWindowListLocked(mDisplay);
+        if (windows == null) {
+            return null;
+        }
         final int N = windows.size();
         for (int i = N - 1; i >= 0; i--) {
             WindowState child = windows.get(i);
diff --git a/services/java/com/android/server/wm/WindowManagerService.java b/services/java/com/android/server/wm/WindowManagerService.java
index c341872..52992a1 100755
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -265,7 +265,7 @@
     static final int DEFAULT_FADE_IN_OUT_DURATION = 400;
 
     /** Amount of time (in milliseconds) to delay before declaring a window freeze timeout. */
-    static final int WINDOW_FREEZE_TIMEOUT_DURATION = 3000;
+    static final int WINDOW_FREEZE_TIMEOUT_DURATION = 2000;
 
     /**
      * If true, the window manager will do its own custom freezing and general
@@ -2092,6 +2092,11 @@
                 throw new IllegalStateException("Display has not been initialialized");
             }
 
+            final DisplayContent displayContent = getDisplayContentLocked(displayId);
+            if (displayContent == null) {
+                return WindowManagerGlobal.ADD_INVALID_DISPLAY;
+            }
+
             if (mWindowMap.containsKey(client.asBinder())) {
                 Slog.w(TAG, "Window " + client + " is already added");
                 return WindowManagerGlobal.ADD_DUPLICATE_ADD;
@@ -2174,7 +2179,6 @@
                 }
             }
 
-            final DisplayContent displayContent = getDisplayContentLocked(displayId);
             win = new WindowState(this, session, client, token,
                     attachedWindow, seq, attrs, viewVisibility, displayContent);
             if (win.mDeathRecipient == null) {
@@ -2420,6 +2424,7 @@
         final WindowList windows = win.getWindowList();
         windows.remove(win);
         mPendingRemove.remove(win);
+        mResizingWindows.remove(win);
         mWindowsChanged = true;
         if (DEBUG_WINDOW_MOVEMENT) Slog.v(TAG, "Final remove of window: " + win);
 
@@ -3384,8 +3389,15 @@
         } else {
             // Exiting app
             if (scaleUp) {
-                // noop animation
-                a = new AlphaAnimation(1, 0);
+                if (transit == WindowManagerPolicy.TRANSIT_WALLPAPER_INTRA_OPEN) {
+                    // Fade out while bringing up selected activity. This keeps the
+                    // current activity from showing through a launching wallpaper
+                    // activity.
+                    a = new AlphaAnimation(1, 0);
+                } else {
+                    // noop animation
+                    a = new AlphaAnimation(1, 1);
+                }
                 a.setDuration(duration);
             } else {
                 float scaleW = thumbWidth / displayInfo.appWidth;
@@ -5704,6 +5716,7 @@
      * @param width the width of the target bitmap
      * @param height the height of the target bitmap
      */
+    @Override
     public Bitmap screenshotApplications(IBinder appToken, int displayId, int width, int height) {
         if (!checkCallingPermission(android.Manifest.permission.READ_FRAME_BUFFER,
                 "screenshotApplications()")) {
@@ -5723,6 +5736,9 @@
             long ident = Binder.clearCallingIdentity();
 
             final DisplayContent displayContent = getDisplayContentLocked(displayId);
+            if (displayContent == null) {
+                return null;
+            }
             final DisplayInfo displayInfo = displayContent.getDisplayInfo();
             dw = displayInfo.logicalWidth;
             dh = displayInfo.logicalHeight;
@@ -6465,6 +6481,7 @@
         return success;
     }
 
+    @Override
     public void addDisplayContentChangeListener(int displayId,
             IDisplayContentChangeListener listener) {
         if (!checkCallingPermission(android.Manifest.permission.RETRIEVE_WINDOW_INFO,
@@ -6473,14 +6490,17 @@
         }
         synchronized(mWindowMap) {
             DisplayContent displayContent = getDisplayContentLocked(displayId);
-            if (displayContent.mDisplayContentChangeListeners == null) {
-                displayContent.mDisplayContentChangeListeners =
-                        new RemoteCallbackList<IDisplayContentChangeListener>();
-            displayContent.mDisplayContentChangeListeners.register(listener);
+            if (displayContent != null) {
+                if (displayContent.mDisplayContentChangeListeners == null) {
+                    displayContent.mDisplayContentChangeListeners =
+                            new RemoteCallbackList<IDisplayContentChangeListener>();
+                    displayContent.mDisplayContentChangeListeners.register(listener);
+                }
             }
         }
     }
 
+    @Override
     public void removeDisplayContentChangeListener(int displayId,
             IDisplayContentChangeListener listener) {
         if (!checkCallingPermission(android.Manifest.permission.RETRIEVE_WINDOW_INFO,
@@ -6489,11 +6509,13 @@
         }
         synchronized(mWindowMap) {
             DisplayContent displayContent = getDisplayContentLocked(displayId);
-            if (displayContent.mDisplayContentChangeListeners != null) {
-                displayContent.mDisplayContentChangeListeners.unregister(listener);
-                if (displayContent.mDisplayContentChangeListeners
-                        .getRegisteredCallbackCount() == 0) {
-                    displayContent.mDisplayContentChangeListeners = null;
+            if (displayContent != null) {
+                if (displayContent.mDisplayContentChangeListeners != null) {
+                    displayContent.mDisplayContentChangeListeners.unregister(listener);
+                    if (displayContent.mDisplayContentChangeListeners
+                            .getRegisteredCallbackCount() == 0) {
+                        displayContent.mDisplayContentChangeListeners = null;
+                    }
                 }
             }
         }
@@ -6569,6 +6591,36 @@
         }
     }
 
+    private void scheduleNotifyWindowLayersChangedIfNeededLocked(DisplayContent displayContent) {
+        if (displayContent.mDisplayContentChangeListeners != null
+                && displayContent.mDisplayContentChangeListeners.getRegisteredCallbackCount() > 0) {
+            mH.obtainMessage(H.NOTIFY_WINDOW_LAYERS_CHANGED, displayContent) .sendToTarget();
+        }
+    }
+
+    private void handleNotifyWindowLayersChanged(DisplayContent displayContent) {
+        RemoteCallbackList<IDisplayContentChangeListener> callbacks = null;
+        synchronized (mWindowMap) {
+            callbacks = displayContent.mDisplayContentChangeListeners;
+            if (callbacks == null) {
+                return;
+            }
+        }
+        try {
+            final int watcherCount = callbacks.beginBroadcast();
+            for (int i = 0; i < watcherCount; i++) {
+                try {
+                    callbacks.getBroadcastItem(i).onWindowLayersChanged(
+                            displayContent.getDisplayId());
+                } catch (RemoteException re) {
+                    /* ignore */
+                }
+            }
+        } finally {
+            callbacks.finishBroadcast();
+        }
+    }
+
     public void addWindowChangeListener(WindowChangeListener listener) {
         synchronized(mWindowMap) {
             mWindowChangeListeners.add(listener);
@@ -7119,7 +7171,6 @@
 
         synchronized(mWindowMap) {
             final DisplayContent displayContent = getDefaultDisplayContentLocked();
-            final Display display = displayContent.getDisplay();
             readForcedDisplaySizeAndDensityLocked(displayContent);
 
             mDisplayReady = true;
@@ -7143,24 +7194,25 @@
         }
     }
 
-    public void displayReady(int displayId) {
+    private void displayReady(int displayId) {
         synchronized(mWindowMap) {
             final DisplayContent displayContent = getDisplayContentLocked(displayId);
-            final DisplayInfo displayInfo;
-            mAnimator.addDisplayLocked(displayId);
-            synchronized(displayContent.mDisplaySizeLock) {
-                // Bootstrap the default logical display from the display manager.
-                displayInfo = displayContent.getDisplayInfo();
-                DisplayInfo newDisplayInfo = mDisplayManagerService.getDisplayInfo(displayId);
-                if (newDisplayInfo != null) {
-                    displayInfo.copyFrom(newDisplayInfo);
+            if (displayContent != null) {
+                mAnimator.addDisplayLocked(displayId);
+                synchronized(displayContent.mDisplaySizeLock) {
+                    // Bootstrap the default logical display from the display manager.
+                    final DisplayInfo displayInfo = displayContent.getDisplayInfo();
+                    DisplayInfo newDisplayInfo = mDisplayManagerService.getDisplayInfo(displayId);
+                    if (newDisplayInfo != null) {
+                        displayInfo.copyFrom(newDisplayInfo);
+                    }
+                    displayContent.mInitialDisplayWidth = displayInfo.logicalWidth;
+                    displayContent.mInitialDisplayHeight = displayInfo.logicalHeight;
+                    displayContent.mInitialDisplayDensity = displayInfo.logicalDensityDpi;
+                    displayContent.mBaseDisplayWidth = displayContent.mInitialDisplayWidth;
+                    displayContent.mBaseDisplayHeight = displayContent.mInitialDisplayHeight;
+                    displayContent.mBaseDisplayDensity = displayContent.mInitialDisplayDensity;
                 }
-                displayContent.mInitialDisplayWidth = displayInfo.logicalWidth;
-                displayContent.mInitialDisplayHeight = displayInfo.logicalHeight;
-                displayContent.mInitialDisplayDensity = displayInfo.logicalDensityDpi;
-                displayContent.mBaseDisplayWidth = displayContent.mInitialDisplayWidth;
-                displayContent.mBaseDisplayHeight = displayContent.mInitialDisplayHeight;
-                displayContent.mBaseDisplayDensity = displayContent.mInitialDisplayDensity;
             }
         }
     }
@@ -7215,12 +7267,13 @@
         public static final int NOTIFY_ROTATION_CHANGED = 28;
         public static final int NOTIFY_WINDOW_TRANSITION = 29;
         public static final int NOTIFY_RECTANGLE_ON_SCREEN_REQUESTED = 30;
+        public static final int NOTIFY_WINDOW_LAYERS_CHANGED = 31;
 
-        public static final int DO_DISPLAY_ADDED = 31;
-        public static final int DO_DISPLAY_REMOVED = 32;
-        public static final int DO_DISPLAY_CHANGED = 33;
+        public static final int DO_DISPLAY_ADDED = 32;
+        public static final int DO_DISPLAY_REMOVED = 33;
+        public static final int DO_DISPLAY_CHANGED = 34;
 
-        public static final int CLIENT_FREEZE_TIMEOUT = 34;
+        public static final int CLIENT_FREEZE_TIMEOUT = 35;
 
         public static final int ANIMATOR_WHAT_OFFSET = 100000;
         public static final int SET_TRANSPARENT_REGION = ANIMATOR_WHAT_OFFSET + 1;
@@ -7692,6 +7745,12 @@
                     break;
                 }
 
+                case NOTIFY_WINDOW_LAYERS_CHANGED: {
+                    DisplayContent displayContent = (DisplayContent) msg.obj;
+                    handleNotifyWindowLayersChanged(displayContent);
+                    break;
+                }
+
                 case DO_DISPLAY_ADDED:
                     synchronized (mWindowMap) {
                         handleDisplayAddedLocked(msg.arg1);
@@ -7794,12 +7853,15 @@
         // TODO(cmautner): Access to DisplayContent should be locked on mWindowMap. Doing that
         //  could lead to deadlock since this is called from ActivityManager.
         final DisplayContent displayContent = getDisplayContentLocked(displayId);
-        synchronized(displayContent.mDisplaySizeLock) {
-            size.x = displayContent.mInitialDisplayWidth;
-            size.y = displayContent.mInitialDisplayHeight;
+        if (displayContent != null) {
+            synchronized(displayContent.mDisplaySizeLock) {
+                size.x = displayContent.mInitialDisplayWidth;
+                size.y = displayContent.mInitialDisplayHeight;
+            }
         }
     }
 
+    @Override
     public void setForcedDisplaySize(int displayId, int width, int height) {
         synchronized(mWindowMap) {
             // Set some sort of reasonable bounds on the size of the display that we
@@ -7808,14 +7870,15 @@
             final int MIN_HEIGHT = 200;
             final int MAX_SCALE = 2;
             final DisplayContent displayContent = getDisplayContentLocked(displayId);
-
-            width = Math.min(Math.max(width, MIN_WIDTH),
-                    displayContent.mInitialDisplayWidth * MAX_SCALE);
-            height = Math.min(Math.max(height, MIN_HEIGHT),
-                    displayContent.mInitialDisplayHeight * MAX_SCALE);
-            setForcedDisplaySizeLocked(displayContent, width, height);
-            Settings.Global.putString(mContext.getContentResolver(),
-                    Settings.Global.DISPLAY_SIZE_FORCED, width + "," + height);
+            if (displayContent != null) {
+                width = Math.min(Math.max(width, MIN_WIDTH),
+                        displayContent.mInitialDisplayWidth * MAX_SCALE);
+                height = Math.min(Math.max(height, MIN_HEIGHT),
+                        displayContent.mInitialDisplayHeight * MAX_SCALE);
+                setForcedDisplaySizeLocked(displayContent, width, height);
+                Settings.Global.putString(mContext.getContentResolver(),
+                        Settings.Global.DISPLAY_SIZE_FORCED, width + "," + height);
+            }
         }
     }
 
@@ -7858,6 +7921,7 @@
         }
     }
 
+    // displayContent must not be null
     private void setForcedDisplaySizeLocked(DisplayContent displayContent, int width, int height) {
         Slog.i(TAG, "Using new display size: " + width + "x" + height);
 
@@ -7868,25 +7932,32 @@
         reconfigureDisplayLocked(displayContent);
     }
 
+    @Override
     public void clearForcedDisplaySize(int displayId) {
         synchronized(mWindowMap) {
             final DisplayContent displayContent = getDisplayContentLocked(displayId);
-            setForcedDisplaySizeLocked(displayContent, displayContent.mInitialDisplayWidth,
-                    displayContent.mInitialDisplayHeight);
-            Settings.Global.putString(mContext.getContentResolver(),
-                    Settings.Global.DISPLAY_SIZE_FORCED, "");
+            if (displayContent != null) {
+                setForcedDisplaySizeLocked(displayContent, displayContent.mInitialDisplayWidth,
+                        displayContent.mInitialDisplayHeight);
+                Settings.Global.putString(mContext.getContentResolver(),
+                        Settings.Global.DISPLAY_SIZE_FORCED, "");
+            }
         }
     }
 
+    @Override
     public void setForcedDisplayDensity(int displayId, int density) {
         synchronized(mWindowMap) {
             final DisplayContent displayContent = getDisplayContentLocked(displayId);
-            setForcedDisplayDensityLocked(displayContent, density);
-            Settings.Global.putString(mContext.getContentResolver(),
-                    Settings.Global.DISPLAY_DENSITY_FORCED, Integer.toString(density));
+            if (displayContent != null) {
+                setForcedDisplayDensityLocked(displayContent, density);
+                Settings.Global.putString(mContext.getContentResolver(),
+                        Settings.Global.DISPLAY_DENSITY_FORCED, Integer.toString(density));
+            }
         }
     }
 
+    // displayContent must not be null
     private void setForcedDisplayDensityLocked(DisplayContent displayContent, int density) {
         Slog.i(TAG, "Using new display density: " + density);
 
@@ -7896,15 +7967,19 @@
         reconfigureDisplayLocked(displayContent);
     }
 
+    @Override
     public void clearForcedDisplayDensity(int displayId) {
         synchronized(mWindowMap) {
             final DisplayContent displayContent = getDisplayContentLocked(displayId);
-            setForcedDisplayDensityLocked(displayContent, displayContent.mInitialDisplayDensity);
-            Settings.Global.putString(mContext.getContentResolver(),
-                    Settings.Global.DISPLAY_DENSITY_FORCED, "");
+            if (displayContent != null) {
+                setForcedDisplayDensityLocked(displayContent, displayContent.mInitialDisplayDensity);
+                Settings.Global.putString(mContext.getContentResolver(),
+                        Settings.Global.DISPLAY_DENSITY_FORCED, "");
+            }
         }
     }
 
+    // displayContent must not be null
     private void reconfigureDisplayLocked(DisplayContent displayContent) {
         // TODO: Multidisplay: for now only use with default display.
         mPolicy.setInitialDisplaySize(displayContent.getDisplay(),
@@ -8068,6 +8143,8 @@
             Slog.v(TAG, "Assigning layers", here);
         }
 
+        boolean anyLayerChanged = false;
+
         for (i=0; i<N; i++) {
             final WindowState w = windows.get(i);
             final WindowStateAnimator winAnimator = w.mWinAnimator;
@@ -8083,6 +8160,7 @@
             }
             if (w.mLayer != oldLayer) {
                 layerChanged = true;
+                anyLayerChanged = true;
             }
             oldLayer = winAnimator.mAnimLayer;
             if (w.mTargetAppToken != null) {
@@ -8101,6 +8179,7 @@
             }
             if (winAnimator.mAnimLayer != oldLayer) {
                 layerChanged = true;
+                anyLayerChanged = true;
             }
             if (layerChanged && mAnimator.isDimmingLocked(winAnimator)) {
                 // Force an animation pass just to update the mDimAnimator layer.
@@ -8115,10 +8194,22 @@
             //System.out.println(
             //    "Assigned layer " + curLayer + " to " + w.mClient.asBinder());
         }
+
+        if (anyLayerChanged) {
+            scheduleNotifyWindowLayersChangedIfNeededLocked(getDefaultDisplayContentLocked());
+        }
+    }
+
+    private final void performLayoutAndPlaceSurfacesLocked() {
+        do {
+            mTraversalScheduled = false;
+            performLayoutAndPlaceSurfacesLockedLoop();
+            mH.removeMessages(H.DO_TRAVERSAL);
+        } while (mTraversalScheduled);
     }
 
     private boolean mInLayout = false;
-    private final void performLayoutAndPlaceSurfacesLocked() {
+    private final void performLayoutAndPlaceSurfacesLockedLoop() {
         if (mInLayout) {
             if (DEBUG) {
                 throw new RuntimeException("Recursive call!");
@@ -9658,7 +9749,9 @@
             for (int i = 0; i < count; ++i) {
                 final DisplayContent displayContent =
                         getDisplayContentLocked(pendingLayouts.keyAt(i));
-                displayContent.pendingLayoutChanges |= pendingLayouts.valueAt(i);
+                if (displayContent != null) {
+                    displayContent.pendingLayoutChanges |= pendingLayouts.valueAt(i);
+                }
             }
 
             mWindowDetachedWallpaper = animToLayout.mWindowDetachedWallpaper;
@@ -10784,11 +10877,20 @@
         mDisplayContents.put(display.getDisplayId(), displayContent);
     }
 
+    /**
+     * Retrieve the DisplayContent for the specified displayId. Will create a new DisplayContent if
+     * there is a Display for the displayId.
+     * @param displayId The display the caller is interested in.
+     * @return The DisplayContent associated with displayId or null if there is no Display for it.
+     */
     public DisplayContent getDisplayContentLocked(final int displayId) {
         DisplayContent displayContent = mDisplayContents.get(displayId);
         if (displayContent == null) {
-            displayContent = new DisplayContent(mDisplayManager.getDisplay(displayId));
-            mDisplayContents.put(displayId, displayContent);
+            final Display display = mDisplayManager.getDisplay(displayId);
+            if (display != null) {
+                displayContent = new DisplayContent(display);
+                mDisplayContents.put(displayId, displayContent);
+            }
         }
         return displayContent;
     }
@@ -10874,6 +10976,7 @@
         }
     }
 
+    // There is an inherent assumption that this will never return null.
     public DisplayContent getDefaultDisplayContentLocked() {
         return getDisplayContentLocked(Display.DEFAULT_DISPLAY);
     }
@@ -10886,8 +10989,14 @@
         return getDefaultDisplayContentLocked().getDisplayInfo();
     }
 
+    /**
+     * Return the list of WindowStates associated on the passed display.
+     * @param display The screen to return windows from.
+     * @return The list of WindowStates on the screen, or null if the there is no screen.
+     */
     public WindowList getWindowListLocked(final Display display) {
-        return getDisplayContentLocked(display.getDisplayId()).getWindowList();
+        final DisplayContent displayContent = getDisplayContentLocked(display.getDisplayId());
+        return displayContent != null ? displayContent.getWindowList() : null;
     }
 
     @Override
@@ -10896,8 +11005,11 @@
     }
 
     private void handleDisplayAddedLocked(int displayId) {
-        createDisplayContentLocked(mDisplayManager.getDisplay(displayId));
-        displayReady(displayId);
+        final Display display = mDisplayManager.getDisplay(displayId);
+        if (display != null) {
+            createDisplayContentLocked(display);
+            displayReady(displayId);
+        }
     }
 
     @Override
@@ -10907,11 +11019,13 @@
 
     private void handleDisplayRemovedLocked(int displayId) {
         final DisplayContent displayContent = getDisplayContentLocked(displayId);
-        mDisplayContents.delete(displayId);
-        WindowList windows = displayContent.getWindowList();
-        while (!windows.isEmpty()) {
-            final WindowState win = windows.get(windows.size() - 1);
-            removeWindowLocked(win.mSession, win);
+        if (displayContent != null) {
+            mDisplayContents.delete(displayId);
+            WindowList windows = displayContent.getWindowList();
+            while (!windows.isEmpty()) {
+                final WindowState win = windows.get(windows.size() - 1);
+                removeWindowLocked(win.mSession, win);
+            }
         }
         mAnimator.removeDisplayLocked(displayId);
     }
diff --git a/services/java/com/android/server/wm/WindowState.java b/services/java/com/android/server/wm/WindowState.java
index feb29b1..c195f45 100644
--- a/services/java/com/android/server/wm/WindowState.java
+++ b/services/java/com/android/server/wm/WindowState.java
@@ -1038,18 +1038,26 @@
     }
 
     boolean isHiddenFromUserLocked() {
-        // Save some cycles by not calling getDisplayInfo unless it is an application
-        // window intended for all users.
-        if (mAttrs.type < WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW
-                && mAppToken != null && mAppToken.showWhenLocked) {
-            final DisplayInfo displayInfo = mDisplayContent.getDisplayInfo();
-            if (isFullscreen(displayInfo.appWidth, displayInfo.appHeight)) {
+        // Attached windows are evaluated based on the window that they are attached to.
+        WindowState win = this;
+        while (win.mAttachedWindow != null) {
+            win = win.mAttachedWindow;
+        }
+        if (win.mAttrs.type < WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW
+                && win.mAppToken != null && win.mAppToken.showWhenLocked) {
+            // Save some cycles by not calling getDisplayInfo unless it is an application
+            // window intended for all users.
+            final DisplayInfo displayInfo = win.mDisplayContent.getDisplayInfo();
+            if (win.mFrame.left <= 0 && win.mFrame.top <= 0
+                    && win.mFrame.right >= displayInfo.appWidth
+                    && win.mFrame.bottom >= displayInfo.appHeight) {
                 // Is a fullscreen window, like the clock alarm. Show to everyone.
                 return false;
             }
         }
 
-        return mShowToOwnerOnly && UserHandle.getUserId(mOwnerUid) != mService.mCurrentUserId;
+        return win.mShowToOwnerOnly
+                && UserHandle.getUserId(win.mOwnerUid) != mService.mCurrentUserId;
     }
 
     private static void applyInsets(Region outRegion, Rect frame, Rect inset) {
diff --git a/tests/HwAccelerationTest/AndroidManifest.xml b/tests/HwAccelerationTest/AndroidManifest.xml
index 4cb409d..9118aea 100644
--- a/tests/HwAccelerationTest/AndroidManifest.xml
+++ b/tests/HwAccelerationTest/AndroidManifest.xml
@@ -33,6 +33,15 @@
         <meta-data android:name="android.graphics.renderThread" android:value="true" />
 
         <activity
+                android:name="MipMapActivity"
+                android:label="_MipMap">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+
+        <activity
                 android:name="PathOffsetActivity"
                 android:label="_PathOffset">
             <intent-filter>
diff --git a/tests/HwAccelerationTest/res/drawable-nodpi/very_large_photo.jpg b/tests/HwAccelerationTest/res/drawable-nodpi/very_large_photo.jpg
new file mode 100644
index 0000000..7f047b1
--- /dev/null
+++ b/tests/HwAccelerationTest/res/drawable-nodpi/very_large_photo.jpg
Binary files differ
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/BitmapMeshActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/BitmapMeshActivity.java
index 8cc2246..854dd69 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/BitmapMeshActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/BitmapMeshActivity.java
@@ -68,9 +68,16 @@
             super.onDraw(canvas);
 
             canvas.drawARGB(255, 255, 255, 255);
+
             canvas.translate(100, 100);
             canvas.drawBitmapMesh(mBitmap1, 3, 3, mVertices, 0, null, 0, null);
 
+            canvas.save();
+            canvas.translate(0, 400);
+            canvas.clipRect(0.0f, 0.0f, 80.0f, 80.0f);
+            canvas.drawBitmapMesh(mBitmap1, 3, 3, mVertices, 0, null, 0, null);
+            canvas.restore();
+
             canvas.translate(400, 0);
             canvas.drawBitmapMesh(mBitmap1, 3, 3, mVertices, 0, mColors, 0, null);
         }
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/MipMapActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/MipMapActivity.java
new file mode 100644
index 0000000..1034649
--- /dev/null
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/MipMapActivity.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.hwui;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
+import android.os.Bundle;
+import android.util.Log;
+import android.view.Gravity;
+import android.view.View;
+import android.view.animation.Animation;
+import android.view.animation.ScaleAnimation;
+import android.widget.FrameLayout;
+
+@SuppressWarnings({"UnusedDeclaration"})
+public class MipMapActivity extends Activity {
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        final BitmapsView view = new BitmapsView(this);
+        setContentView(view);
+    }
+
+    static class BitmapsView extends View {
+        private Paint mBitmapPaint;
+        private final Bitmap mBitmap1;
+        private final Bitmap mBitmap2;
+
+        BitmapsView(Context c) {
+            super(c);
+
+            mBitmap1 = BitmapFactory.decodeResource(c.getResources(), R.drawable.very_large_photo);
+            mBitmap2 = BitmapFactory.decodeResource(c.getResources(), R.drawable.very_large_photo);
+
+            mBitmap1.setHasMipMap(true);
+
+            mBitmapPaint = new Paint();
+            mBitmapPaint.setFilterBitmap(true);
+        }
+
+        @Override
+        protected void onDraw(Canvas canvas) {
+            super.onDraw(canvas);
+
+            canvas.save();
+            canvas.scale(0.3f, 0.3f);
+            canvas.drawBitmap(mBitmap1, 0, 0, mBitmapPaint);
+            canvas.restore();
+
+            canvas.save();
+            canvas.translate(mBitmap1.getWidth() * 0.3f + 96.0f, 0.0f);
+            canvas.scale(0.3f, 0.3f);
+            canvas.drawBitmap(mBitmap2, 0, 0, mBitmapPaint);
+            canvas.restore();
+        }
+    }
+}
diff --git a/tools/aidl/aidl.cpp b/tools/aidl/aidl.cpp
index 0728246..071a8d7 100644
--- a/tools/aidl/aidl.cpp
+++ b/tools/aidl/aidl.cpp
@@ -23,6 +23,12 @@
 #  define O_BINARY  0
 #endif
 
+// The following are gotten as the offset from the allowable id's between
+// android.os.IBinder.FIRST_CALL_TRANSACTION=1 and
+// android.os.IBinder.LAST_CALL_TRANSACTION=16777215
+#define MIN_USER_SET_METHOD_ID                0
+#define MAX_USER_SET_METHOD_ID                16777214
+
 using namespace std;
 
 static void
@@ -847,6 +853,72 @@
     return 0;
 }
 
+static int
+check_and_assign_method_ids(const char * filename, interface_item_type* first_item)
+{
+    // Check whether there are any methods with manually assigned id's and any that are not.
+    // Either all method id's must be manually assigned or all of them must not.
+    // Also, check for duplicates of user set id's and that the id's are within the proper bounds.
+    set<int> usedIds;
+    interface_item_type* item = first_item;
+    bool hasUnassignedIds = false;
+    bool hasAssignedIds = false;
+    while (item != NULL) {
+        if (item->item_type == METHOD_TYPE) {
+            method_type* method_item = (method_type*)item;
+            if (method_item->hasId) {
+                hasAssignedIds = true;
+                method_item->assigned_id = atoi(method_item->id.data);
+                // Ensure that the user set id is not duplicated.
+                if (usedIds.find(method_item->assigned_id) != usedIds.end()) {
+                    // We found a duplicate id, so throw an error.
+                    fprintf(stderr,
+                            "%s:%d Found duplicate method id (%d) for method: %s\n",
+                            filename, method_item->id.lineno,
+                            method_item->assigned_id, method_item->name.data);
+                    return 1;
+                }
+                // Ensure that the user set id is within the appropriate limits
+                if (method_item->assigned_id < MIN_USER_SET_METHOD_ID ||
+                        method_item->assigned_id > MAX_USER_SET_METHOD_ID) {
+                    fprintf(stderr, "%s:%d Found out of bounds id (%d) for method: %s\n",
+                            filename, method_item->id.lineno,
+                            method_item->assigned_id, method_item->name.data);
+                    fprintf(stderr, "    Value for id must be between %d and %d inclusive.\n",
+                            MIN_USER_SET_METHOD_ID, MAX_USER_SET_METHOD_ID);
+                    return 1;
+                }
+                usedIds.insert(method_item->assigned_id);
+            } else {
+                hasUnassignedIds = true;
+            }
+            if (hasAssignedIds && hasUnassignedIds) {
+                fprintf(stderr,
+                        "%s: You must either assign id's to all methods or to none of them.\n",
+                        filename);
+                return 1;
+            }
+        }
+        item = item->next;
+    }
+
+    // In the case that all methods have unassigned id's, set a unique id for them.
+    if (hasUnassignedIds) {
+        int newId = 0;
+        item = first_item;
+        while (item != NULL) {
+            if (item->item_type == METHOD_TYPE) {
+                method_type* method_item = (method_type*)item;
+                method_item->assigned_id = newId++;
+            }
+            item = item->next;
+        }
+    }
+
+    // success
+    return 0;
+}
+
 // ==========================================================
 static int
 compile_aidl(Options& options)
@@ -937,6 +1009,12 @@
     bool onlyParcelable = false;
     err |= exactly_one_interface(options.inputFileName.c_str(), mainDoc, options, &onlyParcelable);
 
+    // If this includes an interface definition, then assign method ids and validate.
+    if (!onlyParcelable) {
+        err |= check_and_assign_method_ids(options.inputFileName.c_str(),
+                ((interface_type*)mainDoc)->interface_items);
+    }
+
     // after this, there shouldn't be any more errors because of the
     // input.
     if (err != 0 || mainDoc == NULL) {
diff --git a/tools/aidl/aidl_language.h b/tools/aidl/aidl_language.h
index f203dbb0..de1370c 100644
--- a/tools/aidl/aidl_language.h
+++ b/tools/aidl/aidl_language.h
@@ -57,9 +57,13 @@
     buffer_type open_paren_token;
     arg_type* args;
     buffer_type close_paren_token;
+    bool hasId;
+    buffer_type equals_token;
+    buffer_type id;
     // XXX missing comments/copy text here
     buffer_type semicolon_token;
     buffer_type* comments_token; // points into this structure, DO NOT DELETE
+    int assigned_id;
 } method_type;
 
 enum {
diff --git a/tools/aidl/aidl_language_l.l b/tools/aidl/aidl_language_l.l
index 7c5290c..3d33e7a 100644
--- a/tools/aidl/aidl_language_l.l
+++ b/tools/aidl/aidl_language_l.l
@@ -36,6 +36,7 @@
 identifier  [_a-zA-Z][_a-zA-Z0-9\.]*
 whitespace  ([ \t\n\r]+)
 brackets    \[{whitespace}?\]
+idvalue     (0|[1-9][0-9]*)
 
 %%
 
@@ -77,6 +78,7 @@
 \(              { SET_BUFFER('('); return '('; }
 \)              { SET_BUFFER(')'); return ')'; }
 ,               { SET_BUFFER(','); return ','; }
+=               { SET_BUFFER('='); return '='; }
 
     /* keywords */
 parcelable      { SET_BUFFER(PARCELABLE); return PARCELABLE; }
@@ -89,7 +91,7 @@
 oneway          { SET_BUFFER(ONEWAY); return ONEWAY; }
 
 {brackets}+     { SET_BUFFER(ARRAY); return ARRAY; }
-
+{idvalue}       { SET_BUFFER(IDVALUE); return IDVALUE; }
 {identifier}                                        { SET_BUFFER(IDENTIFIER); return IDENTIFIER; }
 {identifier}\<{whitespace}*{identifier}({whitespace}*,{whitespace}*{identifier})*{whitespace}*\>    {
                                                       SET_BUFFER(GENERIC); return GENERIC; }
diff --git a/tools/aidl/aidl_language_y.y b/tools/aidl/aidl_language_y.y
index cc04d15..9b40d28 100644
--- a/tools/aidl/aidl_language_y.y
+++ b/tools/aidl/aidl_language_y.y
@@ -15,6 +15,7 @@
 %token IMPORT
 %token PACKAGE
 %token IDENTIFIER
+%token IDVALUE
 %token GENERIC
 %token ARRAY
 %token PARCELABLE
@@ -211,13 +212,16 @@
                                                         method_type *method = (method_type*)malloc(sizeof(method_type));
                                                         method->interface_item.item_type = METHOD_TYPE;
                                                         method->interface_item.next = NULL;
-                                                        method->type = $1.type;
                                                         method->oneway = false;
+                                                        method->type = $1.type;
                                                         memset(&method->oneway_token, 0, sizeof(buffer_type));
                                                         method->name = $2.buffer;
                                                         method->open_paren_token = $3.buffer;
                                                         method->args = $4.arg;
                                                         method->close_paren_token = $5.buffer;
+                                                        method->hasId = false;
+                                                        memset(&method->equals_token, 0, sizeof(buffer_type));
+                                                        memset(&method->id, 0, sizeof(buffer_type));
                                                         method->semicolon_token = $6.buffer;
                                                         method->comments_token = &method->type.type;
                                                         $$.method = method;
@@ -233,10 +237,49 @@
                                                         method->open_paren_token = $4.buffer;
                                                         method->args = $5.arg;
                                                         method->close_paren_token = $6.buffer;
+                                                        method->hasId = false;
+                                                        memset(&method->equals_token, 0, sizeof(buffer_type));
+                                                        memset(&method->id, 0, sizeof(buffer_type));
                                                         method->semicolon_token = $7.buffer;
                                                         method->comments_token = &method->oneway_token;
                                                         $$.method = method;
                                                     }
+    |    type IDENTIFIER '(' arg_list ')' '=' IDVALUE ';'  {
+                                                        method_type *method = (method_type*)malloc(sizeof(method_type));
+                                                        method->interface_item.item_type = METHOD_TYPE;
+                                                        method->interface_item.next = NULL;
+                                                        method->oneway = false;
+                                                        memset(&method->oneway_token, 0, sizeof(buffer_type));
+                                                        method->type = $1.type;
+                                                        method->name = $2.buffer;
+                                                        method->open_paren_token = $3.buffer;
+                                                        method->args = $4.arg;
+                                                        method->close_paren_token = $5.buffer;
+                                                        method->hasId = true;
+                                                        method->equals_token = $6.buffer;
+                                                        method->id = $7.buffer;
+                                                        method->semicolon_token = $8.buffer;
+                                                        method->comments_token = &method->type.type;
+                                                        $$.method = method;
+                                                    }
+    |   ONEWAY type IDENTIFIER '(' arg_list ')' '=' IDVALUE ';'  {
+                                                        method_type *method = (method_type*)malloc(sizeof(method_type));
+                                                        method->interface_item.item_type = METHOD_TYPE;
+                                                        method->interface_item.next = NULL;
+                                                        method->oneway = true;
+                                                        method->oneway_token = $1.buffer;
+                                                        method->type = $2.type;
+                                                        method->name = $3.buffer;
+                                                        method->open_paren_token = $4.buffer;
+                                                        method->args = $5.arg;
+                                                        method->close_paren_token = $6.buffer;
+                                                        method->hasId = true;
+                                                        method->equals_token = $7.buffer;
+                                                        method->id = $8.buffer;
+                                                        method->semicolon_token = $9.buffer;
+                                                        method->comments_token = &method->oneway_token;
+                                                        $$.method = method;
+                                                    }
     ;
 
 arg_list:
diff --git a/tools/aidl/generate_java_binder.cpp b/tools/aidl/generate_java_binder.cpp
index f80a388..f291ceb 100644
--- a/tools/aidl/generate_java_binder.cpp
+++ b/tools/aidl/generate_java_binder.cpp
@@ -260,7 +260,7 @@
     string transactCodeName = "TRANSACTION_";
     transactCodeName += method->name.data;
 
-    char transactCodeValue[50];
+    char transactCodeValue[60];
     sprintf(transactCodeValue, "(android.os.IBinder.FIRST_CALL_TRANSACTION + %d)", index);
 
     Field* transactCode = new Field(STATIC | FINAL,
@@ -548,7 +548,8 @@
     interface_item_type* item = iface->interface_items;
     while (item != NULL) {
         if (item->item_type == METHOD_TYPE) {
-            generate_method((method_type*)item, interface, stub, proxy, index);
+            method_type * method_item = (method_type*) item;
+            generate_method(method_item, interface, stub, proxy, method_item->assigned_id);
         }
         item = item->next;
         index++;
diff --git a/tools/layoutlib/bridge/resources/bars/hdpi/ic_sysbar_back.png b/tools/layoutlib/bridge/resources/bars/hdpi/ic_sysbar_back.png
new file mode 100644
index 0000000..84e6bc8
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/hdpi/ic_sysbar_back.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/hdpi/ic_sysbar_back_default.png b/tools/layoutlib/bridge/resources/bars/hdpi/ic_sysbar_back_default.png
deleted file mode 100644
index ac5a97b..0000000
--- a/tools/layoutlib/bridge/resources/bars/hdpi/ic_sysbar_back_default.png
+++ /dev/null
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/hdpi/ic_sysbar_home.png b/tools/layoutlib/bridge/resources/bars/hdpi/ic_sysbar_home.png
new file mode 100644
index 0000000..38e4f45
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/hdpi/ic_sysbar_home.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/hdpi/ic_sysbar_home_default.png b/tools/layoutlib/bridge/resources/bars/hdpi/ic_sysbar_home_default.png
deleted file mode 100644
index a90dc9b..0000000
--- a/tools/layoutlib/bridge/resources/bars/hdpi/ic_sysbar_home_default.png
+++ /dev/null
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/hdpi/ic_sysbar_recent.png b/tools/layoutlib/bridge/resources/bars/hdpi/ic_sysbar_recent.png
new file mode 100644
index 0000000..bf9f300
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/hdpi/ic_sysbar_recent.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/hdpi/ic_sysbar_recent_default.png b/tools/layoutlib/bridge/resources/bars/hdpi/ic_sysbar_recent_default.png
deleted file mode 100644
index cb3c433..0000000
--- a/tools/layoutlib/bridge/resources/bars/hdpi/ic_sysbar_recent_default.png
+++ /dev/null
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_back.png b/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_back.png
new file mode 100644
index 0000000..a00bc5b
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_back.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_back_default.png b/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_back_default.png
deleted file mode 100644
index 5ab09f0..0000000
--- a/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_back_default.png
+++ /dev/null
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_home.png b/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_home.png
new file mode 100644
index 0000000..dc3183b
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_home.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_home_default.png b/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_home_default.png
deleted file mode 100644
index 62ca427..0000000
--- a/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_home_default.png
+++ /dev/null
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_recent.png b/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_recent.png
new file mode 100644
index 0000000..b07f611
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_recent.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_recent_default.png b/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_recent_default.png
deleted file mode 100644
index ff698fb..0000000
--- a/tools/layoutlib/bridge/resources/bars/mdpi/ic_sysbar_recent_default.png
+++ /dev/null
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/tablet_system_bar.xml b/tools/layoutlib/bridge/resources/bars/navigation_bar.xml
similarity index 76%
rename from tools/layoutlib/bridge/resources/bars/tablet_system_bar.xml
rename to tools/layoutlib/bridge/resources/bars/navigation_bar.xml
index c5acddb..599ca08 100644
--- a/tools/layoutlib/bridge/resources/bars/tablet_system_bar.xml
+++ b/tools/layoutlib/bridge/resources/bars/navigation_bar.xml
@@ -1,5 +1,9 @@
 <?xml version="1.0" encoding="utf-8"?>
 <merge xmlns:android="http://schemas.android.com/apk/res/android">
+	<TextView
+			android:layout_width="wrap_content"
+			android:layout_height="wrap_content"
+			android:layout_weight="1"/>
 	<ImageView
 			android:layout_height="wrap_content"
 			android:layout_width="wrap_content"/>
@@ -13,12 +17,4 @@
 			android:layout_width="wrap_content"
 			android:layout_height="wrap_content"
 			android:layout_weight="1"/>
-	<ImageView
-			android:layout_height="wrap_content"
-			android:layout_width="wrap_content"/>
-	<ImageView
-			android:layout_height="wrap_content"
-			android:layout_width="wrap_content"
-			android:layout_marginLeft="3dip"
-			android:layout_marginRight="15dip"/>
 </merge>
diff --git a/tools/layoutlib/bridge/resources/bars/phone_system_bar.xml b/tools/layoutlib/bridge/resources/bars/status_bar.xml
similarity index 100%
rename from tools/layoutlib/bridge/resources/bars/phone_system_bar.xml
rename to tools/layoutlib/bridge/resources/bars/status_bar.xml
diff --git a/tools/layoutlib/bridge/resources/bars/xhdpi/ic_sysbar_back.png b/tools/layoutlib/bridge/resources/bars/xhdpi/ic_sysbar_back.png
new file mode 100644
index 0000000..bd60cd6
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/xhdpi/ic_sysbar_back.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/xhdpi/ic_sysbar_back_default.png b/tools/layoutlib/bridge/resources/bars/xhdpi/ic_sysbar_back_default.png
deleted file mode 100644
index 4cb305d..0000000
--- a/tools/layoutlib/bridge/resources/bars/xhdpi/ic_sysbar_back_default.png
+++ /dev/null
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/xhdpi/ic_sysbar_home.png b/tools/layoutlib/bridge/resources/bars/xhdpi/ic_sysbar_home.png
new file mode 100644
index 0000000..c5bc5c9
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/xhdpi/ic_sysbar_home.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/xhdpi/ic_sysbar_home_default.png b/tools/layoutlib/bridge/resources/bars/xhdpi/ic_sysbar_home_default.png
deleted file mode 100644
index 31d35c8..0000000
--- a/tools/layoutlib/bridge/resources/bars/xhdpi/ic_sysbar_home_default.png
+++ /dev/null
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/xhdpi/ic_sysbar_recent.png b/tools/layoutlib/bridge/resources/bars/xhdpi/ic_sysbar_recent.png
new file mode 100644
index 0000000..f621d9c
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/xhdpi/ic_sysbar_recent.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/xhdpi/ic_sysbar_recent_default.png b/tools/layoutlib/bridge/resources/bars/xhdpi/ic_sysbar_recent_default.png
deleted file mode 100644
index f0cc341d..0000000
--- a/tools/layoutlib/bridge/resources/bars/xhdpi/ic_sysbar_recent_default.png
+++ /dev/null
Binary files differ
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
index daf520b..bf8658e 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -210,7 +210,8 @@
                 Capability.PLAY_ANIMATION,
                 Capability.ANIMATED_VIEW_MANIPULATION,
                 Capability.ADAPTER_BINDING,
-                Capability.EXTENDED_VIEWINFO);
+                Capability.EXTENDED_VIEWINFO,
+                Capability.FIXED_SCALABLE_NINE_PATCH);
 
 
         BridgeAssetManager.initSystem();
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
index 62c886b..ea9d8d9 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
@@ -60,11 +60,15 @@
 
     protected abstract TextView getStyleableTextView();
 
-    protected CustomBar(Context context, Density density, String layoutPath, String name)
-            throws XmlPullParserException {
+    protected CustomBar(Context context, Density density, int orientation, String layoutPath,
+            String name) throws XmlPullParserException {
         super(context);
-        setOrientation(LinearLayout.HORIZONTAL);
-        setGravity(Gravity.CENTER_VERTICAL);
+        setOrientation(orientation);
+        if (orientation == LinearLayout.HORIZONTAL) {
+            setGravity(Gravity.CENTER_VERTICAL);
+        } else {
+            setGravity(Gravity.CENTER_HORIZONTAL);
+        }
 
         LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(
                 Context.LAYOUT_INFLATER_SERVICE);
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/FakeActionBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/FakeActionBar.java
index 68f5aba..226649d 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/FakeActionBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/FakeActionBar.java
@@ -21,6 +21,7 @@
 import org.xmlpull.v1.XmlPullParserException;
 
 import android.content.Context;
+import android.widget.LinearLayout;
 import android.widget.TextView;
 
 public class FakeActionBar extends CustomBar {
@@ -29,7 +30,7 @@
 
     public FakeActionBar(Context context, Density density, String label, String icon)
             throws XmlPullParserException {
-        super(context, density, "/bars/action_bar.xml", "action_bar.xml");
+        super(context, density, LinearLayout.HORIZONTAL, "/bars/action_bar.xml", "action_bar.xml");
 
         // Cannot access the inside items through id because no R.id values have been
         // created for them.
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java
new file mode 100644
index 0000000..cc90d6b
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.layoutlib.bridge.bars;
+
+import com.android.resources.Density;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.content.Context;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+public class NavigationBar extends CustomBar {
+
+    public NavigationBar(Context context, Density density, int orientation) throws XmlPullParserException {
+        super(context, density, orientation, "/bars/navigation_bar.xml", "navigation_bar.xml");
+
+        setBackgroundColor(0xFF000000);
+
+        // Cannot access the inside items through id because no R.id values have been
+        // created for them.
+        // We do know the order though.
+        // 0 is a spacer.
+        int back = 1;
+        int recent = 3;
+        if (orientation == LinearLayout.VERTICAL) {
+            back = 3;
+            recent = 1;
+        }
+
+        loadIcon(back,   "ic_sysbar_back.png", density);
+        loadIcon(2,      "ic_sysbar_home.png", density);
+        loadIcon(recent, "ic_sysbar_recent.png", density);
+    }
+
+    @Override
+    protected TextView getStyleableTextView() {
+        return null;
+    }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/PhoneSystemBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java
similarity index 86%
rename from tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/PhoneSystemBar.java
rename to tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java
index 7521011..5c08412 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/PhoneSystemBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java
@@ -25,12 +25,13 @@
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.LevelListDrawable;
 import android.view.Gravity;
+import android.widget.LinearLayout;
 import android.widget.TextView;
 
-public class PhoneSystemBar extends CustomBar {
+public class StatusBar extends CustomBar {
 
-    public PhoneSystemBar(Context context, Density density) throws XmlPullParserException {
-        super(context, density, "/bars/phone_system_bar.xml", "phone_system_bar.xml");
+    public StatusBar(Context context, Density density) throws XmlPullParserException {
+        super(context, density, LinearLayout.HORIZONTAL, "/bars/status_bar.xml", "status_bar.xml");
 
         // FIXME: use FILL_H?
         setGravity(Gravity.START | Gravity.TOP | Gravity.RIGHT);
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/TabletSystemBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/TabletSystemBar.java
deleted file mode 100644
index 456ddb4..0000000
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/TabletSystemBar.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.layoutlib.bridge.bars;
-
-import com.android.resources.Density;
-import com.android.resources.ResourceType;
-
-import org.xmlpull.v1.XmlPullParserException;
-
-import android.content.Context;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.LevelListDrawable;
-import android.widget.TextView;
-
-public class TabletSystemBar extends CustomBar {
-
-    public TabletSystemBar(Context context, Density density) throws XmlPullParserException {
-        super(context, density, "/bars/tablet_system_bar.xml", "tablet_system_bar.xml");
-
-        setBackgroundColor(0xFF000000);
-
-        // Cannot access the inside items through id because no R.id values have been
-        // created for them.
-        // We do know the order though.
-        loadIcon(0, "ic_sysbar_back_default.png", density);
-        loadIcon(1, "ic_sysbar_home_default.png", density);
-        loadIcon(2, "ic_sysbar_recent_default.png", density);
-        // 3 is the spacer
-        loadIcon(4, "stat_sys_wifi_signal_4_fully.png", density);
-        Drawable drawable = loadIcon(5, ResourceType.DRAWABLE, "stat_sys_battery_charge");
-        if (drawable instanceof LevelListDrawable) {
-            ((LevelListDrawable) drawable).setLevel(100);
-        }
-    }
-
-    @Override
-    protected TextView getStyleableTextView() {
-        return null;
-    }
-}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/TitleBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/TitleBar.java
index 5f5ebc4..c27859f 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/TitleBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/TitleBar.java
@@ -21,6 +21,7 @@
 import org.xmlpull.v1.XmlPullParserException;
 
 import android.content.Context;
+import android.widget.LinearLayout;
 import android.widget.TextView;
 
 public class TitleBar extends CustomBar {
@@ -29,7 +30,7 @@
 
     public TitleBar(Context context, Density density, String label)
             throws XmlPullParserException {
-        super(context, density, "/bars/title_bar.xml", "title_bar.xml");
+        super(context, density, LinearLayout.HORIZONTAL, "/bars/title_bar.xml", "title_bar.xml");
 
         // Cannot access the inside items through id because no R.id values have been
         // created for them.
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ParserFactory.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ParserFactory.java
index a235ec3..803849f 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ParserFactory.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ParserFactory.java
@@ -21,9 +21,12 @@
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
+import java.io.IOException;
 import java.io.InputStream;
 
 /**
@@ -38,14 +41,21 @@
 
     public static XmlPullParser create(File f)
             throws XmlPullParserException, FileNotFoundException {
-        KXmlParser parser = instantiateParser(f.getName());
-        parser.setInput(new FileInputStream(f), ENCODING);
-        return parser;
+        InputStream stream = new FileInputStream(f);
+        return create(stream, f.getName(), f.length());
     }
 
     public static XmlPullParser create(InputStream stream, String name)
+        throws XmlPullParserException {
+        return create(stream, name, -1);
+    }
+
+    private static XmlPullParser create(InputStream stream, String name, long size)
             throws XmlPullParserException {
         KXmlParser parser = instantiateParser(name);
+
+        stream = readAndClose(stream, name, size);
+
         parser.setInput(stream, ENCODING);
         return parser;
     }
@@ -61,6 +71,61 @@
         return parser;
     }
 
+    private static InputStream readAndClose(InputStream stream, String name, long size)
+            throws XmlPullParserException {
+        // just a sanity check. It's doubtful we'll have such big files!
+        if (size > Integer.MAX_VALUE) {
+            throw new XmlPullParserException("File " + name + " is too big to be parsed");
+        }
+        int intSize = (int) size;
+
+        // create a buffered reader to facilitate reading.
+        BufferedInputStream bufferedStream = new BufferedInputStream(stream);
+        try {
+            int avail;
+            if (intSize != -1) {
+                avail = intSize;
+            } else {
+                // get the size to read.
+                avail = bufferedStream.available();
+            }
+
+            // create the initial buffer and read it.
+            byte[] buffer = new byte[avail];
+            int read = stream.read(buffer);
+
+            // this is the easy case.
+            if (read == intSize) {
+                return new ByteArrayInputStream(buffer);
+            }
+
+            // check if there is more to read (read() does not necessarily read all that
+            // available() returned!)
+            while ((avail = bufferedStream.available()) > 0) {
+                if (read + avail > buffer.length) {
+                    // just allocate what is needed. We're mostly reading small files
+                    // so it shouldn't be too problematic.
+                    byte[] moreBuffer = new byte[read + avail];
+                    System.arraycopy(buffer, 0, moreBuffer, 0, read);
+                    buffer = moreBuffer;
+                }
+
+                read += stream.read(buffer, read, avail);
+            }
+
+            // return a new stream encapsulating this buffer.
+            return new ByteArrayInputStream(buffer);
+
+        } catch (IOException e) {
+            throw new XmlPullParserException("Failed to read " + name, null, e);
+        } finally {
+            try {
+                bufferedStream.close();
+            } catch (IOException e) {
+            }
+        }
+    }
+
     private static class CustomParser extends KXmlParser {
         private final String mName;
 
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
index de65fd4..f109e39 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
@@ -20,11 +20,12 @@
 import static com.android.ide.common.rendering.api.Result.Status.ERROR_TIMEOUT;
 import static com.android.ide.common.rendering.api.Result.Status.SUCCESS;
 
+import com.android.ide.common.rendering.api.HardwareConfig;
 import com.android.ide.common.rendering.api.LayoutLog;
 import com.android.ide.common.rendering.api.RenderParams;
 import com.android.ide.common.rendering.api.RenderResources;
-import com.android.ide.common.rendering.api.Result;
 import com.android.ide.common.rendering.api.RenderResources.FrameworkResourceIdProvider;
+import com.android.ide.common.rendering.api.Result;
 import com.android.layoutlib.bridge.Bridge;
 import com.android.layoutlib.bridge.android.BridgeContext;
 import com.android.resources.Density;
@@ -98,19 +99,22 @@
             return result;
         }
 
+        HardwareConfig hardwareConfig = mParams.getHardwareConfig();
+
         // setup the display Metrics.
         DisplayMetrics metrics = new DisplayMetrics();
-        metrics.densityDpi = metrics.noncompatDensityDpi = mParams.getDensity().getDpiValue();
+        metrics.densityDpi = metrics.noncompatDensityDpi =
+                hardwareConfig.getDensity().getDpiValue();
 
         metrics.density = metrics.noncompatDensity =
                 metrics.densityDpi / (float) DisplayMetrics.DENSITY_DEFAULT;
 
         metrics.scaledDensity = metrics.noncompatScaledDensity = metrics.density;
 
-        metrics.widthPixels = metrics.noncompatWidthPixels = mParams.getScreenWidth();
-        metrics.heightPixels = metrics.noncompatHeightPixels = mParams.getScreenHeight();
-        metrics.xdpi = metrics.noncompatXdpi = mParams.getXdpi();
-        metrics.ydpi = metrics.noncompatYdpi = mParams.getYdpi();
+        metrics.widthPixels = metrics.noncompatWidthPixels = hardwareConfig.getScreenWidth();
+        metrics.heightPixels = metrics.noncompatHeightPixels = hardwareConfig.getScreenHeight();
+        metrics.xdpi = metrics.noncompatXdpi = hardwareConfig.getXdpi();
+        metrics.ydpi = metrics.noncompatYdpi = hardwareConfig.getYdpi();
 
         RenderResources resources = mParams.getResources();
 
@@ -305,7 +309,9 @@
     private Configuration getConfiguration() {
         Configuration config = new Configuration();
 
-        ScreenSize screenSize = mParams.getConfigScreenSize();
+        HardwareConfig hardwareConfig = mParams.getHardwareConfig();
+
+        ScreenSize screenSize = hardwareConfig.getScreenSize();
         if (screenSize != null) {
             switch (screenSize) {
                 case SMALL:
@@ -323,13 +329,13 @@
             }
         }
 
-        Density density = mParams.getDensity();
+        Density density = hardwareConfig.getDensity();
         if (density == null) {
             density = Density.MEDIUM;
         }
 
-        config.screenWidthDp = mParams.getScreenWidth() / density.getDpiValue();
-        config.screenHeightDp = mParams.getScreenHeight() / density.getDpiValue();
+        config.screenWidthDp = hardwareConfig.getScreenWidth() / density.getDpiValue();
+        config.screenHeightDp = hardwareConfig.getScreenHeight() / density.getDpiValue();
         if (config.screenHeightDp < config.screenWidthDp) {
             config.smallestScreenWidthDp = config.screenHeightDp;
         } else {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java
index 8133210..b677131 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java
@@ -19,6 +19,7 @@
 import static com.android.ide.common.rendering.api.Result.Status.ERROR_UNKNOWN;
 
 import com.android.ide.common.rendering.api.DrawableParams;
+import com.android.ide.common.rendering.api.HardwareConfig;
 import com.android.ide.common.rendering.api.ResourceValue;
 import com.android.ide.common.rendering.api.Result;
 import com.android.ide.common.rendering.api.Result.Status;
@@ -59,6 +60,7 @@
         try {
             // get the drawable resource value
             DrawableParams params = getParams();
+            HardwareConfig hardwareConfig = params.getHardwareConfig();
             ResourceValue drawableResource = params.getDrawable();
 
             // resolve it
@@ -75,15 +77,15 @@
 
             // get the actual Drawable object to draw
             Drawable d = ResourceHelper.getDrawable(drawableResource, context);
-            content.setBackgroundDrawable(d);
+            content.setBackground(d);
 
             // set the AttachInfo on the root view.
             AttachInfo_Accessor.setAttachInfo(content);
 
 
             // measure
-            int w = params.getScreenWidth();
-            int h = params.getScreenHeight();
+            int w = hardwareConfig.getScreenWidth();
+            int h = hardwareConfig.getScreenHeight();
             int w_spec = MeasureSpec.makeMeasureSpec(w, MeasureSpec.EXACTLY);
             int h_spec = MeasureSpec.makeMeasureSpec(h, MeasureSpec.EXACTLY);
             content.measure(w_spec, h_spec);
@@ -99,11 +101,11 @@
 
             // create an Android bitmap around the BufferedImage
             Bitmap bitmap = Bitmap_Delegate.createBitmap(image,
-                    true /*isMutable*/, params.getDensity());
+                    true /*isMutable*/, hardwareConfig.getDensity());
 
             // create a Canvas around the Android bitmap
             Canvas canvas = new Canvas(bitmap);
-            canvas.setDensity(params.getDensity().getDpiValue());
+            canvas.setDensity(hardwareConfig.getDensity().getDpiValue());
 
             // and draw
             content.draw(canvas);
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
index cc0f077..c14af4a 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
@@ -24,6 +24,7 @@
 import static com.android.ide.common.rendering.api.Result.Status.SUCCESS;
 
 import com.android.ide.common.rendering.api.AdapterBinding;
+import com.android.ide.common.rendering.api.HardwareConfig;
 import com.android.ide.common.rendering.api.IAnimationListener;
 import com.android.ide.common.rendering.api.ILayoutPullParser;
 import com.android.ide.common.rendering.api.IProjectCallback;
@@ -43,13 +44,13 @@
 import com.android.layoutlib.bridge.android.BridgeLayoutParamsMapAttributes;
 import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
 import com.android.layoutlib.bridge.bars.FakeActionBar;
-import com.android.layoutlib.bridge.bars.PhoneSystemBar;
-import com.android.layoutlib.bridge.bars.TabletSystemBar;
+import com.android.layoutlib.bridge.bars.NavigationBar;
+import com.android.layoutlib.bridge.bars.StatusBar;
 import com.android.layoutlib.bridge.bars.TitleBar;
 import com.android.layoutlib.bridge.impl.binding.FakeAdapter;
 import com.android.layoutlib.bridge.impl.binding.FakeExpandableAdapter;
 import com.android.resources.ResourceType;
-import com.android.resources.ScreenSize;
+import com.android.resources.ScreenOrientation;
 import com.android.util.Pair;
 
 import org.xmlpull.v1.XmlPullParserException;
@@ -68,8 +69,8 @@
 import android.util.TypedValue;
 import android.view.AttachInfo_Accessor;
 import android.view.BridgeInflater;
-import android.view.IWindowManagerImpl;
 import android.view.IWindowManager;
+import android.view.IWindowManagerImpl;
 import android.view.Surface;
 import android.view.View;
 import android.view.View.MeasureSpec;
@@ -124,7 +125,8 @@
     private boolean mWindowIsFloating;
 
     private int mStatusBarSize;
-    private int mSystemBarSize;
+    private int mNavigationBarSize;
+    private int mNavigationBarOrientation = LinearLayout.HORIZONTAL;
     private int mTitleBarSize;
     private int mActionBarSize;
 
@@ -187,7 +189,7 @@
         findBackground(resources);
         findStatusBar(resources, metrics);
         findActionBar(resources, metrics);
-        findSystemBar(resources, metrics);
+        findNavigationBar(resources, metrics);
 
         // FIXME: find those out, and possibly add them to the render params
         boolean hasSystemNavBar = true;
@@ -221,19 +223,57 @@
         try {
 
             SessionParams params = getParams();
+            HardwareConfig hardwareConfig = params.getHardwareConfig();
             BridgeContext context = getContext();
 
+
             // the view group that receives the window background.
             ViewGroup backgroundView = null;
 
             if (mWindowIsFloating || params.isForceNoDecor()) {
                 backgroundView = mViewRoot = mContentRoot = new FrameLayout(context);
             } else {
+                if (hasSoftwareButtons() && mNavigationBarOrientation == LinearLayout.VERTICAL) {
+                    /*
+                     * This is a special case where the navigation bar is on the right.
+                       +-------------------------------------------------+---+
+                       | Status bar (always)                             |   |
+                       +-------------------------------------------------+   |
+                       | (Layout with background drawable)               |   |
+                       | +---------------------------------------------+ |   |
+                       | | Title/Action bar (optional)                 | |   |
+                       | +---------------------------------------------+ |   |
+                       | | Content, vertical extending                 | |   |
+                       | |                                             | |   |
+                       | +---------------------------------------------+ |   |
+                       +-------------------------------------------------+---+
+
+                       So we create a horizontal layout, with the nav bar on the right,
+                       and the left part is the normal layout below without the nav bar at
+                       the bottom
+                     */
+                    LinearLayout topLayout = new LinearLayout(context);
+                    mViewRoot = topLayout;
+                    topLayout.setOrientation(LinearLayout.HORIZONTAL);
+
+                    try {
+                        NavigationBar navigationBar = new NavigationBar(context,
+                                hardwareConfig.getDensity(), LinearLayout.VERTICAL);
+                        navigationBar.setLayoutParams(
+                                new LinearLayout.LayoutParams(
+                                        mNavigationBarSize,
+                                        LayoutParams.MATCH_PARENT));
+                        topLayout.addView(navigationBar);
+                    } catch (XmlPullParserException e) {
+
+                    }
+                }
+
                 /*
                  * we're creating the following layout
                  *
                    +-------------------------------------------------+
-                   | System bar (only in phone UI)                   |
+                   | Status bar (always)                             |
                    +-------------------------------------------------+
                    | (Layout with background drawable)               |
                    | +---------------------------------------------+ |
@@ -243,20 +283,31 @@
                    | |                                             | |
                    | +---------------------------------------------+ |
                    +-------------------------------------------------+
-                   | System bar (only in tablet UI)                  |
+                   | Navigation bar for soft buttons, maybe see above|
                    +-------------------------------------------------+
 
                  */
 
                 LinearLayout topLayout = new LinearLayout(context);
-                mViewRoot = topLayout;
                 topLayout.setOrientation(LinearLayout.VERTICAL);
+                // if we don't already have a view root this is it
+                if (mViewRoot == null) {
+                    mViewRoot = topLayout;
+                } else {
+                    LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
+                            LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
+                    layoutParams.weight = 1;
+                    topLayout.setLayoutParams(layoutParams);
+
+                    // this is the case of soft buttons + vertical bar.
+                    // this top layout is the first layout in the horizontal layout. see above)
+                    mViewRoot.addView(topLayout, 0);
+                }
 
                 if (mStatusBarSize > 0) {
                     // system bar
                     try {
-                        PhoneSystemBar systemBar = new PhoneSystemBar(context,
-                                params.getDensity());
+                        StatusBar systemBar = new StatusBar(context, hardwareConfig.getDensity());
                         systemBar.setLayoutParams(
                                 new LinearLayout.LayoutParams(
                                         LayoutParams.MATCH_PARENT, mStatusBarSize));
@@ -280,7 +331,7 @@
                 if (mActionBarSize > 0) {
                     try {
                         FakeActionBar actionBar = new FakeActionBar(context,
-                                params.getDensity(),
+                                hardwareConfig.getDensity(),
                                 params.getAppLabel(), params.getAppIcon());
                         actionBar.setLayoutParams(
                                 new LinearLayout.LayoutParams(
@@ -292,7 +343,7 @@
                 } else if (mTitleBarSize > 0) {
                     try {
                         TitleBar titleBar = new TitleBar(context,
-                                params.getDensity(), params.getAppLabel());
+                                hardwareConfig.getDensity(), params.getAppLabel());
                         titleBar.setLayoutParams(
                                 new LinearLayout.LayoutParams(
                                         LayoutParams.MATCH_PARENT, mTitleBarSize));
@@ -310,15 +361,16 @@
                 mContentRoot.setLayoutParams(layoutParams);
                 backgroundLayout.addView(mContentRoot);
 
-                if (mSystemBarSize > 0) {
+                if (mNavigationBarOrientation == LinearLayout.HORIZONTAL &&
+                        mNavigationBarSize > 0) {
                     // system bar
                     try {
-                        TabletSystemBar systemBar = new TabletSystemBar(context,
-                                params.getDensity());
-                        systemBar.setLayoutParams(
+                        NavigationBar navigationBar = new NavigationBar(context,
+                                hardwareConfig.getDensity(), LinearLayout.HORIZONTAL);
+                        navigationBar.setLayoutParams(
                                 new LinearLayout.LayoutParams(
-                                        LayoutParams.MATCH_PARENT, mSystemBarSize));
-                        topLayout.addView(systemBar);
+                                        LayoutParams.MATCH_PARENT, mNavigationBarSize));
+                        topLayout.addView(navigationBar);
                     } catch (XmlPullParserException e) {
 
                     }
@@ -346,7 +398,7 @@
             // get the background drawable
             if (mWindowBackground != null && backgroundView != null) {
                 Drawable d = ResourceHelper.getDrawable(mWindowBackground, context);
-                backgroundView.setBackgroundDrawable(d);
+                backgroundView.setBackground(d);
             }
 
             return SUCCESS.createResult();
@@ -389,13 +441,14 @@
             }
 
             RenderingMode renderingMode = params.getRenderingMode();
+            HardwareConfig hardwareConfig = params.getHardwareConfig();
 
             // only do the screen measure when needed.
             boolean newRenderSize = false;
             if (mMeasuredScreenWidth == -1) {
                 newRenderSize = true;
-                mMeasuredScreenWidth = params.getScreenWidth();
-                mMeasuredScreenHeight = params.getScreenHeight();
+                mMeasuredScreenWidth = hardwareConfig.getScreenWidth();
+                mMeasuredScreenHeight = hardwareConfig.getScreenHeight();
 
                 if (renderingMode != RenderingMode.NORMAL) {
                     int widthMeasureSpecMode = renderingMode.isHorizExpand() ?
@@ -495,11 +548,11 @@
 
                     // create an Android bitmap around the BufferedImage
                     Bitmap bitmap = Bitmap_Delegate.createBitmap(mImage,
-                            true /*isMutable*/, params.getDensity());
+                            true /*isMutable*/, hardwareConfig.getDensity());
 
                     // create a Canvas around the Android bitmap
                     mCanvas = new Canvas(bitmap);
-                    mCanvas.setDensity(params.getDensity().getDpiValue());
+                    mCanvas.setDensity(hardwareConfig.getDensity().getDpiValue());
                 }
 
                 if (freshRender && newImage == false) {
@@ -972,30 +1025,28 @@
         }
     }
 
-    private boolean isTabletUi() {
-        return getParams().getConfigScreenSize() == ScreenSize.XLARGE;
+    private boolean hasSoftwareButtons() {
+        return getParams().getHardwareConfig().hasSoftwareButtons();
     }
 
     private void findStatusBar(RenderResources resources, DisplayMetrics metrics) {
-        if (isTabletUi() == false) {
-            boolean windowFullscreen = getBooleanThemeValue(resources,
-                    "windowFullscreen", false /*defaultValue*/);
+        boolean windowFullscreen = getBooleanThemeValue(resources,
+                "windowFullscreen", false /*defaultValue*/);
 
-            if (windowFullscreen == false && mWindowIsFloating == false) {
-                // default value
-                mStatusBarSize = DEFAULT_STATUS_BAR_HEIGHT;
+        if (windowFullscreen == false && mWindowIsFloating == false) {
+            // default value
+            mStatusBarSize = DEFAULT_STATUS_BAR_HEIGHT;
 
-                // get the real value
-                ResourceValue value = resources.getFrameworkResource(ResourceType.DIMEN,
-                        "status_bar_height");
+            // get the real value
+            ResourceValue value = resources.getFrameworkResource(ResourceType.DIMEN,
+                    "status_bar_height");
 
-                if (value != null) {
-                    TypedValue typedValue = ResourceHelper.getValue("status_bar_height",
-                            value.getValue(), true /*requireUnit*/);
-                    if (typedValue != null) {
-                        // compute the pixel value based on the display metrics
-                        mStatusBarSize = (int)typedValue.getDimension(metrics);
-                    }
+            if (value != null) {
+                TypedValue typedValue = ResourceHelper.getValue("status_bar_height",
+                        value.getValue(), true /*requireUnit*/);
+                if (typedValue != null) {
+                    // compute the pixel value based on the display metrics
+                    mStatusBarSize = (int)typedValue.getDimension(metrics);
                 }
             }
         }
@@ -1062,22 +1113,48 @@
         }
     }
 
-    private void findSystemBar(RenderResources resources, DisplayMetrics metrics) {
-        if (isTabletUi() && mWindowIsFloating == false) {
+    private void findNavigationBar(RenderResources resources, DisplayMetrics metrics) {
+        if (hasSoftwareButtons() && mWindowIsFloating == false) {
 
             // default value
-            mSystemBarSize = 48; // ??
+            mNavigationBarSize = 48; // ??
+
+            HardwareConfig hardwareConfig = getParams().getHardwareConfig();
+
+            boolean barOnBottom = true;
+
+            if (hardwareConfig.getOrientation() == ScreenOrientation.LANDSCAPE) {
+                // compute the dp of the screen.
+                int shortSize = hardwareConfig.getScreenHeight();
+
+                // compute in dp
+                int shortSizeDp = shortSize * DisplayMetrics.DENSITY_DEFAULT / hardwareConfig.getDensity().getDpiValue();
+
+                if (shortSizeDp < 600) {
+                    // 0-599dp: "phone" UI with bar on the side
+                    barOnBottom = false;
+                } else {
+                    // 600+dp: "tablet" UI with bar on the bottom
+                    barOnBottom = true;
+                }
+            }
+
+            if (barOnBottom) {
+                mNavigationBarOrientation = LinearLayout.HORIZONTAL;
+            } else {
+                mNavigationBarOrientation = LinearLayout.VERTICAL;
+            }
 
             // get the real value
             ResourceValue value = resources.getFrameworkResource(ResourceType.DIMEN,
-                    "status_bar_height");
+                    barOnBottom ? "navigation_bar_height" : "navigation_bar_width");
 
             if (value != null) {
-                TypedValue typedValue = ResourceHelper.getValue("status_bar_height",
+                TypedValue typedValue = ResourceHelper.getValue("navigation_bar_height",
                         value.getValue(), true /*requireUnit*/);
                 if (typedValue != null) {
                     // compute the pixel value based on the display metrics
-                    mSystemBarSize = (int)typedValue.getDimension(metrics);
+                    mNavigationBarSize = (int)typedValue.getDimension(metrics);
                 }
             }
         }
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index e913d10..b871cdc 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -1983,7 +1983,9 @@
 
     protected void finalize() throws Throwable {
         try {
-            mHandler.getLooper().quit();
+            if (mHandler != null && mHandler.getLooper() != null) {
+                mHandler.getLooper().quit();
+            }
         } finally {
             super.finalize();
         }
diff --git a/wifi/java/android/net/wifi/WifiMonitor.java b/wifi/java/android/net/wifi/WifiMonitor.java
index 93ab4a4..0b0d7388e 100644
--- a/wifi/java/android/net/wifi/WifiMonitor.java
+++ b/wifi/java/android/net/wifi/WifiMonitor.java
@@ -178,6 +178,7 @@
 
     private static final String P2P_GO_NEG_SUCCESS_STR = "P2P-GO-NEG-SUCCESS";
 
+    /* P2P-GO-NEG-FAILURE status=x */
     private static final String P2P_GO_NEG_FAILURE_STR = "P2P-GO-NEG-FAILURE";
 
     private static final String P2P_GROUP_FORMATION_SUCCESS_STR =
@@ -566,6 +567,26 @@
                     WifiManager.ERROR, 0));
         }
 
+        /* <event> status=<err> and the special case of <event> reason=FREQ_CONFLICT */
+        private P2pStatus p2pError(String dataString) {
+            P2pStatus err = P2pStatus.UNKNOWN;
+            String[] tokens = dataString.split(" ");
+            if (tokens.length < 2) return err;
+            String[] nameValue = tokens[1].split("=");
+            if (nameValue.length != 2) return err;
+
+            /* Handle the special case of reason=FREQ+CONFLICT */
+            if (nameValue[1].equals("FREQ_CONFLICT")) {
+                return P2pStatus.NO_COMMON_CHANNEL;
+            }
+            try {
+                err = P2pStatus.valueOf(Integer.parseInt(nameValue[1]));
+            } catch (NumberFormatException e) {
+                e.printStackTrace();
+            }
+            return err;
+        }
+
         /**
          * Handle p2p events
          */
@@ -582,11 +603,11 @@
             } else if (dataString.startsWith(P2P_GO_NEG_SUCCESS_STR)) {
                 mStateMachine.sendMessage(P2P_GO_NEGOTIATION_SUCCESS_EVENT);
             } else if (dataString.startsWith(P2P_GO_NEG_FAILURE_STR)) {
-                mStateMachine.sendMessage(P2P_GO_NEGOTIATION_FAILURE_EVENT);
+                mStateMachine.sendMessage(P2P_GO_NEGOTIATION_FAILURE_EVENT, p2pError(dataString));
             } else if (dataString.startsWith(P2P_GROUP_FORMATION_SUCCESS_STR)) {
                 mStateMachine.sendMessage(P2P_GROUP_FORMATION_SUCCESS_EVENT);
             } else if (dataString.startsWith(P2P_GROUP_FORMATION_FAILURE_STR)) {
-                mStateMachine.sendMessage(P2P_GROUP_FORMATION_FAILURE_EVENT);
+                mStateMachine.sendMessage(P2P_GROUP_FORMATION_FAILURE_EVENT, p2pError(dataString));
             } else if (dataString.startsWith(P2P_GROUP_STARTED_STR)) {
                 mStateMachine.sendMessage(P2P_GROUP_STARTED_EVENT, new WifiP2pGroup(dataString));
             } else if (dataString.startsWith(P2P_GROUP_REMOVED_STR)) {
@@ -595,17 +616,7 @@
                 mStateMachine.sendMessage(P2P_INVITATION_RECEIVED_EVENT,
                         new WifiP2pGroup(dataString));
             } else if (dataString.startsWith(P2P_INVITATION_RESULT_STR)) {
-                String[] tokens = dataString.split(" ");
-                if (tokens.length != 2) return;
-                String[] nameValue = tokens[1].split("=");
-                if (nameValue.length != 2) return;
-                P2pStatus err = P2pStatus.UNKNOWN;
-                try {
-                    err = P2pStatus.valueOf(Integer.parseInt(nameValue[1]));
-                } catch (NumberFormatException e) {
-                    e.printStackTrace();
-                }
-                mStateMachine.sendMessage(P2P_INVITATION_RESULT_EVENT, err);
+                mStateMachine.sendMessage(P2P_INVITATION_RESULT_EVENT, p2pError(dataString));
             } else if (dataString.startsWith(P2P_PROV_DISC_PBC_REQ_STR)) {
                 mStateMachine.sendMessage(P2P_PROV_DISC_PBC_REQ_EVENT,
                         new WifiP2pProvDiscEvent(dataString));
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index db539e4..fd76fc8d 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -114,6 +114,7 @@
 
     private final boolean mP2pSupported;
     private final AtomicBoolean mP2pConnected = new AtomicBoolean(false);
+    private boolean mTemporarilyDisconnectWifi = false;
     private final String mPrimaryDeviceType;
 
     /* Scan results handling */
@@ -358,8 +359,12 @@
     static final int CMD_RESET_SUPPLICANT_STATE           = BASE + 111;
 
     /* P2p commands */
+    /* We are ok with no response here since we wont do much with it anyway */
     public static final int CMD_ENABLE_P2P                = BASE + 131;
-    public static final int CMD_DISABLE_P2P               = BASE + 132;
+    /* In order to shut down supplicant cleanly, we wait till p2p has
+     * been disabled */
+    public static final int CMD_DISABLE_P2P_REQ           = BASE + 132;
+    public static final int CMD_DISABLE_P2P_RSP           = BASE + 133;
 
     private static final int CONNECT_MODE   = 1;
     private static final int SCAN_ONLY_MODE = 2;
@@ -457,6 +462,11 @@
     private State mDriverStartingState = new DriverStartingState();
     /* Driver started */
     private State mDriverStartedState = new DriverStartedState();
+    /* Wait until p2p is disabled
+     * This is a special state which is entered right after we exit out of DriverStartedState
+     * before transitioning to another state.
+     */
+    private State mWaitForP2pDisableState = new WaitForP2pDisableState();
     /* Driver stopping */
     private State mDriverStoppingState = new DriverStoppingState();
     /* Driver stopped */
@@ -698,6 +708,7 @@
                         addState(mDisconnectingState, mConnectModeState);
                         addState(mDisconnectedState, mConnectModeState);
                         addState(mWpsRunningState, mConnectModeState);
+                addState(mWaitForP2pDisableState, mSupplicantStartedState);
                 addState(mDriverStoppingState, mSupplicantStartedState);
                 addState(mDriverStoppedState, mSupplicantStartedState);
             addState(mSupplicantStoppingState, mDefaultState);
@@ -2017,6 +2028,10 @@
                     NetworkInfo info = (NetworkInfo) message.obj;
                     mP2pConnected.set(info.isConnected());
                     break;
+                case WifiP2pService.DISCONNECT_WIFI_REQUEST:
+                    mTemporarilyDisconnectWifi = (message.arg1 == 1);
+                    replyToMessage(message, WifiP2pService.DISCONNECT_WIFI_RESPONSE);
+                    break;
                 default:
                     loge("Error! unhandled message" + message);
                     break;
@@ -2428,7 +2443,11 @@
             WifiConfiguration config;
             switch(message.what) {
                 case CMD_STOP_SUPPLICANT:   /* Supplicant stopped by user */
-                    transitionTo(mSupplicantStoppingState);
+                    if (mP2pSupported) {
+                        transitionTo(mWaitForP2pDisableState);
+                    } else {
+                        transitionTo(mSupplicantStoppingState);
+                    }
                     break;
                 case WifiMonitor.SUP_DISCONNECTION_EVENT:  /* Supplicant connection lost */
                     loge("Connection lost, restart supplicant");
@@ -2438,7 +2457,11 @@
                     handleNetworkDisconnect();
                     sendSupplicantConnectionChangedBroadcast(false);
                     mSupplicantStateTracker.sendMessage(CMD_RESET_SUPPLICANT_STATE);
-                    transitionTo(mDriverLoadedState);
+                    if (mP2pSupported) {
+                        transitionTo(mWaitForP2pDisableState);
+                    } else {
+                        transitionTo(mDriverLoadedState);
+                    }
                     sendMessageDelayed(CMD_START_SUPPLICANT, SUPPLICANT_RESTART_INTERVAL_MSECS);
                     break;
                 case WifiMonitor.SCAN_RESULTS_EVENT:
@@ -2833,8 +2856,12 @@
                     }
                     mWakeLock.acquire();
                     mWifiNative.stopDriver();
-                    transitionTo(mDriverStoppingState);
                     mWakeLock.release();
+                    if (mP2pSupported) {
+                        transitionTo(mWaitForP2pDisableState);
+                    } else {
+                        transitionTo(mDriverStoppingState);
+                    }
                     break;
                 case CMD_START_PACKET_FILTERING:
                     if (message.arg1 == MULTICAST_V6) {
@@ -2880,8 +2907,63 @@
             mIsRunning = false;
             updateBatteryWorkSource(null);
             mScanResults = new ArrayList<ScanResult>();
+        }
+    }
 
-            if (mP2pSupported) mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_DISABLE_P2P);
+    class WaitForP2pDisableState extends State {
+        private State mTransitionToState;
+        @Override
+        public void enter() {
+            if (DBG) log(getName() + "\n");
+            EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
+            switch (getCurrentMessage().what) {
+                case WifiMonitor.SUP_DISCONNECTION_EVENT:
+                    mTransitionToState = mDriverLoadedState;
+                    break;
+                case CMD_DELAYED_STOP_DRIVER:
+                    mTransitionToState = mDriverStoppingState;
+                    break;
+                case CMD_STOP_SUPPLICANT:
+                    mTransitionToState = mSupplicantStoppingState;
+                    break;
+                default:
+                    mTransitionToState = mDriverStoppingState;
+                    break;
+            }
+            mWifiP2pChannel.sendMessage(WifiStateMachine.CMD_DISABLE_P2P_REQ);
+        }
+        @Override
+        public boolean processMessage(Message message) {
+            if (DBG) log(getName() + message.toString() + "\n");
+            switch(message.what) {
+                case WifiStateMachine.CMD_DISABLE_P2P_RSP:
+                    transitionTo(mTransitionToState);
+                    break;
+                /* Defer wifi start/shut and driver commands */
+                case CMD_LOAD_DRIVER:
+                case CMD_UNLOAD_DRIVER:
+                case CMD_START_SUPPLICANT:
+                case CMD_STOP_SUPPLICANT:
+                case CMD_START_AP:
+                case CMD_STOP_AP:
+                case CMD_START_DRIVER:
+                case CMD_STOP_DRIVER:
+                case CMD_SET_SCAN_MODE:
+                case CMD_SET_SCAN_TYPE:
+                case CMD_SET_COUNTRY_CODE:
+                case CMD_SET_FREQUENCY_BAND:
+                case CMD_START_PACKET_FILTERING:
+                case CMD_STOP_PACKET_FILTERING:
+                case CMD_START_SCAN:
+                case CMD_DISCONNECT:
+                case CMD_REASSOCIATE:
+                case CMD_RECONNECT:
+                    deferMessage(message);
+                    break;
+                default:
+                    return NOT_HANDLED;
+            }
+            return HANDLED;
         }
     }
 
@@ -3030,6 +3112,15 @@
                         transitionTo(mDisconnectedState);
                     }
                     break;
+                case WifiP2pService.DISCONNECT_WIFI_REQUEST:
+                    if (message.arg1 == 1) {
+                        mWifiNative.disconnect();
+                        mTemporarilyDisconnectWifi = true;
+                    } else {
+                        mWifiNative.reconnect();
+                        mTemporarilyDisconnectWifi = false;
+                    }
+                    break;
                     /* Do a redundant disconnect without transition */
                 case CMD_DISCONNECT:
                     mWifiNative.disconnect();
@@ -3159,6 +3250,13 @@
                     mWifiNative.disconnect();
                     transitionTo(mDisconnectingState);
                     break;
+                case WifiP2pService.DISCONNECT_WIFI_REQUEST:
+                    if (message.arg1 == 1) {
+                        mWifiNative.disconnect();
+                        mTemporarilyDisconnectWifi = true;
+                        transitionTo(mDisconnectingState);
+                    }
+                    break;
                 case CMD_SET_SCAN_MODE:
                     if (message.arg1 == SCAN_ONLY_MODE) {
                         sendMessage(CMD_DISCONNECT);
@@ -3465,6 +3563,13 @@
             if (DBG) log(getName() + "\n");
             EventLog.writeEvent(EVENTLOG_WIFI_STATE_CHANGED, getName());
 
+            // We dont scan frequently if this is a temporary disconnect
+            // due to p2p
+            if (mTemporarilyDisconnectWifi) {
+                mWifiP2pChannel.sendMessage(WifiP2pService.DISCONNECT_WIFI_RESPONSE);
+                return;
+            }
+
             mFrameworkScanIntervalMs = Settings.Global.getLong(mContext.getContentResolver(),
                     Settings.Global.WIFI_FRAMEWORK_SCAN_INTERVAL_MS,
                     mDefaultFrameworkScanIntervalMs);
@@ -3579,6 +3684,12 @@
                         sendMessageDelayed(obtainMessage(CMD_NO_NETWORKS_PERIODIC_SCAN,
                                     ++mPeriodicScanToken, 0), mSupplicantScanIntervalMs);
                     }
+                case CMD_RECONNECT:
+                case CMD_REASSOCIATE:
+                    // Drop a third party reconnect/reassociate if we are
+                    // tempoarily disconnected for p2p
+                    if (mTemporarilyDisconnectWifi) ret = NOT_HANDLED;
+                    break;
                 default:
                     ret = NOT_HANDLED;
             }
diff --git a/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java b/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
index 9c727f9..c8f0712 100644
--- a/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiWatchdogStateMachine.java
@@ -556,8 +556,8 @@
                             mLinkProperties = (LinkProperties) intent.getParcelableExtra(
                                     WifiManager.EXTRA_LINK_PROPERTIES);
                             if (mPoorNetworkDetectionEnabled) {
-                                if (mWifiInfo == null) {
-                                    if (DBG) logd("Ignoring link verification, mWifiInfo is NULL");
+                                if (mWifiInfo == null || mCurrentBssid == null) {
+                                    loge("Ignore, wifiinfo " + mWifiInfo +" bssid " + mCurrentBssid);
                                     sendLinkStatusNotification(true);
                                 } else {
                                     transitionTo(mVerifyingLinkState);
@@ -726,7 +726,7 @@
         }
 
         private void handleRssiChange() {
-            if (mCurrentSignalLevel <= LINK_MONITOR_LEVEL_THRESHOLD) {
+            if (mCurrentSignalLevel <= LINK_MONITOR_LEVEL_THRESHOLD && mCurrentBssid != null) {
                 transitionTo(mLinkMonitoringState);
             } else {
                 // stay here
@@ -920,11 +920,15 @@
         if (DBG) logd("########################################");
         if (isGood) {
             mWsmChannel.sendMessage(GOOD_LINK_DETECTED);
-            mCurrentBssid.mLastTimeGood = SystemClock.elapsedRealtime();
-            logd("Good link notification is sent");
+            if (mCurrentBssid != null) {
+                mCurrentBssid.mLastTimeGood = SystemClock.elapsedRealtime();
+            }
+            if (DBG) logd("Good link notification is sent");
         } else {
             mWsmChannel.sendMessage(POOR_LINK_DETECTED);
-            mCurrentBssid.mLastTimePoor = SystemClock.elapsedRealtime();
+            if (mCurrentBssid != null) {
+                mCurrentBssid.mLastTimePoor = SystemClock.elapsedRealtime();
+            }
             logd("Poor link notification is sent");
         }
     }
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pService.java b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
index 70baf13..ba8ffec 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pService.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
@@ -30,6 +30,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.PackageManager;
+import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.net.IConnectivityManager;
 import android.net.ConnectivityManager;
@@ -68,6 +69,7 @@
 import android.text.TextUtils;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -134,6 +136,9 @@
     private static final int GROUP_CREATING_WAIT_TIME_MS = 120 * 1000;
     private static int mGroupCreatingTimeoutIndex = 0;
 
+    private static final int DISABLE_P2P_WAIT_TIME_MS = 5 * 1000;
+    private static int mDisableP2pTimeoutIndex = 0;
+
     /* Set a two minute discover timeout to avoid STA scans from being blocked */
     private static final int DISCOVER_TIMEOUT_S = 120;
 
@@ -149,9 +154,30 @@
     private static final int PEER_CONNECTION_USER_ACCEPT    =   BASE + 2;
     /* User rejected a peer request */
     private static final int PEER_CONNECTION_USER_REJECT    =   BASE + 3;
+    /* User wants to disconnect wifi in favour of p2p */
+    private static final int DROP_WIFI_USER_ACCEPT          =   BASE + 4;
+    /* User wants to keep his wifi connection and drop p2p */
+    private static final int DROP_WIFI_USER_REJECT          =   BASE + 5;
+    /* Delayed message to timeout p2p disable */
+    public static final int DISABLE_P2P_TIMED_OUT           =   BASE + 6;
+
 
     /* Commands to the WifiStateMachine */
-    public static final int P2P_CONNECTION_CHANGED         =   BASE + 11;
+    public static final int P2P_CONNECTION_CHANGED          =   BASE + 11;
+
+    /* These commands are used to tempoarily disconnect wifi when we detect
+     * a frequency conflict which would make it impossible to have with p2p
+     * and wifi active at the same time.
+     *
+     * If the user chooses to disable wifi tempoarily, we keep wifi disconnected
+     * until the p2p connection is done and terminated at which point we will
+     * bring back wifi up
+     *
+     * DISCONNECT_WIFI_REQUEST
+     *      msg.arg1 = 1 enables temporary disconnect and 0 disables it.
+     */
+    public static final int DISCONNECT_WIFI_REQUEST         =   BASE + 12;
+    public static final int DISCONNECT_WIFI_RESPONSE        =   BASE + 13;
 
     private final boolean mP2pSupported;
 
@@ -172,6 +198,8 @@
 
     private NetworkInfo mNetworkInfo;
 
+    private boolean mTempoarilyDisconnectedWifi = false;
+
     /* The transaction Id of service discovery request */
     private byte mServiceTransactionId = 0;
 
@@ -222,7 +250,7 @@
         PREVIOUS_PROTOCOL_ERROR,
 
         /* There is no common channels the both devices can use. */
-        NO_COMMON_CHANNE,
+        NO_COMMON_CHANNEL,
 
         /* Unknown p2p group. For example, Device A tries to invoke the previous persistent group,
          *  but device B has removed the specified credential already. */
@@ -257,7 +285,7 @@
             case 6:
                 return PREVIOUS_PROTOCOL_ERROR;
             case 7:
-                return NO_COMMON_CHANNE;
+                return NO_COMMON_CHANNEL;
             case 8:
                 return UNKNOWN_P2P_GROUP;
             case 9:
@@ -346,6 +374,7 @@
                 = new UserAuthorizingInvitationState();
         private ProvisionDiscoveryState mProvisionDiscoveryState = new ProvisionDiscoveryState();
         private GroupNegotiationState mGroupNegotiationState = new GroupNegotiationState();
+        private FrequencyConflictState mFrequencyConflictState =new FrequencyConflictState();
 
         private GroupCreatedState mGroupCreatedState = new GroupCreatedState();
         private UserAuthorizingJoinState mUserAuthorizingJoinState = new UserAuthorizingJoinState();
@@ -400,6 +429,7 @@
                         addState(mUserAuthorizingInvitationState, mGroupCreatingState);
                         addState(mProvisionDiscoveryState, mGroupCreatingState);
                         addState(mGroupNegotiationState, mGroupCreatingState);
+                        addState(mFrequencyConflictState, mGroupCreatingState);
                     addState(mGroupCreatedState, mP2pEnabledState);
                         addState(mUserAuthorizingJoinState, mGroupCreatedState);
                         addState(mOngoingGroupRemovalState, mGroupCreatedState);
@@ -551,16 +581,25 @@
                 case WifiMonitor.P2P_DEVICE_LOST_EVENT:
                 case WifiMonitor.P2P_FIND_STOPPED_EVENT:
                 case WifiMonitor.P2P_SERV_DISC_RESP_EVENT:
-                case WifiStateMachine.CMD_ENABLE_P2P:
-                case WifiStateMachine.CMD_DISABLE_P2P:
                 case PEER_CONNECTION_USER_ACCEPT:
                 case PEER_CONNECTION_USER_REJECT:
+                case DISCONNECT_WIFI_RESPONSE:
+                case DROP_WIFI_USER_ACCEPT:
+                case DROP_WIFI_USER_REJECT:
                 case GROUP_CREATING_TIMED_OUT:
+                case DISABLE_P2P_TIMED_OUT:
                 case DhcpStateMachine.CMD_PRE_DHCP_ACTION:
                 case DhcpStateMachine.CMD_POST_DHCP_ACTION:
                 case DhcpStateMachine.CMD_ON_QUIT:
                 case WifiMonitor.P2P_PROV_DISC_FAILURE_EVENT:
                     break;
+                case WifiStateMachine.CMD_ENABLE_P2P:
+                    // Enable is lazy and has no response
+                    break;
+                case WifiStateMachine.CMD_DISABLE_P2P_REQ:
+                    // If we end up handling in default, p2p is not enabled
+                    mWifiChannel.sendMessage(WifiStateMachine.CMD_DISABLE_P2P_RSP);
+                    break;
                     /* unexpected group created, remove */
                 case WifiMonitor.P2P_GROUP_STARTED_EVENT:
                     mGroup = (WifiP2pGroup) message.obj;
@@ -663,6 +702,13 @@
 
     class P2pDisablingState extends State {
         @Override
+        public void enter() {
+            if (DBG) logd(getName());
+            sendMessageDelayed(obtainMessage(DISABLE_P2P_TIMED_OUT,
+                    ++mDisableP2pTimeoutIndex, 0), DISABLE_P2P_WAIT_TIME_MS);
+        }
+
+        @Override
         public boolean processMessage(Message message) {
             if (DBG) logd(getName() + message.toString());
             switch (message.what) {
@@ -671,14 +717,25 @@
                     transitionTo(mP2pDisabledState);
                     break;
                 case WifiStateMachine.CMD_ENABLE_P2P:
-                case WifiStateMachine.CMD_DISABLE_P2P:
+                case WifiStateMachine.CMD_DISABLE_P2P_REQ:
                     deferMessage(message);
                     break;
+                case DISABLE_P2P_TIMED_OUT:
+                    if (mGroupCreatingTimeoutIndex == message.arg1) {
+                        loge("P2p disable timed out");
+                        transitionTo(mP2pDisabledState);
+                    }
+                    break;
                 default:
                     return NOT_HANDLED;
             }
             return HANDLED;
         }
+
+        @Override
+        public void exit() {
+            mWifiChannel.sendMessage(WifiStateMachine.CMD_DISABLE_P2P_RSP);
+        }
     }
 
     class P2pDisabledState extends State {
@@ -702,9 +759,6 @@
                     mWifiMonitor.startMonitoring();
                     transitionTo(mP2pEnablingState);
                     break;
-                case WifiStateMachine.CMD_DISABLE_P2P:
-                    //Nothing to do
-                    break;
                 default:
                     return NOT_HANDLED;
             }
@@ -731,7 +785,7 @@
                     transitionTo(mP2pDisabledState);
                     break;
                 case WifiStateMachine.CMD_ENABLE_P2P:
-                case WifiStateMachine.CMD_DISABLE_P2P:
+                case WifiStateMachine.CMD_DISABLE_P2P_REQ:
                     deferMessage(message);
                     break;
                 default:
@@ -762,7 +816,7 @@
                 case WifiStateMachine.CMD_ENABLE_P2P:
                     //Nothing to do
                     break;
-                case WifiStateMachine.CMD_DISABLE_P2P:
+                case WifiStateMachine.CMD_DISABLE_P2P_REQ:
                     if (mPeers.clear()) sendP2pPeersChangedBroadcast();
                     if (mGroups.clear()) sendP2pPersistentGroupsChangedBroadcast();
 
@@ -1027,20 +1081,7 @@
                        // remain at this state.
                    }
                    break;
-                case WifiMonitor.P2P_GROUP_STARTED_EVENT:
-                    mGroup = (WifiP2pGroup) message.obj;
-                    if (DBG) logd(getName() + " group started");
-
-                    if (mGroup.getNetworkId() == WifiP2pGroup.PERSISTENT_NET_ID) {
-                        // This is an invocation case.
-                        mAutonomousGroup = false;
-                        deferMessage(message);
-                        transitionTo(mGroupNegotiationState);
-                    } else {
-                        return NOT_HANDLED;
-                    }
-                    break;
-               default:
+              default:
                    return NOT_HANDLED;
             }
             return HANDLED;
@@ -1074,6 +1115,10 @@
                     // mSavedPeerConfig can be empty
                     if (mSavedPeerConfig != null &&
                             !mSavedPeerConfig.deviceAddress.equals(device.deviceAddress)) {
+                        if (DBG) {
+                            logd("mSavedPeerConfig " + mSavedPeerConfig.deviceAddress +
+                                "device " + device.deviceAddress);
+                        }
                         // Do the regular device lost handling
                         ret = NOT_HANDLED;
                         break;
@@ -1269,6 +1314,12 @@
                     transitionTo(mGroupCreatedState);
                     break;
                 case WifiMonitor.P2P_GO_NEGOTIATION_FAILURE_EVENT:
+                    P2pStatus status = (P2pStatus) message.obj;
+                    if (status == P2pStatus.NO_COMMON_CHANNEL) {
+                        transitionTo(mFrequencyConflictState);
+                        break;
+                    }
+                    /* continue with group removal handling */
                 case WifiMonitor.P2P_GROUP_REMOVED_EVENT:
                     if (DBG) logd(getName() + " go failure");
                     handleGroupCreationFailure();
@@ -1278,9 +1329,14 @@
                 // a group removed event. Flushing things at group formation
                 // failure causes supplicant issues. Ignore right now.
                 case WifiMonitor.P2P_GROUP_FORMATION_FAILURE_EVENT:
+                    status = (P2pStatus) message.obj;
+                    if (status == P2pStatus.NO_COMMON_CHANNEL) {
+                        transitionTo(mFrequencyConflictState);
+                        break;
+                    }
                     break;
                 case WifiMonitor.P2P_INVITATION_RESULT_EVENT:
-                    P2pStatus status = (P2pStatus)message.obj;
+                    status = (P2pStatus)message.obj;
                     if (status == P2pStatus.SUCCESS) {
                         // invocation was succeeded.
                         // wait P2P_GROUP_STARTED_EVENT.
@@ -1300,6 +1356,8 @@
                             handleGroupCreationFailure();
                             transitionTo(mInactiveState);
                         }
+                    } else if (status == P2pStatus.NO_COMMON_CHANNEL) {
+                        transitionTo(mFrequencyConflictState);
                     } else {
                         handleGroupCreationFailure();
                         transitionTo(mInactiveState);
@@ -1312,7 +1370,90 @@
         }
     }
 
+    class FrequencyConflictState extends State {
+        private AlertDialog mFrequencyConflictDialog;
+        @Override
+        public void enter() {
+            if (DBG) logd(getName());
+            notifyFrequencyConflict();
+        }
 
+        private void notifyFrequencyConflict() {
+            logd("Notify frequency conflict");
+            Resources r = Resources.getSystem();
+
+            AlertDialog dialog = new AlertDialog.Builder(mContext)
+                .setMessage(r.getString(R.string.wifi_p2p_frequency_conflict_message,
+                        getDeviceName(mSavedPeerConfig.deviceAddress)))
+                .setPositiveButton(r.getString(R.string.dlg_ok), new OnClickListener() {
+                        @Override
+                        public void onClick(DialogInterface dialog, int which) {
+                            sendMessage(DROP_WIFI_USER_ACCEPT);
+                        }
+                    })
+                .setNegativeButton(r.getString(R.string.decline), new OnClickListener() {
+                        @Override
+                        public void onClick(DialogInterface dialog, int which) {
+                            sendMessage(DROP_WIFI_USER_REJECT);
+                        }
+                    })
+                .setOnCancelListener(new DialogInterface.OnCancelListener() {
+                        @Override
+                        public void onCancel(DialogInterface arg0) {
+                            sendMessage(DROP_WIFI_USER_REJECT);
+                        }
+                    })
+                .create();
+
+            dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
+            dialog.show();
+            mFrequencyConflictDialog = dialog;
+        }
+
+        @Override
+        public boolean processMessage(Message message) {
+            if (DBG) logd(getName() + message.toString());
+            switch (message.what) {
+                case WifiMonitor.P2P_GO_NEGOTIATION_SUCCESS_EVENT:
+                case WifiMonitor.P2P_GROUP_FORMATION_SUCCESS_EVENT:
+                    loge(getName() + "group sucess during freq conflict!");
+                    break;
+                case WifiMonitor.P2P_GROUP_STARTED_EVENT:
+                    loge(getName() + "group started after freq conflict, handle anyway");
+                    deferMessage(message);
+                    transitionTo(mGroupNegotiationState);
+                    break;
+                case WifiMonitor.P2P_GO_NEGOTIATION_FAILURE_EVENT:
+                case WifiMonitor.P2P_GROUP_REMOVED_EVENT:
+                case WifiMonitor.P2P_GROUP_FORMATION_FAILURE_EVENT:
+                    // Ignore failures since we retry again
+                    break;
+                case DROP_WIFI_USER_REJECT:
+                    // User rejected dropping wifi in favour of p2p
+                    handleGroupCreationFailure();
+                    transitionTo(mInactiveState);
+                    break;
+                case DROP_WIFI_USER_ACCEPT:
+                    // User accepted dropping wifi in favour of p2p
+                    mWifiChannel.sendMessage(WifiP2pService.DISCONNECT_WIFI_REQUEST, 1);
+                    mTempoarilyDisconnectedWifi = true;
+                    break;
+                case DISCONNECT_WIFI_RESPONSE:
+                    // Got a response from wifistatemachine, retry p2p
+                    if (DBG) logd(getName() + "Wifi disconnected, retry p2p");
+                    transitionTo(mInactiveState);
+                    sendMessage(WifiP2pManager.CONNECT, mSavedPeerConfig);
+                    break;
+                default:
+                    return NOT_HANDLED;
+            }
+            return HANDLED;
+        }
+
+        public void exit() {
+            if (mFrequencyConflictDialog != null) mFrequencyConflictDialog.dismiss();
+        }
+    }
 
     class GroupCreatedState extends State {
         @Override
@@ -1326,6 +1467,12 @@
             if (mGroup.isGroupOwner()) {
                 setWifiP2pInfoOnGroupFormation(SERVER_ADDRESS);
             }
+
+            // In case of a negotiation group, connection changed is sent
+            // after a client joins. For autonomous, send now
+            if (mAutonomousGroup) {
+                sendP2pConnectionChangedBroadcast();
+            }
         }
 
         @Override
@@ -1340,7 +1487,11 @@
                                 deviceAddress.equals(mSavedProvDiscDevice.deviceAddress)) {
                             mSavedProvDiscDevice = null;
                         }
-                        mGroup.addClient(mPeers.get(deviceAddress));
+                        if (mPeers.get(deviceAddress) != null) {
+                            mGroup.addClient(mPeers.get(deviceAddress));
+                        } else {
+                            mGroup.addClient(deviceAddress);
+                        }
                         mPeers.updateStatus(deviceAddress, WifiP2pDevice.CONNECTED);
                         if (DBG) logd(getName() + " ap sta connected");
                         sendP2pPeersChangedBroadcast();
@@ -1421,7 +1572,7 @@
                     }
                     // Do the regular device lost handling
                     return NOT_HANDLED;
-                case WifiStateMachine.CMD_DISABLE_P2P:
+                case WifiStateMachine.CMD_DISABLE_P2P_REQ:
                     sendMessage(WifiP2pManager.REMOVE_GROUP);
                     deferMessage(message);
                     break;
@@ -1778,6 +1929,26 @@
                 break;
         }
 
+        if ((r.getConfiguration().uiMode & Configuration.UI_MODE_TYPE_APPLIANCE) ==
+                Configuration.UI_MODE_TYPE_APPLIANCE) {
+            // For appliance devices, add a key listener which accepts.
+            dialog.setOnKeyListener(new DialogInterface.OnKeyListener() {
+
+                @Override
+                public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
+                    // TODO: make the actual key come from a config value.
+                    if (keyCode == KeyEvent.KEYCODE_VOLUME_MUTE) {
+                        sendMessage(PEER_CONNECTION_USER_ACCEPT);
+                        dialog.dismiss();
+                        return true;
+                    }
+                    return false;
+                }
+            });
+            // TODO: add timeout for this dialog.
+            // TODO: update UI in appliance mode to tell user what to do.
+        }
+
         dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
         dialog.show();
     }
@@ -2195,6 +2366,11 @@
         mPeersLostDuringConnection.clear();
         mServiceDiscReqId = null;
         if (changed) sendP2pPeersChangedBroadcast();
+
+        if (mTempoarilyDisconnectedWifi) {
+            mWifiChannel.sendMessage(WifiP2pService.DISCONNECT_WIFI_REQUEST, 0);
+            mTempoarilyDisconnectedWifi = false;
+        }
     }
 
     //State machine initiated requests can have replyTo set to null indicating