Merge "Show brightness dialog for all users." into jb-mr1-dev
diff --git a/api/current.txt b/api/current.txt
index d7f4e11..5462aee 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();
@@ -16151,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();
diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c
index a276225..8e4d7ed 100644
--- a/cmds/installd/commands.c
+++ b/cmds/installd/commands.c
@@ -36,6 +36,7 @@
     char pkgdir[PKG_PATH_MAX];
     char libsymlink[PKG_PATH_MAX];
     char applibdir[PKG_PATH_MAX];
+    struct stat libStat;
 
     if ((uid < AID_SYSTEM) || (gid < AID_SYSTEM)) {
         ALOGE("invalid uid/gid: %d %d\n", uid, gid);
@@ -67,6 +68,25 @@
         return -1;
     }
 
+    if (lstat(libsymlink, &libStat) < 0) {
+        if (errno != ENOENT) {
+            ALOGE("couldn't stat lib dir: %s\n", strerror(errno));
+            return -1;
+        }
+    } else {
+        if (S_ISDIR(libStat.st_mode)) {
+            if (delete_dir_contents(libsymlink, 1, 0) < 0) {
+                ALOGE("couldn't delete lib directory during install for: %s", libsymlink);
+                return -1;
+            }
+        } else if (S_ISLNK(libStat.st_mode)) {
+            if (unlink(libsymlink) < 0) {
+                ALOGE("couldn't unlink lib directory during install for: %s", libsymlink);
+                return -1;
+            }
+        }
+    }
+
     if (symlink(applibdir, libsymlink) < 0) {
         ALOGE("couldn't symlink directory '%s' -> '%s': %s\n", libsymlink, applibdir,
                 strerror(errno));
@@ -140,7 +160,7 @@
     if (stat(pkgdir, &s) < 0) return -1;
 
     if (s.st_uid != 0 || s.st_gid != 0) {
-        ALOGE("fixing uid of non-root pkg: %s %d %d\n", pkgdir, s.st_uid, s.st_gid);
+        ALOGE("fixing uid of non-root pkg: %s %lu %lu\n", pkgdir, s.st_uid, s.st_gid);
         return -1;
     }
 
@@ -165,18 +185,30 @@
     if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, persona))
         return -1;
 
-    /* delete contents, excluding "lib", but not the directory itself */
-    return delete_dir_contents(pkgdir, 0, "lib");
+    /* delete contents AND directory, no exceptions */
+    return delete_dir_contents(pkgdir, 1, NULL);
 }
 
 int make_user_data(const char *pkgname, uid_t uid, uid_t persona)
 {
     char pkgdir[PKG_PATH_MAX];
+    char applibdir[PKG_PATH_MAX];
+    char libsymlink[PKG_PATH_MAX];
+    struct stat libStat;
 
     // Create the data dir for the package
     if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, persona)) {
         return -1;
     }
+    if (create_pkg_path(libsymlink, pkgname, PKG_LIB_POSTFIX, persona)) {
+        ALOGE("cannot create package lib symlink origin path\n");
+        return -1;
+    }
+    if (create_pkg_path_in_dir(applibdir, &android_app_lib_dir, pkgname, PKG_DIR_POSTFIX)) {
+        ALOGE("cannot create package lib symlink dest path\n");
+        return -1;
+    }
+
     if (mkdir(pkgdir, 0751) < 0) {
         ALOGE("cannot create dir '%s': %s\n", pkgdir, strerror(errno));
         return -errno;
@@ -186,8 +218,41 @@
         unlink(pkgdir);
         return -errno;
     }
+
+    if (lstat(libsymlink, &libStat) < 0) {
+        if (errno != ENOENT) {
+            ALOGE("couldn't stat lib dir for non-primary: %s\n", strerror(errno));
+            unlink(pkgdir);
+            return -1;
+        }
+    } else {
+        if (S_ISDIR(libStat.st_mode)) {
+            if (delete_dir_contents(libsymlink, 1, 0) < 0) {
+                ALOGE("couldn't delete lib directory during install for non-primary: %s",
+                        libsymlink);
+                unlink(pkgdir);
+                return -1;
+            }
+        } else if (S_ISLNK(libStat.st_mode)) {
+            if (unlink(libsymlink) < 0) {
+                ALOGE("couldn't unlink lib directory during install for non-primary: %s",
+                        libsymlink);
+                unlink(pkgdir);
+                return -1;
+            }
+        }
+    }
+
+    if (symlink(applibdir, libsymlink) < 0) {
+        ALOGE("couldn't symlink directory for non-primary '%s' -> '%s': %s\n", libsymlink,
+                applibdir, strerror(errno));
+        unlink(pkgdir);
+        return -1;
+    }
+
     if (chown(pkgdir, uid, uid) < 0) {
         ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno));
+        unlink(libsymlink);
         unlink(pkgdir);
         return -errno;
     }
@@ -195,6 +260,7 @@
 #ifdef HAVE_SELINUX
     if (selinux_android_setfilecon(pkgdir, pkgname, uid) < 0) {
         ALOGE("cannot setfilecon dir '%s': %s\n", pkgdir, strerror(errno));
+        unlink(libsymlink);
         unlink(pkgdir);
         return -errno;
     }
@@ -254,7 +320,7 @@
                 /* Get the file stat */
                 if (stat(pkg_path, &s) < 0) continue;
                 /* Get the uid of the package */
-                ALOGI("Adding datadir for uid = %d\n", s.st_uid);
+                ALOGI("Adding datadir for uid = %lu\n", s.st_uid);
                 uid = (uid_t) s.st_uid % PER_USER_RANGE;
                 /* Create the directory for the target */
                 make_user_data(name, uid + target_persona * PER_USER_RANGE,
@@ -991,75 +1057,71 @@
     return 0;
 }
 
-int linklib(const char* dataDir, const char* asecLibDir)
+int linklib(const char* pkgname, const char* asecLibDir, int userId)
 {
-    char libdir[PKG_PATH_MAX];
+    char pkgdir[PKG_PATH_MAX];
+    char libsymlink[PKG_PATH_MAX];
     struct stat s, libStat;
     int rc = 0;
 
-    const size_t libdirLen = strlen(dataDir) + strlen(PKG_LIB_POSTFIX);
-    if (libdirLen >= PKG_PATH_MAX) {
-        ALOGE("library dir len too large");
+    if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, userId)) {
+        ALOGE("cannot create package path\n");
+        return -1;
+    }
+    if (create_pkg_path(libsymlink, pkgname, PKG_LIB_POSTFIX, userId)) {
+        ALOGE("cannot create package lib symlink origin path\n");
         return -1;
     }
 
-    if (snprintf(libdir, sizeof(libdir), "%s%s", dataDir, PKG_LIB_POSTFIX) != (ssize_t)libdirLen) {
-        ALOGE("library dir not written successfully: %s\n", strerror(errno));
+    if (stat(pkgdir, &s) < 0) return -1;
+
+    if (chown(pkgdir, AID_INSTALL, AID_INSTALL) < 0) {
+        ALOGE("failed to chown '%s': %s\n", pkgdir, strerror(errno));
         return -1;
     }
 
-    if (stat(dataDir, &s) < 0) return -1;
-
-    if (chown(dataDir, AID_INSTALL, AID_INSTALL) < 0) {
-        ALOGE("failed to chown '%s': %s\n", dataDir, strerror(errno));
-        return -1;
-    }
-
-    if (chmod(dataDir, 0700) < 0) {
-        ALOGE("linklib() 1: failed to chmod '%s': %s\n", dataDir, strerror(errno));
+    if (chmod(pkgdir, 0700) < 0) {
+        ALOGE("linklib() 1: failed to chmod '%s': %s\n", pkgdir, strerror(errno));
         rc = -1;
         goto out;
     }
 
-    if (lstat(libdir, &libStat) < 0) {
-        ALOGE("couldn't stat lib dir: %s\n", strerror(errno));
-        rc = -1;
-        goto out;
-    }
-
-    if (S_ISDIR(libStat.st_mode)) {
-        if (delete_dir_contents(libdir, 1, 0) < 0) {
+    if (lstat(libsymlink, &libStat) < 0) {
+        if (errno != ENOENT) {
+            ALOGE("couldn't stat lib dir: %s\n", strerror(errno));
             rc = -1;
             goto out;
         }
-    } else if (S_ISLNK(libStat.st_mode)) {
-        if (unlink(libdir) < 0) {
-            rc = -1;
-            goto out;
+    } else {
+        if (S_ISDIR(libStat.st_mode)) {
+            if (delete_dir_contents(libsymlink, 1, 0) < 0) {
+                rc = -1;
+                goto out;
+            }
+        } else if (S_ISLNK(libStat.st_mode)) {
+            if (unlink(libsymlink) < 0) {
+                ALOGE("couldn't unlink lib dir: %s\n", strerror(errno));
+                rc = -1;
+                goto out;
+            }
         }
     }
 
-    if (symlink(asecLibDir, libdir) < 0) {
-        ALOGE("couldn't symlink directory '%s' -> '%s': %s\n", libdir, asecLibDir, strerror(errno));
-        rc = -errno;
-        goto out;
-    }
-
-    if (lchown(libdir, AID_SYSTEM, AID_SYSTEM) < 0) {
-        ALOGE("cannot chown dir '%s': %s\n", libdir, strerror(errno));
-        unlink(libdir);
+    if (symlink(asecLibDir, libsymlink) < 0) {
+        ALOGE("couldn't symlink directory '%s' -> '%s': %s\n", libsymlink, asecLibDir,
+                strerror(errno));
         rc = -errno;
         goto out;
     }
 
 out:
-    if (chmod(dataDir, s.st_mode) < 0) {
-        ALOGE("linklib() 2: failed to chmod '%s': %s\n", dataDir, strerror(errno));
+    if (chmod(pkgdir, s.st_mode) < 0) {
+        ALOGE("linklib() 2: failed to chmod '%s': %s\n", pkgdir, strerror(errno));
         rc = -errno;
     }
 
-    if (chown(dataDir, s.st_uid, s.st_gid) < 0) {
-        ALOGE("failed to chown '%s' : %s\n", dataDir, strerror(errno));
+    if (chown(pkgdir, s.st_uid, s.st_gid) < 0) {
+        ALOGE("failed to chown '%s' : %s\n", pkgdir, strerror(errno));
         return -errno;
     }
 
diff --git a/cmds/installd/installd.c b/cmds/installd/installd.c
index 19298a3..21d674a 100644
--- a/cmds/installd/installd.c
+++ b/cmds/installd/installd.c
@@ -123,7 +123,7 @@
 
 static int do_linklib(char **arg, char reply[REPLY_MAX])
 {
-    return linklib(arg[0], arg[1]);
+    return linklib(arg[0], arg[1], atoi(arg[2]));
 }
 
 struct cmdinfo {
@@ -146,7 +146,7 @@
     { "getsize",              5, do_get_size },
     { "rmuserdata",           2, do_rm_user_data },
     { "movefiles",            0, do_movefiles },
-    { "linklib",              2, do_linklib },
+    { "linklib",              3, do_linklib },
     { "mkuserdata",           3, do_mk_user_data },
     { "rmuser",               1, do_rm_user },
     { "cloneuserdata",        3, do_clone_user_data },
diff --git a/cmds/installd/installd.h b/cmds/installd/installd.h
index 2540dbe..0500c23 100644
--- a/cmds/installd/installd.h
+++ b/cmds/installd/installd.h
@@ -188,6 +188,7 @@
 char *build_string3(char *s1, char *s2, char *s3);
 
 int ensure_dir(const char* path, mode_t mode, uid_t uid, gid_t gid);
+int ensure_media_user_dirs(userid_t userid);
 
 /* commands.c */
 
@@ -209,4 +210,4 @@
 int free_cache(int64_t free_size);
 int dexopt(const char *apk_path, uid_t uid, int is_public);
 int movefiles();
-int linklib(const char* target, const char* source);
+int linklib(const char* target, const char* source, int userId);
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/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index 3d656c7..829b80c 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -45,6 +45,7 @@
     public static final int DISABLE_RECENT = View.STATUS_BAR_DISABLE_RECENT;
     public static final int DISABLE_BACK = View.STATUS_BAR_DISABLE_BACK;
     public static final int DISABLE_CLOCK = View.STATUS_BAR_DISABLE_CLOCK;
+    public static final int DISABLE_SEARCH = View.STATUS_BAR_DISABLE_SEARCH;
 
     @Deprecated
     public static final int DISABLE_NAVIGATION = 
@@ -54,7 +55,8 @@
 
     public static final int DISABLE_MASK = DISABLE_EXPAND | DISABLE_NOTIFICATION_ICONS
             | DISABLE_NOTIFICATION_ALERTS | DISABLE_NOTIFICATION_TICKER
-            | DISABLE_SYSTEM_INFO | DISABLE_RECENT | DISABLE_HOME | DISABLE_BACK | DISABLE_CLOCK;
+            | DISABLE_SYSTEM_INFO | DISABLE_RECENT | DISABLE_HOME | DISABLE_BACK | DISABLE_CLOCK
+            | DISABLE_SEARCH;
 
     public static final int NAVIGATION_HINT_BACK_NOP      = 1 << 0;
     public static final int NAVIGATION_HINT_HOME_NOP      = 1 << 1;
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 97d299a..cf0603e 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -2430,7 +2430,8 @@
     /**
      * Broadcast sent to the system when a user is removed. Carries an extra EXTRA_USER_HANDLE that has
      * the userHandle of the user.  It is sent to all running users except the
-     * one that has been removed.  You must hold
+     * one that has been removed. The user will not be completely removed until all receivers have
+     * handled the broadcast. You must hold
      * {@link android.Manifest.permission#MANAGE_USERS} to receive this broadcast.
      * @hide
      */
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 58df167..05bab9c 100644
--- a/core/java/android/content/SyncManager.java
+++ b/core/java/android/content/SyncManager.java
@@ -55,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;
@@ -264,7 +265,9 @@
     }
 
     private void doDatabaseCleanup() {
-        for (UserInfo user : mUserManager.getUsers()) {
+        for (UserInfo user : mUserManager.getUsers(true)) {
+            // Skip any partially created/removed users
+            if (user.partial) continue;
             Account[] accountsForUser = AccountManagerService.getSingleton().getAccounts(user.id);
             mSyncStorageEngine.doDatabaseCleanup(accountsForUser, user.id);
         }
@@ -311,13 +314,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);
             }
         }
@@ -338,6 +338,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.
@@ -441,9 +445,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
diff --git a/core/java/android/content/SyncQueue.java b/core/java/android/content/SyncQueue.java
index 14bfc5b..c9a325e 100644
--- a/core/java/android/content/SyncQueue.java
+++ b/core/java/android/content/SyncQueue.java
@@ -51,8 +51,6 @@
     public SyncQueue(SyncStorageEngine syncStorageEngine, final SyncAdaptersCache syncAdapters) {
         mSyncStorageEngine = syncStorageEngine;
         mSyncAdapters = syncAdapters;
-
-        addPendingOperations(UserHandle.USER_OWNER);
     }
 
     public void addPendingOperations(int userId) {
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/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 b4ba871..6360242b 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2452,6 +2452,17 @@
 
     /**
      * @hide
+     *
+     * NOTE: This flag may only be used in subtreeSystemUiVisibility. It is masked
+     * out of the public fields to keep the undefined bits out of the developer's way.
+     *
+     * Flag to disable the global search gesture. Don't use this
+     * unless you're a special part of the system UI (i.e., setup wizard, keyguard).
+     */
+    public static final int STATUS_BAR_DISABLE_SEARCH = 0x02000000;
+
+    /**
+     * @hide
      */
     public static final int PUBLIC_STATUS_BAR_VISIBILITY_MASK = 0x0000FFFF;
 
@@ -10002,8 +10013,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 b95e1bd..c252c77 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -5362,6 +5362,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();
@@ -5611,19 +5624,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");
         }
 
         /**
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 7ce3042..8a82a54 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -317,6 +317,8 @@
     private final int mDensity;
     private final int mNoncompatDensity;
 
+    private int mViewLayoutDirectionInitial;
+
     /**
      * Consistency verifier for debugging purposes.
      */
@@ -465,6 +467,7 @@
         synchronized (this) {
             if (mView == null) {
                 mView = view;
+                mViewLayoutDirectionInitial = mView.getRawLayoutDirection();
                 mFallbackEventHandler.setView(view);
                 mWindowAttributes.copyFrom(attrs);
                 attrs = mWindowAttributes;
@@ -887,11 +890,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;
@@ -1184,7 +1189,10 @@
             viewVisibilityChanged = false;
             mLastConfiguration.setTo(host.getResources().getConfiguration());
             mLastSystemUiVisibility = mAttachInfo.mSystemUiVisibility;
-            host.setLayoutDirection(mLastConfiguration.getLayoutDirection());
+            // 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);
@@ -2680,7 +2688,8 @@
                 final int lastLayoutDirection = mLastConfiguration.getLayoutDirection();
                 final int currentLayoutDirection = config.getLayoutDirection();
                 mLastConfiguration.setTo(config);
-                if (lastLayoutDirection != currentLayoutDirection) {
+                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/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/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 113299a..399b4fa 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 3f8f9dae..68ffd73 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/com/android/internal/app/IMediaContainerService.aidl b/core/java/com/android/internal/app/IMediaContainerService.aidl
index c82834f7..03d3b22 100755
--- a/core/java/com/android/internal/app/IMediaContainerService.aidl
+++ b/core/java/com/android/internal/app/IMediaContainerService.aidl
@@ -36,4 +36,5 @@
     /** Return file system stats: [0] is total bytes, [1] is available bytes */
     long[] getFileSystemStats(in String path);
     void clearDirectory(in String directory);
+    long calculateInstalledSize(in String packagePath, boolean isForwardLocked);
 }
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_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/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/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 e76b67b..8ef91df 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/apks/install_bad_dex/AndroidManifest.xml b/core/tests/coretests/apks/install_bad_dex/AndroidManifest.xml
index fe4dd8e..76f0fe5 100644
--- a/core/tests/coretests/apks/install_bad_dex/AndroidManifest.xml
+++ b/core/tests/coretests/apks/install_bad_dex/AndroidManifest.xml
@@ -14,7 +14,7 @@
      limitations under the License.
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
-        package="com.android.frameworks.coretests.install_loc">
+        package="com.android.frameworks.coretests.install_bad_dex">
 
     <application android:hasCode="true">
         <activity
diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
index 56070ee..04f8009 100755
--- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
+++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
@@ -981,19 +981,22 @@
         try {
             DeleteObserver observer = new DeleteObserver(pkgName);
 
-            getPm().deletePackage(pkgName, observer, flags);
+            getPm().deletePackage(pkgName, observer, flags | PackageManager.DELETE_ALL_USERS);
             observer.waitForCompletion(MAX_WAIT_TIME);
 
             assertUninstalled(info);
 
             // Verify we received the broadcast
-            long waitTime = 0;
-            while ((!receiver.isDone()) && (waitTime < MAX_WAIT_TIME)) {
-                receiver.wait(WAIT_TIME_INCR);
-                waitTime += WAIT_TIME_INCR;
-            }
-            if (!receiver.isDone()) {
-                throw new Exception("Timed out waiting for PACKAGE_REMOVED notification");
+            // TODO replace this with a CountDownLatch
+            synchronized (receiver) {
+                long waitTime = 0;
+                while ((!receiver.isDone()) && (waitTime < MAX_WAIT_TIME)) {
+                    receiver.wait(WAIT_TIME_INCR);
+                    waitTime += WAIT_TIME_INCR;
+                }
+                if (!receiver.isDone()) {
+                    throw new Exception("Timed out waiting for PACKAGE_REMOVED notification");
+                }
             }
             return receiver.received;
         } finally {
@@ -1331,7 +1334,7 @@
         }
 
         DeleteObserver observer = new DeleteObserver(packageName);
-        getPm().deletePackage(packageName, observer, 0);
+        getPm().deletePackage(packageName, observer, PackageManager.DELETE_ALL_USERS);
         observer.waitForCompletion(MAX_WAIT_TIME);
 
         try {
@@ -1357,7 +1360,7 @@
 
             if (info != null) {
                 DeleteObserver observer = new DeleteObserver(pkgName);
-                getPm().deletePackage(pkgName, observer, 0);
+                getPm().deletePackage(pkgName, observer, PackageManager.DELETE_ALL_USERS);
                 observer.waitForCompletion(MAX_WAIT_TIME);
                 assertUninstalled(info);
             }
@@ -3126,7 +3129,7 @@
             int rawResId = apk2;
             Uri packageURI = getInstallablePackage(rawResId, outFile);
             PackageParser.Package pkg = parsePackage(packageURI);
-            getPm().deletePackage(pkg.packageName, null, 0);
+            getPm().deletePackage(pkg.packageName, null, PackageManager.DELETE_ALL_USERS);
             // Check signatures now
             int match = mContext.getPackageManager().checkSignatures(
                     ip1.pkg.packageName, pkg.packageName);
@@ -3265,7 +3268,7 @@
             PackageManager pm = mContext.getPackageManager();
             // Delete app2
             PackageParser.Package pkg = getParsedPackage(apk2Name, apk2);
-            getPm().deletePackage(pkg.packageName, null, 0);
+            getPm().deletePackage(pkg.packageName, null, PackageManager.DELETE_ALL_USERS);
             // Check signatures now
             int match = mContext.getPackageManager().checkSignatures(
                     ip1.pkg.packageName, pkg.packageName);
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/data/sounds/effects/ogg/VideoRecord.ogg b/data/sounds/effects/ogg/VideoRecord.ogg
index d2dee03..ca66604 100644
--- a/data/sounds/effects/ogg/VideoRecord.ogg
+++ b/data/sounds/effects/ogg/VideoRecord.ogg
Binary files differ
diff --git a/data/sounds/effects/ogg/VideoRecord_48k.ogg b/data/sounds/effects/ogg/VideoRecord_48k.ogg
new file mode 100644
index 0000000..fd9c760
--- /dev/null
+++ b/data/sounds/effects/ogg/VideoRecord_48k.ogg
Binary files differ
diff --git a/data/sounds/effects/ogg/VideoStop.ogg b/data/sounds/effects/ogg/VideoStop.ogg
index f16ed13..2516710 100644
--- a/data/sounds/effects/ogg/VideoStop.ogg
+++ b/data/sounds/effects/ogg/VideoStop.ogg
Binary files differ
diff --git a/data/sounds/effects/ogg/VideoStop_48k.ogg b/data/sounds/effects/ogg/VideoStop_48k.ogg
new file mode 100644
index 0000000..7c40021
--- /dev/null
+++ b/data/sounds/effects/ogg/VideoStop_48k.ogg
Binary files differ
diff --git a/data/sounds/effects/ogg/camera_click.ogg b/data/sounds/effects/ogg/camera_click.ogg
index 44b6683..130b534 100644
--- a/data/sounds/effects/ogg/camera_click.ogg
+++ b/data/sounds/effects/ogg/camera_click.ogg
Binary files differ
diff --git a/data/sounds/effects/ogg/camera_click_48k.ogg b/data/sounds/effects/ogg/camera_click_48k.ogg
new file mode 100644
index 0000000..b836e10
--- /dev/null
+++ b/data/sounds/effects/ogg/camera_click_48k.ogg
Binary files differ
diff --git a/docs/html/distribute/googleplay/promote/linking.jd b/docs/html/distribute/googleplay/promote/linking.jd
index 2d3bd05..46607f5 100644
--- a/docs/html/distribute/googleplay/promote/linking.jd
+++ b/docs/html/distribute/googleplay/promote/linking.jd
@@ -5,7 +5,7 @@
 <div class="sidebox">
 <a href="badges.html">
   <img alt="Get it on Google Play"
-       src="{@docRoot}en_app_rgb_wo_45.png" />
+       src="{@docRoot}images/brand/en_app_rgb_wo_45.png" />
 </a>
 <p>For a link that includes the Google Play brand icon, check out the <a href="badges.html">Badges</a> page. </p>
 </div>
diff --git a/docs/html/distribute/googleplay/strategies/app-quality.jd b/docs/html/distribute/googleplay/strategies/app-quality.jd
index ecc51dc..eb2cd2b 100644
--- a/docs/html/distribute/googleplay/strategies/app-quality.jd
+++ b/docs/html/distribute/googleplay/strategies/app-quality.jd
@@ -37,7 +37,7 @@
 <p>
 The most obvious way to listen to users is by reading and addressing comments on your app in Google Play. Although the comments aren't always productive or constructive, some will provide valuable insight on aspects of your app that you may not have consciously considered before. It's important to remember that users have the opportunity to change their ratings and comments about an app as much as they'd like.</p>
 <p>
-One way to reach users and help them address their concerns is to set up your own support and discussion destination(s). There are some great support tools out there that can put you in touch with your users directly such as <a href="http://groups.google.com">Google Groups</a>, <a href="http://discussions.zoho.com/">Zoho Discussions</a>, <a href="http://getsatisfaction.com">getsatisfaction.com</a> and <a href="http://uservoice.com">uservoice.com</a>. Once you get set up with such a tool, make sure to fill in the support link in your Google Play product details page &mdash; users do click through to these.</p>
+One way to reach users and help them address their concerns is to set up your own support and discussion destination(s). There are some great support tools out there that can put you in touch with your users directly, from forums such as <a href="http://groups.google.com">Google Groups</a> to comprehensive customer support products and destinations. Once you get set up with such a tool, make sure to fill in the support link in your Google Play product details page &mdash; users do click through to these.</p>
 <p>
 Another way to better listen to your users is by having a public beta or trusted tester program. It's crucial to have some amount of real user testing before releasing something in Google Play. Fortunately, you can distribute your apps to users outside of Google Play via a website; this website can require a login or be publicly accessible&nbsp;&mdash;&nbsp;it's entirely up to you. Take advantage of this opportunity by offering your next planned update to some early adopters, before submitting to Google Play. You'll be surprised by how many little, yet impactful, improvements can come out of crowd-sourced, real-user testing.</p>
 
@@ -51,7 +51,7 @@
 <p>
 Also, with the Google error-reporting features built into most Android devices, users now have a way to report application crashes to developers. The error reports show up in aggregate in the Google Play Developer Console. Make sure to read these reports often and act on them appropriately.</p>
 <p>
-Last, keep an external bug and feature request tracker and let users know how to find it. This will enable them to engage with the app at a closer level, by following features and bugs that affect them. User frustration with app problems can be effectively managed with diligent issue tracking and communication. Some of the community support tools listed above offer issue tracking features, and if your project is open source, most popular repository hosting sites such as <a href="http://code.google.com/hosting">Google Code</a> and <a href="https://github.com/">GitHub</a> will offer this as well.</p>
+Last, keep an external bug and feature request tracker and let users know how to find it. This will enable them to engage with the app at a closer level, by following features and bugs that affect them. User frustration with app problems can be effectively managed with diligent issue tracking and communication. Some of the community support tools listed above offer issue tracking features, and if your project is open source, most popular repository hosting sites will offer this as well.</p>
 
 <h2 id="responsiveness">Improve UI Responsiveness</h2>
 <p>
@@ -96,9 +96,9 @@
 
 <h2 id="appearance">Professional Appearance and Aesthetics</h2>
 <p>
-There's no substitute for a real user interface designer&nbsp;&mdash;&nbsp;ideally one who's well-versed in mobile and Android, and ideally handy with both interaction and visual design. One popular venue to post openings for designers is <a href="http://jobs.smashingmagazine.com">jobs.smashingmagazine.com</a>, and leveraging social connections on Twitter and LinkedIn can surface great talent.</p>
+There's no substitute for a real user interface designer&nbsp;&mdash;&nbsp;ideally one who's well-versed in mobile and Android, and ideally handy with both interaction and visual design. One popular venue to post openings for designers is <a href="http://jobs.smashingmagazine.com">jobs.smashingmagazine.com</a>, and leveraging social networks can also surface great talent.</p>
 <p>
-If you don't have the luxury of working with a UI designer, there are some ways in which you can improve your app's appearance yourself. First, get familiar with Adobe Photoshop, Adobe Fireworks, or some other raster image editing tool. Mastering the art of the pixel in these apps takes time, but honing this skill can help build polish across your interface designs. Also, master the resources framework by studying <a href="http://android.git.kernel.org/?p=platform/frameworks/base.git;a=tree;f=core/res/res;h=a3562fe1af94134486a8a899f02a9c2f7986c8dd;hb=master">the framework UI</a> assets and layouts and reading through the new <a href="{@docRoot}guide/topics/resources/index.html">resources documentation</a>. Techniques such as 9-patches and resource directory qualifiers are somewhat unique to Android, and are crucial in building flexible yet aesthetic UIs.</p>
+If you don't have the luxury of working with a UI designer, there are some ways in which you can improve your app's appearance yourself. First, get familiar with Adobe Photoshop, Adobe Fireworks, or some other raster image editing tool. Mastering the art of the pixel in these apps takes time, but honing this skill can help build polish across your interface designs. Also, master the resources framework by studying the framework UI assets and layouts and reading through the <a href="{@docRoot}guide/topics/resources/index.html">resources documentation</a>. Techniques such as 9-patches and resource directory qualifiers are somewhat unique to Android, and are crucial in building flexible yet aesthetic UIs.</p>
 <p>
 Before you get too far in designing your app and writing the code, make sure to visit the Android Design site and learn about the vision, the building blocks, and the tools of designing beautiful and inspiring user interfaces.</p>
 
@@ -114,8 +114,8 @@
 
 <p>For some app categories, basic features like home screen widgets are par for the course. Not including them is a sure-fire way to tarnish an otherwise positive user experience. Some apps can achieve even tighter OS integration with Android's contacts, accounts, and sync APIs. </p>
 <p>
-Third-party integrations can provide even more user delight and give the user a feeling of device cohesiveness. It's also a really nice way of adding functionality to your app without writing any extra code (by leveraging other apps' functionalities). For example, if you're creating a camera app, you can allow users to edit their photos in <a href=" http://mobile.photoshop.com/android/">Photoshop Express</a> before saving them to their collection, if they have that third-party application installed. More information on this subject is available in the class, <a href="{@docRoot}training/basics/intents/index.html">Interacting with Other Apps</a>.</p>
+Third-party integrations can provide even more user delight and give the user a feeling of device cohesiveness. It's also a really nice way of adding functionality to your app without writing any extra code (by leveraging other apps' functionalities). For example, if you're creating a camera app, you can allow users to edit their photos in another app before saving them to their collection, if they have that third-party application installed. More information on this subject is available in the Android Training class <a href="{@docRoot}training/basics/intents/index.html">Interacting with Other Apps</a>.</p>
 
 <h2 id="details">Pay Attention to Details</h2>
 <p>
-One particular detail to pay close attention to is your app's icon quality and consistency. Make sure your app icons (especially your launcher icon) are crisp and pixel-perfect at all resolutions, and follow the <a href="{@docRoot}guide/practices/ui_guidelines/icon_design.html">icon guidelines</a> as much as possible. If you're having trouble or don't have the resources to design the icons yourself, consider using the new <a href="http://android-ui-utils.googlecode.com/hg/asset-studio/dist/index.html">Android Asset Studio</a> tool to generate a set.</p>
+One particular detail to pay close attention to is your app's icon quality and consistency. Make sure your app icons (especially your launcher icon) are crisp and pixel-perfect at all resolutions, and follow the <a href="{@docRoot}guide/practices/ui_guidelines/icon_design.html">icon guidelines</a> as much as possible. If you're having trouble or don't have the resources to design the icons yourself, consider using the <a href="http://android-ui-utils.googlecode.com/hg/asset-studio/dist/index.html">Android Asset Studio</a> tool to generate a set.</p>
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/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 406d5e9..914516c 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -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) {
@@ -2792,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;
     }
 
@@ -2858,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/TextureCache.cpp b/libs/hwui/TextureCache.cpp
index 7fb86ee..10d112a 100644
--- a/libs/hwui/TextureCache.cpp
+++ b/libs/hwui/TextureCache.cpp
@@ -74,8 +74,6 @@
     INIT_LOGD("    Maximum texture dimension is %d pixels", mMaxTextureSize);
 
     mDebugEnabled = readDebugLevel() & kDebugCaches;
-
-    mHasNPot = false; //Caches::getInstance().extensions.hasNPot();
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -219,11 +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) ||
-            (regenerate && mHasNPot && texture->mipMap && !bitmap->hasHardwareMipMap());
+            (regenerate && canMipMap && texture->mipMap && !bitmap->hasHardwareMipMap());
 
     if (!regenerate) {
         glGenTextures(1, &texture->id);
@@ -267,7 +269,7 @@
         break;
     }
 
-    if (mHasNPot) {
+    if (canMipMap) {
         texture->mipMap = bitmap->hasHardwareMipMap();
         if (texture->mipMap) {
             glGenerateMipmap(GL_TEXTURE_2D);
diff --git a/libs/hwui/TextureCache.h b/libs/hwui/TextureCache.h
index 8e19092..31a2e3d 100644
--- a/libs/hwui/TextureCache.h
+++ b/libs/hwui/TextureCache.h
@@ -138,7 +138,6 @@
 
     float mFlushRate;
 
-    bool mHasNPot;
     bool mDebugEnabled;
 
     Vector<SkBitmap*> mGarbage;
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 3464924..1c60401 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/performance/MediaPlayerPerformance.java
@@ -117,6 +117,7 @@
         }
         mMemWriter = new BufferedWriter(new FileWriter
                 (new File(MEDIA_MEMORY_OUTPUT), true));
+        mMemWriter.write(this.getName() + "\n");
     }
 
     @Override
diff --git a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
index 76b1ec6..cf56cba 100644
--- a/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
+++ b/packages/DefaultContainerService/src/com/android/defcontainer/DefaultContainerService.java
@@ -259,6 +259,21 @@
                 eraseFiles(directory);
             }
         }
+
+        @Override
+        public long calculateInstalledSize(String packagePath, boolean isForwardLocked)
+                throws RemoteException {
+            final File packageFile = new File(packagePath);
+            try {
+                return calculateContainerSize(packageFile, isForwardLocked) * 1024 * 1024;
+            } catch (IOException e) {
+                /*
+                 * Okay, something failed, so let's just estimate it to be 2x
+                 * the file size. Note this will be 0 if the file doesn't exist.
+                 */
+                return packageFile.length() * 2;
+            }
+        }
     };
 
     public DefaultContainerService() {
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/layout-sw600dp/navigation_bar.xml b/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml
index fbbd7e5..afa4cfc 100644
--- a/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml
+++ b/packages/SystemUI/res/layout-sw600dp/navigation_bar.xml
@@ -141,6 +141,16 @@
                 />
         </LinearLayout>
 
+        <ImageView
+            android:layout_width="128dp"
+            android:id="@+id/search_light"
+            android:layout_height="match_parent"
+            android:layout_gravity="center_horizontal"
+            android:src="@drawable/ic_sysbar_lights_out_dot_large"
+            android:scaleType="center"
+            android:visibility="gone"
+            />
+
         <com.android.systemui.statusbar.policy.DeadZone
             android:id="@+id/deadzone"
             android:layout_height="match_parent"
@@ -272,6 +282,16 @@
                 />
         </LinearLayout>
 
+        <ImageView
+            android:layout_width="162dp"
+            android:id="@+id/search_light"
+            android:layout_height="match_parent"
+            android:layout_gravity="center_horizontal"
+            android:src="@drawable/ic_sysbar_lights_out_dot_large"
+            android:scaleType="center"
+            android:visibility="gone"
+            />
+
         <com.android.systemui.statusbar.policy.DeadZone
             android:id="@+id/deadzone"
             android:layout_height="match_parent"
diff --git a/packages/SystemUI/res/layout/navigation_bar.xml b/packages/SystemUI/res/layout/navigation_bar.xml
index 33b5dbb..133f79d 100644
--- a/packages/SystemUI/res/layout/navigation_bar.xml
+++ b/packages/SystemUI/res/layout/navigation_bar.xml
@@ -145,6 +145,16 @@
                 />
         </LinearLayout>
 
+        <ImageView
+            android:layout_width="80dp"
+            android:id="@+id/search_light"
+            android:layout_height="match_parent"
+            android:layout_gravity="center_horizontal"
+            android:src="@drawable/ic_sysbar_lights_out_dot_large"
+            android:scaleType="center"
+            android:visibility="gone"
+            />
+
         <com.android.systemui.statusbar.policy.DeadZone
             android:id="@+id/deadzone"
             android:layout_height="match_parent"
@@ -279,6 +289,16 @@
                 />
         </LinearLayout>
 
+        <ImageView
+            android:id="@+id/search_light"
+            android:layout_height="80dp"
+            android:layout_width="match_parent"
+            android:layout_gravity="center_vertical"
+            android:src="@drawable/ic_sysbar_lights_out_dot_large"
+            android:scaleType="center"
+            android:visibility="gone"
+            />
+
         <com.android.systemui.statusbar.policy.DeadZone
             android:id="@+id/deadzone"
             android:layout_height="match_parent"
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/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/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 0958f70..0a7dd7c 100644
--- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
@@ -109,7 +109,7 @@
         private WallpaperObserver mReceiver;
 
         Bitmap mBackground;
-        int mBackgroundWidth = -1, mBackgroundHeight = -1;
+        int mLastSurfaceWidth = -1, mLastSurfaceHeight = -1;
         int mLastRotation = -1;
         float mXOffset;
         float mYOffset;
@@ -156,7 +156,7 @@
                 }
 
                 synchronized (mLock) {
-                    mBackgroundWidth = mBackgroundHeight = -1;
+                    mLastSurfaceWidth = mLastSurfaceHeight = -1;
                     mBackground = null;
                     mRedrawNeeded = true;
                     drawFrameLocked();
@@ -172,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();
@@ -286,13 +289,13 @@
         @Override
         public void onSurfaceDestroyed(SurfaceHolder holder) {
             super.onSurfaceDestroyed(holder);
-            mBackgroundWidth = mBackgroundHeight = -1;
+            mLastSurfaceWidth = mLastSurfaceHeight = -1;
         }
 
         @Override
         public void onSurfaceCreated(SurfaceHolder holder) {
             super.onSurfaceCreated(holder);
-            mBackgroundWidth = mBackgroundHeight = -1;
+            mLastSurfaceWidth = mLastSurfaceHeight = -1;
         }
 
         @Override
@@ -314,9 +317,9 @@
             final int dh = frame.height();
             int newRotation = ((WindowManager) getSystemService(WINDOW_SERVICE)).
                     getDefaultDisplay().getRotation();
+            boolean surfaceDimensionsChanged = dw != mLastSurfaceWidth || dh != mLastSurfaceHeight;
 
-            boolean redrawNeeded = dw != mBackgroundWidth || dh != mBackgroundHeight ||
-                    newRotation != mLastRotation;
+            boolean redrawNeeded = surfaceDimensionsChanged || newRotation != mLastRotation;
             if (!redrawNeeded && !mOffsetsChanged) {
                 if (DEBUG) {
                     Log.d(TAG, "Suppressed drawFrame since redraw is not needed "
@@ -327,21 +330,41 @@
             mLastRotation = newRotation;
 
             // Load bitmap if it is not yet loaded or if it was loaded at a different size
-            if (mBackground == null || dw != mBackgroundWidth || dw != mBackgroundHeight) {
+            if (mBackground == null || surfaceDimensionsChanged) {
                 if (DEBUG) {
-                    Log.d(TAG, "Reloading bitmap");
+                    Log.d(TAG, "Reloading bitmap: mBackground, bgw, bgh, dw, dh = " +
+                            mBackground + ", " +
+                            ((mBackground == null) ? 0 : mBackground.getWidth()) + ", " +
+                            ((mBackground == null) ? 0 : mBackground.getHeight()) + ", " +
+                            dw + ", " + dh);
                 }
-                mWallpaperManager.forgetLoadedWallpaper();
                 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 - mBackgroundWidth;
-            final int availh = dh - mBackgroundHeight;
+            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;
             mRedrawNeeded = false;
+            if (surfaceDimensionsChanged) {
+                mLastSurfaceWidth = dw;
+                mLastSurfaceHeight = dh;
+            }
             mLastXTranslation = xPixels;
             mLastYTranslation = yPixels;
             if (!redrawNeeded && xPixels == mLastXTranslation && yPixels == mLastYTranslation) {
@@ -374,9 +397,10 @@
 
         }
 
-        void updateWallpaperLocked() {
+        private void updateWallpaperLocked() {
             Throwable exception = null;
             try {
+                mWallpaperManager.forgetLoadedWallpaper(); // force reload
                 mBackground = mWallpaperManager.getBitmap();
             } catch (RuntimeException e) {
                 exception = e;
@@ -397,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) {
@@ -413,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();
                     }
@@ -429,8 +451,8 @@
         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();
diff --git a/packages/SystemUI/src/com/android/systemui/SearchPanelView.java b/packages/SystemUI/src/com/android/systemui/SearchPanelView.java
index bc61ab0..4b0e818 100644
--- a/packages/SystemUI/src/com/android/systemui/SearchPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/SearchPanelView.java
@@ -17,6 +17,7 @@
 package com.android.systemui;
 
 import android.animation.LayoutTransition;
+import android.app.ActivityManagerNative;
 import android.app.ActivityOptions;
 import android.app.SearchManager;
 import android.content.ActivityNotFoundException;
@@ -24,6 +25,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Resources;
+import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.Vibrator;
 import android.provider.Settings;
@@ -71,12 +73,21 @@
     }
 
     private void startAssistActivity() {
+        if (!mBar.isDeviceProvisioned()) return;
+
         // Close Recent Apps if needed
         mBar.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_SEARCH_PANEL);
         // Launch Assist
         Intent intent = ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE))
                 .getAssistIntent(mContext, UserHandle.USER_CURRENT);
         if (intent == null) return;
+
+        // Dismiss the keyguard if possible. XXX: TODO: invoke bouncer.
+        try {
+            ActivityManagerNative.getDefault().dismissKeyguardOnNextActivity();
+        } catch (RemoteException e) {
+        }
+
         try {
             ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext,
                     R.anim.search_launch_enter, R.anim.search_launch_exit,
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/DelegateViewHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/DelegateViewHelper.java
index 4f33e23..3ac1bcf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DelegateViewHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DelegateViewHelper.java
@@ -49,7 +49,7 @@
 
     public boolean onInterceptTouchEvent(MotionEvent event) {
         if (mSourceView == null || mDelegateView == null
-                || mBar.shouldDisableNavbarGestures() || mBar.inKeyguardRestrictedInputMode()) {
+                || mBar.shouldDisableNavbarGestures()) {
             return false;
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index dcc2e57..770ae6d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -142,6 +142,11 @@
         return mCurrentView.findViewById(R.id.home);
     }
 
+    // for when home is disabled, but search isn't
+    public View getSearchLight() {
+        return mCurrentView.findViewById(R.id.search_light);
+    }
+
     public NavigationBarView(Context context, AttributeSet attrs) {
         super(context, attrs);
 
@@ -222,12 +227,15 @@
         final boolean disableHome = ((disabledFlags & View.STATUS_BAR_DISABLE_HOME) != 0);
         final boolean disableRecent = ((disabledFlags & View.STATUS_BAR_DISABLE_RECENT) != 0);
         final boolean disableBack = ((disabledFlags & View.STATUS_BAR_DISABLE_BACK) != 0);
+        final boolean disableSearch = ((disabledFlags & View.STATUS_BAR_DISABLE_SEARCH) != 0);
 
         setSlippery(disableHome && disableRecent && disableBack);
 
         getBackButton()   .setVisibility(disableBack       ? View.INVISIBLE : View.VISIBLE);
         getHomeButton()   .setVisibility(disableHome       ? View.INVISIBLE : View.VISIBLE);
         getRecentsButton().setVisibility(disableRecent     ? View.INVISIBLE : View.VISIBLE);
+
+        getSearchLight().setVisibility((disableHome && !disableSearch) ? View.VISIBLE : View.GONE);
     }
 
     public void setSlippery(boolean newSlippery) {
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 a857eba..248a516 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -35,7 +35,7 @@
     View mHandleView;
     int mFingers;
     PhoneStatusBar mStatusBar;
-    private boolean mFlipped;
+    boolean mOkToFlip;
 
     public NotificationPanelView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -94,10 +94,10 @@
         if (PhoneStatusBar.SETTINGS_DRAG_SHORTCUT && mStatusBar.mHasFlipSettings) {
             switch (event.getActionMasked()) {
                 case MotionEvent.ACTION_DOWN:
-                    mFlipped = false;
+                    mOkToFlip = getExpandedHeight() == 0;
                     break;
                 case MotionEvent.ACTION_POINTER_DOWN:
-                    if (!mFlipped) {
+                    if (mOkToFlip) {
                         float miny = event.getY(0);
                         float maxy = miny;
                         for (int i=1; i<event.getPointerCount(); i++) {
@@ -111,7 +111,7 @@
                             } else {
                                 mStatusBar.flipToSettings();
                             }
-                            mFlipped = true;
+                            mOkToFlip = false;
                         }
                     }
                     break;
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 1c4dff8..41ccf39 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;
@@ -677,6 +676,10 @@
     @Override
     public void showSearchPanel() {
         super.showSearchPanel();
+
+        // we want to freeze the sysui state wherever it is
+        mSearchPanelView.setSystemUiVisibility(mSystemUiVisibility);
+
         WindowManager.LayoutParams lp =
             (android.view.WindowManager.LayoutParams) mNavigationBarView.getLayoutParams();
         lp.flags &= ~WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
@@ -723,7 +726,7 @@
         public boolean onTouch(View v, MotionEvent event) {
             switch(event.getAction()) {
             case MotionEvent.ACTION_DOWN:
-                if (!shouldDisableNavbarGestures() && !inKeyguardRestrictedInputMode()) {
+                if (!shouldDisableNavbarGestures()) {
                     mHandler.removeCallbacks(mShowSearchPanel);
                     mHandler.postDelayed(mShowSearchPanel, mShowSearchHoldoff);
                 }
@@ -753,7 +756,7 @@
         mNavigationBarView.reorient();
 
         mNavigationBarView.getRecentsButton().setOnClickListener(mRecentsClickListener);
-        mNavigationBarView.getRecentsButton().setOnTouchListener(getRecentTasksLoader());
+        mNavigationBarView.getRecentsButton().setOnTouchListener(mRecentsPreloadOnTouchListener);
         mNavigationBarView.getHomeButton().setOnTouchListener(mHomeSearchActionListener);
         updateSearchPanel();
     }
@@ -1179,6 +1182,8 @@
         flagdbg.append(((diff  & StatusBarManager.DISABLE_RECENT) != 0) ? "* " : " ");
         flagdbg.append(((state & StatusBarManager.DISABLE_CLOCK) != 0) ? "CLOCK" : "clock");
         flagdbg.append(((diff  & StatusBarManager.DISABLE_CLOCK) != 0) ? "* " : " ");
+        flagdbg.append(((state & StatusBarManager.DISABLE_SEARCH) != 0) ? "SEARCH" : "search");
+        flagdbg.append(((diff  & StatusBarManager.DISABLE_SEARCH) != 0) ? "* " : " ");
         flagdbg.append(">");
         Slog.d(TAG, flagdbg.toString());
 
@@ -1216,7 +1221,8 @@
 
         if ((diff & (StatusBarManager.DISABLE_HOME
                         | StatusBarManager.DISABLE_RECENT
-                        | StatusBarManager.DISABLE_BACK)) != 0) {
+                        | StatusBarManager.DISABLE_BACK
+                        | StatusBarManager.DISABLE_SEARCH)) != 0) {
             // the nav bar will take care of these
             if (mNavigationBarView != null) mNavigationBarView.setDisabledFlags(state);
 
@@ -2416,7 +2422,9 @@
 
     @Override
     protected boolean shouldDisableNavbarGestures() {
-        return mExpandedVisible || (mDisabled & StatusBarManager.DISABLE_HOME) != 0;
+        return !isDeviceProvisioned()
+                || mExpandedVisible
+                || (mDisabled & StatusBarManager.DISABLE_SEARCH) != 0;
     }
 
     private static class FastColorDrawable extends Drawable {
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/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/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/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 63eeeb3..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)) {
@@ -1344,7 +1453,8 @@
           return null;
         }
 
-        checkPermissionForProvider(getBestCallingPermission(), provider);
+        checkResolutionLevelIsSufficientForProviderUse(getCallerAllowedResolutionLevel(),
+                provider);
 
         LocationProviderInterface p;
         synchronized (mLock) {
@@ -1357,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();
@@ -1522,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/accessibility/ScreenMagnifier.java b/services/java/com/android/server/accessibility/ScreenMagnifier.java
index caf37b7..482bff5 100644
--- a/services/java/com/android/server/accessibility/ScreenMagnifier.java
+++ b/services/java/com/android/server/accessibility/ScreenMagnifier.java
@@ -40,6 +40,7 @@
 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;
@@ -71,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.
@@ -174,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);
@@ -263,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
@@ -293,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);
         }
     }
@@ -1000,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 {
@@ -1067,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) {
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 7132e1e..5722326 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -7251,11 +7251,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);
         }
 
@@ -7317,9 +7317,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;
@@ -7596,12 +7596,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);
@@ -11119,8 +11119,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
@@ -11181,6 +11181,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
@@ -11217,32 +11228,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 93896af..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);
     }
@@ -631,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);
 
@@ -857,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 680662e..aa7ea82 100644
--- a/services/java/com/android/server/display/LogicalDisplay.java
+++ b/services/java/com/android/server/display/LogicalDisplay.java
@@ -241,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/Installer.java b/services/java/com/android/server/pm/Installer.java
index 8b1e80f..71a6a01 100644
--- a/services/java/com/android/server/pm/Installer.java
+++ b/services/java/com/android/server/pm/Installer.java
@@ -369,7 +369,7 @@
      * @param nativeLibPath target native library path
      * @return -1 on error
      */
-    public int linkNativeLibraryDirectory(String dataPath, String nativeLibPath) {
+    public int linkNativeLibraryDirectory(String dataPath, String nativeLibPath, int userId) {
         if (dataPath == null) {
             Slog.e(TAG, "linkNativeLibraryDirectory dataPath is null");
             return -1;
@@ -382,6 +382,8 @@
         builder.append(dataPath);
         builder.append(' ');
         builder.append(nativeLibPath);
+        builder.append(' ');
+        builder.append(userId);
 
         return execute(builder.toString());
     }
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index f59e30d..4c6f589 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -2575,7 +2575,7 @@
     @Override
     public List<ResolveInfo> queryIntentActivities(Intent intent,
             String resolvedType, int flags, int userId) {
-        if (!sUserManager.exists(userId)) return null;
+        if (!sUserManager.exists(userId)) return Collections.emptyList();
         enforceCrossUserPermission(Binder.getCallingUid(), userId, false, "query intent activities");
         ComponentName comp = intent.getComponent();
         if (comp == null) {
@@ -2615,7 +2615,7 @@
     public List<ResolveInfo> queryIntentActivityOptions(ComponentName caller,
             Intent[] specifics, String[] specificTypes, Intent intent,
             String resolvedType, int flags, int userId) {
-        if (!sUserManager.exists(userId)) return null;
+        if (!sUserManager.exists(userId)) return Collections.emptyList();
         enforceCrossUserPermission(Binder.getCallingUid(), userId, false,
                 "query intent activity options");
         final String resultsAction = intent.getAction();
@@ -2787,7 +2787,7 @@
     @Override
     public List<ResolveInfo> queryIntentReceivers(Intent intent, String resolvedType, int flags,
             int userId) {
-        if (!sUserManager.exists(userId)) return null;
+        if (!sUserManager.exists(userId)) return Collections.emptyList();
         ComponentName comp = intent.getComponent();
         if (comp == null) {
             if (intent.getSelector() != null) {
@@ -2838,7 +2838,7 @@
     @Override
     public List<ResolveInfo> queryIntentServices(Intent intent, String resolvedType, int flags,
             int userId) {
-        if (!sUserManager.exists(userId)) return null;
+        if (!sUserManager.exists(userId)) return Collections.emptyList();
         ComponentName comp = intent.getComponent();
         if (comp == null) {
             if (intent.getSelector() != null) {
@@ -4088,39 +4088,42 @@
                         Log.i(TAG, "removed obsolete native libraries for system package "
                                 + path);
                     }
-                } else if (!isForwardLocked(pkg) && !isExternal(pkg)) {
-                    // Update native library dir if it starts with /data/data
-                    if (nativeLibraryDir.getPath().startsWith(dataPathString)) {
-                        setInternalAppNativeLibraryPath(pkg, pkgSetting);
-                        nativeLibraryDir = new File(pkg.applicationInfo.nativeLibraryDir);
-                    }
+                } else {
+                    if (!isForwardLocked(pkg) && !isExternal(pkg)) {
+                        /*
+                         * Update native library dir if it starts with
+                         * /data/data
+                         */
+                        if (nativeLibraryDir.getPath().startsWith(dataPathString)) {
+                            setInternalAppNativeLibraryPath(pkg, pkgSetting);
+                            nativeLibraryDir = new File(pkg.applicationInfo.nativeLibraryDir);
+                        }
 
-                    try {
-                        if (copyNativeLibrariesForInternalApp(scanFile, nativeLibraryDir) != PackageManager.INSTALL_SUCCEEDED) {
-                            Slog.e(TAG, "Unable to copy native libraries");
+                        try {
+                            if (copyNativeLibrariesForInternalApp(scanFile, nativeLibraryDir) != PackageManager.INSTALL_SUCCEEDED) {
+                                Slog.e(TAG, "Unable to copy native libraries");
+                                mLastScanError = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
+                                return null;
+                            }
+                        } catch (IOException e) {
+                            Slog.e(TAG, "Unable to copy native libraries", e);
                             mLastScanError = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
                             return null;
                         }
-                    } catch (IOException e) {
-                        Slog.e(TAG, "Unable to copy native libraries", e);
-                        mLastScanError = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
-                        return null;
                     }
 
-                    if (mInstaller.linkNativeLibraryDirectory(dataPathString,
-                            pkg.applicationInfo.nativeLibraryDir) == -1) {
-                        Slog.e(TAG, "Unable to link native library directory");
-                        mLastScanError = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
-                        return null;
-                    }
-                } else {
                     Slog.i(TAG, "Linking native library dir for " + path);
-                    int ret = mInstaller.linkNativeLibraryDirectory(dataPathString,
-                            pkg.applicationInfo.nativeLibraryDir);
-                    if (ret < 0) {
-                        Slog.w(TAG, "Failed linking native library dir for " + path);
-                        mLastScanError = PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE;
-                        return null;
+                    final int[] userIds = sUserManager.getUserIds();
+                    synchronized (mInstallLock) {
+                        for (int userId : userIds) {
+                            if (mInstaller.linkNativeLibraryDirectory(pkg.packageName,
+                                    pkg.applicationInfo.nativeLibraryDir, userId) < 0) {
+                                Slog.w(TAG, "Failed linking native library dir (user=" + userId
+                                        + ")");
+                                mLastScanError = PackageManager.INSTALL_FAILED_INTERNAL_ERROR;
+                                return null;
+                            }
+                        }
                     }
                 }
             } catch (IOException ioe) {
@@ -6327,8 +6330,23 @@
 
                     if (packageFile != null) {
                         // Remote call to find out default install location
-                        pkgLite = mContainerService.getMinimalPackageInfo(
-                                packageFile.getAbsolutePath(), flags, lowThreshold);
+                        final String packageFilePath = packageFile.getAbsolutePath();
+                        pkgLite = mContainerService.getMinimalPackageInfo(packageFilePath, flags,
+                                lowThreshold);
+
+                        /*
+                         * If we have too little free space, try to free cache
+                         * before giving up.
+                         */
+                        if (pkgLite.recommendedInstallLocation
+                                == PackageHelper.RECOMMEND_FAILED_INSUFFICIENT_STORAGE) {
+                            final long size = mContainerService.calculateInstalledSize(
+                                    packageFilePath, isForwardLocked());
+                            if (mInstaller.freeCache(size + lowThreshold) >= 0) {
+                                pkgLite = mContainerService.getMinimalPackageInfo(packageFilePath,
+                                        flags, lowThreshold);
+                            }
+                        }
                     }
                 } finally {
                     mContext.revokeUriPermission(mPackageURI,
@@ -6350,12 +6368,12 @@
                     ret = PackageManager.INSTALL_FAILED_INVALID_URI;
                 } else if (loc == PackageHelper.RECOMMEND_MEDIA_UNAVAILABLE) {
                     ret = PackageManager.INSTALL_FAILED_MEDIA_UNAVAILABLE;
-                } else if (loc == PackageHelper.RECOMMEND_FAILED_VERSION_DOWNGRADE) {
-                    ret = PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
                 } else {
                     // Override with defaults if needed.
                     loc = installLocationPolicy(pkgLite, flags);
-                    if (!onSd && !onInt) {
+                    if (loc == PackageHelper.RECOMMEND_FAILED_VERSION_DOWNGRADE) {
+                        ret = PackageManager.INSTALL_FAILED_VERSION_DOWNGRADE;
+                    } else if (!onSd && !onInt) {
                         // Override install location with flags
                         if (loc == PackageHelper.RECOMMEND_INSTALL_EXTERNAL) {
                             // Set the flag to install on external media.
@@ -9959,20 +9977,14 @@
                                     final File newNativeDir = new File(newNativePath);
 
                                     if (!isForwardLocked(pkg) && !isExternal(pkg)) {
-                                        synchronized (mInstallLock) {
-                                            if (mInstaller.linkNativeLibraryDirectory(
-                                                    pkg.applicationInfo.dataDir, newNativePath) < 0) {
-                                                returnCode = PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE;
-                                            }
-                                        }
-                                        NativeLibraryHelper.copyNativeBinariesIfNeededLI(new File(
-                                                newCodePath), newNativeDir);
-                                    } else {
-                                        synchronized (mInstallLock) {
-                                            if (mInstaller.linkNativeLibraryDirectory(
-                                                    pkg.applicationInfo.dataDir, newNativePath) < 0) {
-                                                returnCode = PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE;
-                                            }
+                                        NativeLibraryHelper.copyNativeBinariesIfNeededLI(
+                                                new File(newCodePath), newNativeDir);
+                                    }
+                                    final int[] users = sUserManager.getUserIds();
+                                    for (int user : users) {
+                                        if (mInstaller.linkNativeLibraryDirectory(pkg.packageName,
+                                                newNativePath, user) < 0) {
+                                            returnCode = PackageManager.MOVE_FAILED_INSUFFICIENT_STORAGE;
                                         }
                                     }
 
diff --git a/services/java/com/android/server/pm/UserManagerService.java b/services/java/com/android/server/pm/UserManagerService.java
index 77e6c03..fb93d05 100644
--- a/services/java/com/android/server/pm/UserManagerService.java
+++ b/services/java/com/android/server/pm/UserManagerService.java
@@ -19,9 +19,11 @@
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.FastXmlSerializer;
 
+import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
 import android.app.IStopUserCallback;
+import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
@@ -62,6 +64,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 +101,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;
 
@@ -199,7 +206,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;
         }
@@ -668,6 +676,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);
@@ -709,7 +718,7 @@
             user.partial = true;
             writeUserLocked(user);
         }
-
+        if (DBG) Slog.i(LOG_TAG, "Stopping user " + userHandle);
         int res;
         try {
             res = ActivityManagerNative.getDefault().stopUser(userHandle,
@@ -729,20 +738,38 @@
         return res == ActivityManager.USER_OP_SUCCESS;
     }
 
-    void finishRemoveUser(int userHandle) {
-        synchronized (mInstallLock) {
-            synchronized (mPackagesLock) {
-                removeUserStateLocked(userHandle);
-            }
-        }
-
-        // Let other services shutdown any activity
+    void finishRemoveUser(final int userHandle) {
+        if (DBG) Slog.i(LOG_TAG, "finishRemoveUser " + userHandle);
+        // Let other services shutdown any activity and clean up their state before completely
+        // wiping the user's system directory and removing from the user list
         long ident = Binder.clearCallingIdentity();
         try {
             Intent addedIntent = new Intent(Intent.ACTION_USER_REMOVED);
             addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userHandle);
-            mContext.sendBroadcastAsUser(addedIntent, UserHandle.ALL,
-                    android.Manifest.permission.MANAGE_USERS);
+            mContext.sendOrderedBroadcastAsUser(addedIntent, UserHandle.ALL,
+                    android.Manifest.permission.MANAGE_USERS,
+
+                    new BroadcastReceiver() {
+                        @Override
+                        public void onReceive(Context context, Intent intent) {
+                            if (DBG) {
+                                Slog.i(LOG_TAG,
+                                        "USER_REMOVED broadcast sent, cleaning up user data "
+                                        + userHandle);
+                            }
+                            new Thread() {
+                                public void run() {
+                                    synchronized (mInstallLock) {
+                                        synchronized (mPackagesLock) {
+                                            removeUserStateLocked(userHandle);
+                                        }
+                                    }
+                                }
+                            }.start();
+                        }
+                    },
+
+                    null, Activity.RESULT_OK, null, null);
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
@@ -804,10 +831,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;
@@ -840,13 +868,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 fa450ae..52992a1 100755
--- a/services/java/com/android/server/wm/WindowManagerService.java
+++ b/services/java/com/android/server/wm/WindowManagerService.java
@@ -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;
+                    }
                 }
             }
         }
@@ -7149,7 +7171,6 @@
 
         synchronized(mWindowMap) {
             final DisplayContent displayContent = getDefaultDisplayContentLocked();
-            final Display display = displayContent.getDisplay();
             readForcedDisplaySizeAndDensityLocked(displayContent);
 
             mDisplayReady = true;
@@ -7173,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;
             }
         }
     }
@@ -7831,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
@@ -7845,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);
+            }
         }
     }
 
@@ -7895,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);
 
@@ -7905,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);
 
@@ -7933,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(),
@@ -9711,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;
@@ -10837,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;
     }
@@ -10927,6 +10976,7 @@
         }
     }
 
+    // There is an inherent assumption that this will never return null.
     public DisplayContent getDefaultDisplayContentLocked() {
         return getDisplayContentLocked(Display.DEFAULT_DISPLAY);
     }
@@ -10939,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
@@ -10949,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
@@ -10960,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/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 8aeb2af..7848b1d 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -34,7 +34,7 @@
     <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
     <uses-permission android:name="android.permission.MANAGE_USERS" />
-    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
     
     <application>
         <uses-library android:name="android.test.runner" />
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index 59a86c2..1758d93 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -16,23 +16,37 @@
 
 package com.android.server.pm;
 
+import android.content.BroadcastReceiver;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.pm.UserInfo;
 import android.os.Debug;
 import android.os.Environment;
 import android.os.UserManager;
 import android.test.AndroidTestCase;
 
+import java.util.ArrayList;
 import java.util.List;
 
 /** Test {@link UserManager} functionality. */
 public class UserManagerTest extends AndroidTestCase {
 
     UserManager mUserManager = null;
+    Object mUserLock = new Object();
 
     @Override
     public void setUp() throws Exception {
         mUserManager = (UserManager) getContext().getSystemService(Context.USER_SERVICE);
+        IntentFilter filter = new IntentFilter(Intent.ACTION_USER_REMOVED);
+        getContext().registerReceiver(new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                synchronized (mUserLock) {
+                    mUserLock.notifyAll();
+                }
+            }
+        }, filter);
     }
 
     public void testHasPrimary() throws Exception {
@@ -54,7 +68,7 @@
             }
         }
         assertTrue(found);
-        mUserManager.removeUser(userInfo.id);
+        removeUser(userInfo.id);
     }
 
     public void testAdd2Users() throws Exception {
@@ -67,14 +81,13 @@
         assertTrue(findUser(0));
         assertTrue(findUser(user1.id));
         assertTrue(findUser(user2.id));
-        mUserManager.removeUser(user1.id);
-        mUserManager.removeUser(user2.id);
+        removeUser(user1.id);
+        removeUser(user2.id);
     }
 
     public void testRemoveUser() throws Exception {
         UserInfo userInfo = mUserManager.createUser("Guest 1", UserInfo.FLAG_GUEST);
-
-        mUserManager.removeUser(userInfo.id);
+        removeUser(userInfo.id);
 
         assertFalse(findUser(userInfo.id));
     }
@@ -95,12 +108,47 @@
         int serialNumber1 = user1.serialNumber;
         assertEquals(serialNumber1, mUserManager.getUserSerialNumber(user1.id));
         assertEquals(user1.id, mUserManager.getUserHandle(serialNumber1));
-        mUserManager.removeUser(user1.id);
+        removeUser(user1.id);
         UserInfo user2 = mUserManager.createUser("User 2", UserInfo.FLAG_RESTRICTED);
         int serialNumber2 = user2.serialNumber;
         assertFalse(serialNumber1 == serialNumber2);
         assertEquals(serialNumber2, mUserManager.getUserSerialNumber(user2.id));
         assertEquals(user2.id, mUserManager.getUserHandle(serialNumber2));
-        mUserManager.removeUser(user2.id);
+        removeUser(user2.id);
+    }
+
+    public void testMaxUsers() {
+        int N = UserManager.getMaxSupportedUsers();
+        int count = mUserManager.getUsers().size();
+        List<UserInfo> created = new ArrayList<UserInfo>();
+        // Create as many users as permitted and make sure creation passes
+        while (count < N) {
+            UserInfo ui = mUserManager.createUser("User " + count, 0);
+            assertNotNull(ui);
+            created.add(ui);
+            count++;
+        }
+        // Try to create one more user and make sure it fails
+        UserInfo extra = null;
+        assertNull(extra = mUserManager.createUser("One more", 0));
+        if (extra != null) {
+            removeUser(extra.id);
+        }
+        while (!created.isEmpty()) {
+            UserInfo user = created.remove(0);
+            removeUser(user.id);
+        }
+    }
+
+    private void removeUser(int userId) {
+        synchronized (mUserLock) {
+            mUserManager.removeUser(userId);
+            while (mUserManager.getUserInfo(userId) != null) {
+                try {
+                    mUserLock.wait(1000);
+                } catch (InterruptedException ie) {
+                }
+            }
+        }
     }
 }
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/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index 196bf2e..fd76fc8d 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -359,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;
@@ -458,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 */
@@ -699,6 +708,7 @@
                         addState(mDisconnectingState, mConnectModeState);
                         addState(mDisconnectedState, mConnectModeState);
                         addState(mWpsRunningState, mConnectModeState);
+                addState(mWaitForP2pDisableState, mSupplicantStartedState);
                 addState(mDriverStoppingState, mSupplicantStartedState);
                 addState(mDriverStoppedState, mSupplicantStartedState);
             addState(mSupplicantStoppingState, mDefaultState);
@@ -2433,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");
@@ -2443,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:
@@ -2838,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) {
@@ -2885,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;
         }
     }
 
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 4b90901..f0aef92 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pService.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pService.java
@@ -134,6 +134,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;
 
@@ -153,6 +156,8 @@
     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 */
@@ -574,19 +579,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;
@@ -689,6 +700,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) {
@@ -697,14 +715,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 {
@@ -728,9 +757,6 @@
                     mWifiMonitor.startMonitoring();
                     transitionTo(mP2pEnablingState);
                     break;
-                case WifiStateMachine.CMD_DISABLE_P2P:
-                    //Nothing to do
-                    break;
                 default:
                     return NOT_HANDLED;
             }
@@ -757,7 +783,7 @@
                     transitionTo(mP2pDisabledState);
                     break;
                 case WifiStateMachine.CMD_ENABLE_P2P:
-                case WifiStateMachine.CMD_DISABLE_P2P:
+                case WifiStateMachine.CMD_DISABLE_P2P_REQ:
                     deferMessage(message);
                     break;
                 default:
@@ -788,7 +814,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();
 
@@ -1439,6 +1465,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
@@ -1453,7 +1485,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();
@@ -1534,7 +1570,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;