Merge "More latency tests (1/2)"
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index ace4e32..ac8ee8d 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -981,7 +981,7 @@
             } else if (userId < 0) {
                 info = mUm.createUser(name, flags);
             } else {
-                info = mUm.createProfileForUser(name, flags, userId);
+                info = mUm.createProfileForUser(name, flags, userId, null);
             }
 
             if (info != null) {
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index 85a0403..6e2c464 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -32,6 +32,7 @@
 import android.content.Context;
 import android.content.ContextWrapper;
 import android.content.DialogInterface;
+import android.content.res.Configuration;
 import android.content.pm.ApplicationInfo;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
@@ -288,9 +289,14 @@
         }
 
         mCanceled = false;
-        
+
         if (!mCreated) {
             dispatchOnCreate(null);
+        } else {
+            // Fill the DecorView in on any configuration changes that
+            // may have occured while it was removed from the WindowManager.
+            final Configuration config = mContext.getResources().getConfiguration();
+            mWindow.getDecorView().dispatchConfigurationChanged(config);
         }
 
         onStart();
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index cd5eff2..5c9e2ee 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -895,6 +895,14 @@
         return false;
     }
 
+    /** @hide */
+    public boolean isBondingInitiatedLocally() {
+        try {
+            return sService.isBondingInitiatedLocally(this);
+        } catch (RemoteException e) {Log.e(TAG, "", e);}
+        return false;
+    }
+
     /**
      * Set the Out Of Band data for a remote device to be used later
      * in the pairing mechanism. Users can obtain this data through other
diff --git a/core/java/android/bluetooth/IBluetooth.aidl b/core/java/android/bluetooth/IBluetooth.aidl
index a420539..8c98536 100644
--- a/core/java/android/bluetooth/IBluetooth.aidl
+++ b/core/java/android/bluetooth/IBluetooth.aidl
@@ -62,6 +62,7 @@
     boolean cancelBondProcess(in BluetoothDevice device);
     boolean removeBond(in BluetoothDevice device);
     int getBondState(in BluetoothDevice device);
+    boolean isBondingInitiatedLocally(in BluetoothDevice device);
     int getConnectionState(in BluetoothDevice device);
 
     String getRemoteName(in BluetoothDevice device);
diff --git a/core/java/android/database/sqlite/SQLiteOpenHelper.java b/core/java/android/database/sqlite/SQLiteOpenHelper.java
index 2dd4800..bb8d9ff 100644
--- a/core/java/android/database/sqlite/SQLiteOpenHelper.java
+++ b/core/java/android/database/sqlite/SQLiteOpenHelper.java
@@ -20,6 +20,7 @@
 import android.database.DatabaseErrorHandler;
 import android.database.sqlite.SQLiteDatabase.CursorFactory;
 import android.util.Log;
+import java.io.File;
 
 /**
  * A helper class to manage database creation and version management.
@@ -54,6 +55,7 @@
     private final String mName;
     private final CursorFactory mFactory;
     private final int mNewVersion;
+    private final int mMinimumSupportedVersion;
 
     private SQLiteDatabase mDatabase;
     private boolean mIsInitializing;
@@ -96,6 +98,34 @@
      */
     public SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version,
             DatabaseErrorHandler errorHandler) {
+        this(context, name, factory, version, 0, errorHandler);
+    }
+
+    /**
+     * Same as {@link #SQLiteOpenHelper(Context, String, CursorFactory, int, DatabaseErrorHandler)}
+     * but also accepts an integer minimumSupportedVersion as a convenience for upgrading very old
+     * versions of this database that are no longer supported. If a database with older version that
+     * minimumSupportedVersion is found, it is simply deleted and a new database is created with the
+     * given name and version
+     *
+     * @param context to use to open or create the database
+     * @param name the name of the database file, null for a temporary in-memory database
+     * @param factory to use for creating cursor objects, null for default
+     * @param version the required version of the database
+     * @param minimumSupportedVersion the minimum version that is supported to be upgraded to
+     *            {@code version} via {@link #onUpgrade}. If the current database version is lower
+     *            than this, database is simply deleted and recreated with the version passed in
+     *            {@code version}. {@link #onBeforeDelete} is called before deleting the database
+     *            when this happens. This is 0 by default.
+     * @param errorHandler the {@link DatabaseErrorHandler} to be used when sqlite reports database
+     *            corruption, or null to use the default error handler.
+     * @see #onBeforeDelete(SQLiteDatabase)
+     * @see #SQLiteOpenHelper(Context, String, CursorFactory, int, DatabaseErrorHandler)
+     * @see #onUpgrade(SQLiteDatabase, int, int)
+     * @hide
+     */
+    public SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version,
+            int minimumSupportedVersion, DatabaseErrorHandler errorHandler) {
         if (version < 1) throw new IllegalArgumentException("Version must be >= 1, was " + version);
 
         mContext = context;
@@ -103,6 +133,7 @@
         mFactory = factory;
         mNewVersion = version;
         mErrorHandler = errorHandler;
+        mMinimumSupportedVersion = Math.max(0, minimumSupportedVersion);
     }
 
     /**
@@ -245,21 +276,34 @@
                             db.getVersion() + " to " + mNewVersion + ": " + mName);
                 }
 
-                db.beginTransaction();
-                try {
-                    if (version == 0) {
-                        onCreate(db);
+                if (version > 0 && version < mMinimumSupportedVersion) {
+                    File databaseFile = new File(db.getPath());
+                    onBeforeDelete(db);
+                    db.close();
+                    if (SQLiteDatabase.deleteDatabase(databaseFile)) {
+                        mIsInitializing = false;
+                        return getDatabaseLocked(writable);
                     } else {
-                        if (version > mNewVersion) {
-                            onDowngrade(db, version, mNewVersion);
-                        } else {
-                            onUpgrade(db, version, mNewVersion);
-                        }
+                        throw new IllegalStateException("Unable to delete obsolete database "
+                                + mName + " with version " + version);
                     }
-                    db.setVersion(mNewVersion);
-                    db.setTransactionSuccessful();
-                } finally {
-                    db.endTransaction();
+                } else {
+                    db.beginTransaction();
+                    try {
+                        if (version == 0) {
+                            onCreate(db);
+                        } else {
+                            if (version > mNewVersion) {
+                                onDowngrade(db, version, mNewVersion);
+                            } else {
+                                onUpgrade(db, version, mNewVersion);
+                            }
+                        }
+                        db.setVersion(mNewVersion);
+                        db.setTransactionSuccessful();
+                    } finally {
+                        db.endTransaction();
+                    }
                 }
             }
 
@@ -292,18 +336,18 @@
     }
 
     /**
-     * Called when the database connection is being configured, to enable features
-     * such as write-ahead logging or foreign key support.
+     * Called when the database connection is being configured, to enable features such as
+     * write-ahead logging or foreign key support.
      * <p>
-     * This method is called before {@link #onCreate}, {@link #onUpgrade},
-     * {@link #onDowngrade}, or {@link #onOpen} are called.  It should not modify
-     * the database except to configure the database connection as required.
-     * </p><p>
-     * This method should only call methods that configure the parameters of the
-     * database connection, such as {@link SQLiteDatabase#enableWriteAheadLogging}
-     * {@link SQLiteDatabase#setForeignKeyConstraintsEnabled},
-     * {@link SQLiteDatabase#setLocale}, {@link SQLiteDatabase#setMaximumSize},
-     * or executing PRAGMA statements.
+     * This method is called before {@link #onCreate}, {@link #onUpgrade}, {@link #onDowngrade}, or
+     * {@link #onOpen} are called. It should not modify the database except to configure the
+     * database connection as required.
+     * </p>
+     * <p>
+     * This method should only call methods that configure the parameters of the database
+     * connection, such as {@link SQLiteDatabase#enableWriteAheadLogging}
+     * {@link SQLiteDatabase#setForeignKeyConstraintsEnabled}, {@link SQLiteDatabase#setLocale},
+     * {@link SQLiteDatabase#setMaximumSize}, or executing PRAGMA statements.
      * </p>
      *
      * @param db The database.
@@ -311,6 +355,20 @@
     public void onConfigure(SQLiteDatabase db) {}
 
     /**
+     * Called before the database is deleted when the version returned by
+     * {@link SQLiteDatabase#getVersion()} is lower than the minimum supported version passed (if at
+     * all) while creating this helper. After the database is deleted, a fresh database with the
+     * given version is created. This will be followed by {@link #onConfigure(SQLiteDatabase)} and
+     * {@link #onCreate(SQLiteDatabase)} being called with a new SQLiteDatabase object
+     *
+     * @param db the database opened with this helper
+     * @see #SQLiteOpenHelper(Context, String, CursorFactory, int, int, DatabaseErrorHandler)
+     * @hide
+     */
+    public void onBeforeDelete(SQLiteDatabase db) {
+    }
+
+    /**
      * Called when the database is created for the first time. This is where the
      * creation of tables and the initial population of the tables should happen.
      *
diff --git a/core/java/android/net/metrics/DhcpErrorEvent.java b/core/java/android/net/metrics/DhcpErrorEvent.java
index 59c5fb6..c3abcf7 100644
--- a/core/java/android/net/metrics/DhcpErrorEvent.java
+++ b/core/java/android/net/metrics/DhcpErrorEvent.java
@@ -50,9 +50,13 @@
     public static final int DHCP_INVALID_OPTION_LENGTH = makeErrorCode(DHCP_ERROR, 3);
     public static final int DHCP_NO_MSG_TYPE           = makeErrorCode(DHCP_ERROR, 4);
     public static final int DHCP_UNKNOWN_MSG_TYPE      = makeErrorCode(DHCP_ERROR, 5);
+    /** {@hide} */
+    public static final int DHCP_NO_COOKIE             = makeErrorCode(DHCP_ERROR, 6);
 
     public static final int BUFFER_UNDERFLOW           = makeErrorCode(MISC_ERROR, 1);
     public static final int RECEIVE_ERROR              = makeErrorCode(MISC_ERROR, 2);
+    /** {@hide} */
+    public static final int PARSING_ERROR              = makeErrorCode(MISC_ERROR, 3);
 
     public final String ifName;
     // error code byte format (MSB to LSB):
@@ -115,8 +119,9 @@
     }
 
     final static class Decoder {
-        static final SparseArray<String> constants =
-                MessageUtils.findMessageNames(new Class[]{DhcpErrorEvent.class},
-                new String[]{"L2_", "L3_", "L4_", "BOOTP_", "DHCP_", "BUFFER_", "RECEIVE_"});
+        static final SparseArray<String> constants = MessageUtils.findMessageNames(
+                new Class[]{DhcpErrorEvent.class},
+                new String[]{"L2_", "L3_", "L4_", "BOOTP_", "DHCP_", "BUFFER_", "RECEIVE_",
+                "PARSING_"});
     }
 }
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index eeb641d..3324f6f 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -36,7 +36,8 @@
     int getCredentialOwnerProfile(int userHandle);
 
     UserInfo createUser(in String name, int flags);
-    UserInfo createProfileForUser(in String name, int flags, int userHandle);
+    UserInfo createProfileForUser(in String name, int flags, int userHandle,
+            in String[] disallowedPackages);
     UserInfo createRestrictedProfile(String name, int parentUserHandle);
     void setUserEnabled(int userHandle);
     boolean removeUser(int userHandle);
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 5dc18fb..c7e5e63 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -1340,15 +1340,34 @@
      *
      * @param name the user's name
      * @param flags flags that identify the type of user and other properties.
-     * @see UserInfo
-     * @param userHandle new user will be a profile of this use.
+     * @param userHandle new user will be a profile of this user.
      *
-     * @return the UserInfo object for the created user, or null if the user could not be created.
+     * @return the {@link UserInfo} object for the created user, or null if the user
+     *         could not be created.
      * @hide
      */
     public UserInfo createProfileForUser(String name, int flags, @UserIdInt int userHandle) {
+        return createProfileForUser(name, flags, userHandle, null);
+    }
+
+    /**
+     * Version of {@link #createProfileForUser(String, int, int)} that allows you to specify
+     * any packages that should not be installed in the new profile by default, these packages can
+     * still be installed later by the user if needed.
+     *
+     * @param name the user's name
+     * @param flags flags that identify the type of user and other properties.
+     * @param userHandle new user will be a profile of this user.
+     * @param disallowedPackages packages that will not be installed in the profile being created.
+     *
+     * @return the {@link UserInfo} object for the created user, or null if the user
+     *         could not be created.
+     * @hide
+     */
+    public UserInfo createProfileForUser(String name, int flags, @UserIdInt int userHandle,
+            String[] disallowedPackages) {
         try {
-            return mService.createProfileForUser(name, flags, userHandle);
+            return mService.createProfileForUser(name, flags, userHandle, disallowedPackages);
         } catch (RemoteException re) {
             throw re.rethrowFromSystemServer();
         }
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 0aa3a7e..b60e6b5 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -10787,7 +10787,7 @@
             }
 
             int NW = in.readInt();
-            if (NW > 100) {
+            if (NW > (MAX_WAKELOCKS_PER_UID+1)) {
                 throw new ParcelFormatException("File corrupt: too many wake locks " + NW);
             }
             for (int iw = 0; iw < NW; iw++) {
@@ -10796,7 +10796,7 @@
             }
 
             int NS = in.readInt();
-            if (NS > 100) {
+            if (NS > (MAX_WAKELOCKS_PER_UID+1)) {
                 throw new ParcelFormatException("File corrupt: too many syncs " + NS);
             }
             for (int is = 0; is < NS; is++) {
@@ -10805,7 +10805,7 @@
             }
 
             int NJ = in.readInt();
-            if (NJ > 100) {
+            if (NJ > (MAX_WAKELOCKS_PER_UID+1)) {
                 throw new ParcelFormatException("File corrupt: too many job timers " + NJ);
             }
             for (int ij = 0; ij < NJ; ij++) {
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 59a3563..12d4be3 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -476,11 +476,11 @@
      */
     private static PathClassLoader createSystemServerClassLoader(String systemServerClasspath,
                                                                  int targetSdkVersion) {
-      String librarySearchPath = System.getProperty("java.library.path");
+      String libraryPath = System.getProperty("java.library.path");
 
       return PathClassLoaderFactory.createClassLoader(systemServerClasspath,
-                                                      librarySearchPath,
-                                                      null /* libraryPermittedPath */,
+                                                      libraryPath,
+                                                      libraryPath,
                                                       ClassLoader.getSystemClassLoader(),
                                                       targetSdkVersion,
                                                       true /* isNamespaceShared */);
diff --git a/core/java/com/android/internal/widget/LockPatternChecker.java b/core/java/com/android/internal/widget/LockPatternChecker.java
index 3d43f5d..586ece0 100644
--- a/core/java/com/android/internal/widget/LockPatternChecker.java
+++ b/core/java/com/android/internal/widget/LockPatternChecker.java
@@ -4,6 +4,7 @@
 
 import com.android.internal.widget.LockPatternUtils.RequestThrottledException;
 
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -66,11 +67,19 @@
             final OnVerifyCallback callback) {
         AsyncTask<Void, Void, byte[]> task = new AsyncTask<Void, Void, byte[]>() {
             private int mThrottleTimeout;
+            private List<LockPatternView.Cell> patternCopy;
+
+            @Override
+            protected void onPreExecute() {
+                // Make a copy of the pattern to prevent race conditions.
+                // No need to clone the individual cells because they are immutable.
+                patternCopy = new ArrayList(pattern);
+            }
 
             @Override
             protected byte[] doInBackground(Void... args) {
                 try {
-                    return utils.verifyPattern(pattern, challenge, userId);
+                    return utils.verifyPattern(patternCopy, challenge, userId);
                 } catch (RequestThrottledException ex) {
                     mThrottleTimeout = ex.getTimeoutMs();
                     return null;
@@ -100,11 +109,19 @@
             final OnCheckCallback callback) {
         AsyncTask<Void, Void, Boolean> task = new AsyncTask<Void, Void, Boolean>() {
             private int mThrottleTimeout;
+            private List<LockPatternView.Cell> patternCopy;
+
+            @Override
+            protected void onPreExecute() {
+                // Make a copy of the pattern to prevent race conditions.
+                // No need to clone the individual cells because they are immutable.
+                patternCopy = new ArrayList(pattern);
+            }
 
             @Override
             protected Boolean doInBackground(Void... args) {
                 try {
-                    return utils.checkPattern(pattern, userId, callback::onEarlyMatched);
+                    return utils.checkPattern(patternCopy, userId, callback::onEarlyMatched);
                 } catch (RequestThrottledException ex) {
                     mThrottleTimeout = ex.getTimeoutMs();
                     return false;
diff --git a/core/jni/android_app_admin_SecurityLog.cpp b/core/jni/android_app_admin_SecurityLog.cpp
index da47c4c..e8ca793 100644
--- a/core/jni/android_app_admin_SecurityLog.cpp
+++ b/core/jni/android_app_admin_SecurityLog.cpp
@@ -19,7 +19,7 @@
 #include "JNIHelp.h"
 #include "core_jni_helpers.h"
 #include "jni.h"
-#include "log/logger.h"
+#include <private/android_logger.h>
 
 // The size of the tag number comes out of the payload size.
 #define MAX_EVENT_PAYLOAD (LOGGER_ENTRY_MAX_PAYLOAD - sizeof(int32_t))
diff --git a/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp b/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp
index ade718b..99a5fc7 100644
--- a/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp
+++ b/core/jni/android_graphics_drawable_AnimatedVectorDrawable.cpp
@@ -188,17 +188,20 @@
     {"nCreateAnimatorSet", "()J", (void*)createAnimatorSet},
     {"nSetVectorDrawableTarget", "(JJ)V", (void*)setVectorDrawableTarget},
     {"nAddAnimator", "(JJJJJII)V", (void*)addAnimator},
-    {"nCreateGroupPropertyHolder", "!(JIFF)J", (void*)createGroupPropertyHolder},
-    {"nCreatePathDataPropertyHolder", "!(JJJ)J", (void*)createPathDataPropertyHolder},
-    {"nCreatePathColorPropertyHolder", "!(JIII)J", (void*)createPathColorPropertyHolder},
-    {"nCreatePathPropertyHolder", "!(JIFF)J", (void*)createPathPropertyHolder},
-    {"nCreateRootAlphaPropertyHolder", "!(JFF)J", (void*)createRootAlphaPropertyHolder},
     {"nSetPropertyHolderData", "(J[FI)V", (void*)setFloatPropertyHolderData},
     {"nSetPropertyHolderData", "(J[II)V", (void*)setIntPropertyHolderData},
     {"nStart", "(JLandroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimatorRT;I)V", (void*)start},
     {"nReverse", "(JLandroid/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimatorRT;I)V", (void*)reverse},
-    {"nEnd", "!(J)V", (void*)end},
-    {"nReset", "!(J)V", (void*)reset},
+
+    // ------------- @FastNative -------------------
+
+    {"nCreateGroupPropertyHolder", "(JIFF)J", (void*)createGroupPropertyHolder},
+    {"nCreatePathDataPropertyHolder", "(JJJ)J", (void*)createPathDataPropertyHolder},
+    {"nCreatePathColorPropertyHolder", "(JIII)J", (void*)createPathColorPropertyHolder},
+    {"nCreatePathPropertyHolder", "(JIFF)J", (void*)createPathPropertyHolder},
+    {"nCreateRootAlphaPropertyHolder", "(JFF)J", (void*)createRootAlphaPropertyHolder},
+    {"nEnd", "(J)V", (void*)end},
+    {"nReset", "(J)V", (void*)reset},
 };
 
 const char* const kClassPathName = "android/graphics/drawable/AnimatedVectorDrawable$VectorDrawableAnimatorRT";
diff --git a/core/jni/android_graphics_drawable_VectorDrawable.cpp b/core/jni/android_graphics_drawable_VectorDrawable.cpp
index 045f127..e9ea702 100644
--- a/core/jni/android_graphics_drawable_VectorDrawable.cpp
+++ b/core/jni/android_graphics_drawable_VectorDrawable.cpp
@@ -350,64 +350,66 @@
 }
 
 static const JNINativeMethod gMethods[] = {
-        {"nCreateTree", "!(J)J", (void*)createTree},
-        {"nCreateTreeFromCopy", "!(JJ)J", (void*)createTreeFromCopy},
-        {"nSetRendererViewportSize", "!(JFF)V", (void*)setTreeViewportSize},
-        {"nSetRootAlpha", "!(JF)Z", (void*)setRootAlpha},
-        {"nGetRootAlpha", "!(J)F", (void*)getRootAlpha},
-        {"nSetAllowCaching", "!(JZ)V", (void*)setAllowCaching},
-
         {"nDraw", "(JJJLandroid/graphics/Rect;ZZ)I", (void*)draw},
-        {"nCreateFullPath", "!()J", (void*)createEmptyFullPath},
-        {"nCreateFullPath", "!(J)J", (void*)createFullPath},
-        {"nUpdateFullPathProperties", "!(JFIFIFFFFFIII)V", (void*)updateFullPathPropertiesAndStrokeStyles},
-        {"nUpdateFullPathFillGradient", "!(JJ)V", (void*)updateFullPathFillGradient},
-        {"nUpdateFullPathStrokeGradient", "!(JJ)V", (void*)updateFullPathStrokeGradient},
         {"nGetFullPathProperties", "(J[BI)Z", (void*)getFullPathProperties},
         {"nGetGroupProperties", "(J[FI)Z", (void*)getGroupProperties},
-
-        {"nCreateClipPath", "!()J", (void*)createEmptyClipPath},
-        {"nCreateClipPath", "!(J)J", (void*)createClipPath},
-        {"nCreateGroup", "!()J", (void*)createEmptyGroup},
-        {"nCreateGroup", "!(J)J", (void*)createGroup},
-        {"nSetName", "(JLjava/lang/String;)V", (void*)setNodeName},
-        {"nUpdateGroupProperties", "!(JFFFFFFF)V", (void*)updateGroupProperties},
-
-        {"nAddChild", "!(JJ)V", (void*)addChild},
         {"nSetPathString", "(JLjava/lang/String;I)V", (void*)setPathString},
+        {"nSetName", "(JLjava/lang/String;)V", (void*)setNodeName},
 
-        {"nGetRotation", "!(J)F", (void*)getRotation},
-        {"nSetRotation", "!(JF)V", (void*)setRotation},
-        {"nGetPivotX", "!(J)F", (void*)getPivotX},
-        {"nSetPivotX", "!(JF)V", (void*)setPivotX},
-        {"nGetPivotY", "!(J)F", (void*)getPivotY},
-        {"nSetPivotY", "!(JF)V", (void*)setPivotY},
-        {"nGetScaleX", "!(J)F", (void*)getScaleX},
-        {"nSetScaleX", "!(JF)V", (void*)setScaleX},
-        {"nGetScaleY", "!(J)F", (void*)getScaleY},
-        {"nSetScaleY", "!(JF)V", (void*)setScaleY},
-        {"nGetTranslateX", "!(J)F", (void*)getTranslateX},
-        {"nSetTranslateX", "!(JF)V", (void*)setTranslateX},
-        {"nGetTranslateY", "!(J)F", (void*)getTranslateY},
-        {"nSetTranslateY", "!(JF)V", (void*)setTranslateY},
+        // ------------- @FastNative ----------------
 
-        {"nSetPathData", "!(JJ)V", (void*)setPathData},
-        {"nGetStrokeWidth", "!(J)F", (void*)getStrokeWidth},
-        {"nSetStrokeWidth", "!(JF)V", (void*)setStrokeWidth},
-        {"nGetStrokeColor", "!(J)I", (void*)getStrokeColor},
-        {"nSetStrokeColor", "!(JI)V", (void*)setStrokeColor},
-        {"nGetStrokeAlpha", "!(J)F", (void*)getStrokeAlpha},
-        {"nSetStrokeAlpha", "!(JF)V", (void*)setStrokeAlpha},
-        {"nGetFillColor", "!(J)I", (void*)getFillColor},
-        {"nSetFillColor", "!(JI)V", (void*)setFillColor},
-        {"nGetFillAlpha", "!(J)F", (void*)getFillAlpha},
-        {"nSetFillAlpha", "!(JF)V", (void*)setFillAlpha},
-        {"nGetTrimPathStart", "!(J)F", (void*)getTrimPathStart},
-        {"nSetTrimPathStart", "!(JF)V", (void*)setTrimPathStart},
-        {"nGetTrimPathEnd", "!(J)F", (void*)getTrimPathEnd},
-        {"nSetTrimPathEnd", "!(JF)V", (void*)setTrimPathEnd},
-        {"nGetTrimPathOffset", "!(J)F", (void*)getTrimPathOffset},
-        {"nSetTrimPathOffset", "!(JF)V", (void*)setTrimPathOffset},
+        {"nCreateTree", "(J)J", (void*)createTree},
+        {"nCreateTreeFromCopy", "(JJ)J", (void*)createTreeFromCopy},
+        {"nSetRendererViewportSize", "(JFF)V", (void*)setTreeViewportSize},
+        {"nSetRootAlpha", "(JF)Z", (void*)setRootAlpha},
+        {"nGetRootAlpha", "(J)F", (void*)getRootAlpha},
+        {"nSetAllowCaching", "(JZ)V", (void*)setAllowCaching},
+
+        {"nCreateFullPath", "()J", (void*)createEmptyFullPath},
+        {"nCreateFullPath", "(J)J", (void*)createFullPath},
+        {"nUpdateFullPathProperties", "(JFIFIFFFFFIII)V", (void*)updateFullPathPropertiesAndStrokeStyles},
+        {"nUpdateFullPathFillGradient", "(JJ)V", (void*)updateFullPathFillGradient},
+        {"nUpdateFullPathStrokeGradient", "(JJ)V", (void*)updateFullPathStrokeGradient},
+
+        {"nCreateClipPath", "()J", (void*)createEmptyClipPath},
+        {"nCreateClipPath", "(J)J", (void*)createClipPath},
+        {"nCreateGroup", "()J", (void*)createEmptyGroup},
+        {"nCreateGroup", "(J)J", (void*)createGroup},
+        {"nUpdateGroupProperties", "(JFFFFFFF)V", (void*)updateGroupProperties},
+
+        {"nAddChild", "(JJ)V", (void*)addChild},
+        {"nGetRotation", "(J)F", (void*)getRotation},
+        {"nSetRotation", "(JF)V", (void*)setRotation},
+        {"nGetPivotX", "(J)F", (void*)getPivotX},
+        {"nSetPivotX", "(JF)V", (void*)setPivotX},
+        {"nGetPivotY", "(J)F", (void*)getPivotY},
+        {"nSetPivotY", "(JF)V", (void*)setPivotY},
+        {"nGetScaleX", "(J)F", (void*)getScaleX},
+        {"nSetScaleX", "(JF)V", (void*)setScaleX},
+        {"nGetScaleY", "(J)F", (void*)getScaleY},
+        {"nSetScaleY", "(JF)V", (void*)setScaleY},
+        {"nGetTranslateX", "(J)F", (void*)getTranslateX},
+        {"nSetTranslateX", "(JF)V", (void*)setTranslateX},
+        {"nGetTranslateY", "(J)F", (void*)getTranslateY},
+        {"nSetTranslateY", "(JF)V", (void*)setTranslateY},
+
+        {"nSetPathData", "(JJ)V", (void*)setPathData},
+        {"nGetStrokeWidth", "(J)F", (void*)getStrokeWidth},
+        {"nSetStrokeWidth", "(JF)V", (void*)setStrokeWidth},
+        {"nGetStrokeColor", "(J)I", (void*)getStrokeColor},
+        {"nSetStrokeColor", "(JI)V", (void*)setStrokeColor},
+        {"nGetStrokeAlpha", "(J)F", (void*)getStrokeAlpha},
+        {"nSetStrokeAlpha", "(JF)V", (void*)setStrokeAlpha},
+        {"nGetFillColor", "(J)I", (void*)getFillColor},
+        {"nSetFillColor", "(JI)V", (void*)setFillColor},
+        {"nGetFillAlpha", "(J)F", (void*)getFillAlpha},
+        {"nSetFillAlpha", "(JF)V", (void*)setFillAlpha},
+        {"nGetTrimPathStart", "(J)F", (void*)getTrimPathStart},
+        {"nSetTrimPathStart", "(JF)V", (void*)setTrimPathStart},
+        {"nGetTrimPathEnd", "(J)F", (void*)getTrimPathEnd},
+        {"nSetTrimPathEnd", "(JF)V", (void*)setTrimPathEnd},
+        {"nGetTrimPathOffset", "(J)F", (void*)getTrimPathOffset},
+        {"nSetTrimPathOffset", "(JF)V", (void*)setTrimPathOffset},
 };
 
 int register_android_graphics_drawable_VectorDrawable(JNIEnv* env) {
diff --git a/core/jni/android_util_EventLog.cpp b/core/jni/android_util_EventLog.cpp
index 4f8a2cb..173afd8 100644
--- a/core/jni/android_util_EventLog.cpp
+++ b/core/jni/android_util_EventLog.cpp
@@ -19,7 +19,7 @@
 #include "JNIHelp.h"
 #include "core_jni_helpers.h"
 #include "jni.h"
-#include "log/logger.h"
+#include <log/logger.h>
 
 #define UNUSED  __attribute__((__unused__))
 
diff --git a/core/res/res/color/background_cache_hint_selector_device_default.xml b/core/res/res/color/background_cache_hint_selector_device_default.xml
deleted file mode 100644
index 3cb4bbc..0000000
--- a/core/res/res/color/background_cache_hint_selector_device_default.xml
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 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.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_accelerated="false" android:color="?attr/colorBackground" />
-    <item android:color="@android:color/transparent" />
-</selector>
diff --git a/core/res/res/values-watch/themes_device_defaults.xml b/core/res/res/values-watch/themes_device_defaults.xml
index 0471444..2313b26 100644
--- a/core/res/res/values-watch/themes_device_defaults.xml
+++ b/core/res/res/values-watch/themes_device_defaults.xml
@@ -32,12 +32,12 @@
  -->
 <resources>
     <!-- Theme used for the intent picker activity. -->
-    <style name="Theme.DeviceDefault.Resolver" parent="Theme.DeviceDefault">
+    <style name="Theme.DeviceDefault.Resolver" parent="Theme.Material">
         <item name="colorControlActivated">?attr/colorControlHighlight</item>
         <item name="listPreferredItemPaddingStart">?attr/dialogPreferredPadding</item>
         <item name="listPreferredItemPaddingEnd">?attr/dialogPreferredPadding</item>
     </style>
 
     <!-- Use a dark theme for watches. -->
-    <style name="Theme.DeviceDefault.System" />
+    <style name="Theme.DeviceDefault.System" parent="Theme.Material" />
 </resources>
diff --git a/core/res/res/values/colors_device_defaults.xml b/core/res/res/values/colors_device_defaults.xml
index 171f5cb..89691e9 100644
--- a/core/res/res/values/colors_device_defaults.xml
+++ b/core/res/res/values/colors_device_defaults.xml
@@ -37,6 +37,4 @@
     <color name="background_device_default_light">@color/background_material_light</color>
     <color name="background_floating_device_default_dark">@color/background_floating_material_dark</color>
     <color name="background_floating_device_default_light">@color/background_floating_material_light</color>
-    <color name="button_normal_device_default_dark">@color/btn_default_material_dark</color>
-    <color name="button_normal_device_default_light">@color/btn_default_material_light</color>
 </resources>
diff --git a/core/res/res/values/themes_device_defaults.xml b/core/res/res/values/themes_device_defaults.xml
index 4be45e9..0e98ade 100644
--- a/core/res/res/values/themes_device_defaults.xml
+++ b/core/res/res/values/themes_device_defaults.xml
@@ -203,42 +203,45 @@
         <item name="colorPrimary">@color/primary_device_default_dark</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
         <item name="colorAccent">@color/accent_device_default_dark</item>
-        <item name="colorBackground">@color/background_device_default_dark</item>
-        <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
-        <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item>
-        <item name="colorButtonNormal">@color/button_normal_device_default_dark</item>
+
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault} with no action bar -->
-    <style name="Theme.DeviceDefault.NoActionBar">
-        <item name="windowActionBar">false</item>
-        <item name="windowNoTitle">true</item>
+    <style name="Theme.DeviceDefault.NoActionBar" parent="Theme.Material.NoActionBar">
+        <!-- Color palette -->
+        <item name="colorPrimary">@color/primary_device_default_dark</item>
+        <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
+        <item name="colorAccent">@color/accent_device_default_dark</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault} with no action bar and no status bar.  This theme
          sets {@link android.R.attr#windowFullscreen} to true.  -->
-    <style name="Theme.DeviceDefault.NoActionBar.Fullscreen">
-        <item name="windowFullscreen">true</item>
-        <item name="windowContentOverlay">@null</item>
+    <style name="Theme.DeviceDefault.NoActionBar.Fullscreen" parent="Theme.Material.NoActionBar.Fullscreen">
+        <!-- Color palette -->
+        <item name="colorPrimary">@color/primary_device_default_dark</item>
+        <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
+        <item name="colorAccent">@color/accent_device_default_dark</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault} with no action bar and no status bar and
     extending in to overscan region.  This theme
     sets {@link android.R.attr#windowFullscreen} and {@link android.R.attr#windowOverscan}
     to true. -->
-    <style name="Theme.DeviceDefault.NoActionBar.Overscan">
-        <item name="windowFullscreen">true</item>
-        <item name="windowOverscan">true</item>
-        <item name="windowContentOverlay">@null</item>
+    <style name="Theme.DeviceDefault.NoActionBar.Overscan" parent="Theme.Material.NoActionBar.Overscan">
+        <!-- Color palette -->
+        <item name="colorPrimary">@color/primary_device_default_dark</item>
+        <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
+        <item name="colorAccent">@color/accent_device_default_dark</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault} that has no title bar and translucent
          system decor.  This theme sets {@link android.R.attr#windowTranslucentStatus} and
          {@link android.R.attr#windowTranslucentNavigation} to true. -->
-    <style name="Theme.DeviceDefault.NoActionBar.TranslucentDecor">
-        <item name="windowTranslucentStatus">true</item>
-        <item name="windowTranslucentNavigation">true</item>
-        <item name="windowContentOverlay">@null</item>
+    <style name="Theme.DeviceDefault.NoActionBar.TranslucentDecor" parent="Theme.Material.NoActionBar.TranslucentDecor">
+        <!-- Color palette -->
+        <item name="colorPrimary">@color/primary_device_default_dark</item>
+        <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
+        <item name="colorAccent">@color/accent_device_default_dark</item>
     </style>
 
     <!-- DeviceDefault theme for dialog windows and activities. This changes the window to be
@@ -258,30 +261,32 @@
         <item name="colorPrimary">@color/primary_device_default_dark</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
         <item name="colorAccent">@color/accent_device_default_dark</item>
-        <item name="colorBackground">@color/background_floating_device_default_dark</item>
-        <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
-        <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item>
-        <item name="colorButtonNormal">@color/button_normal_device_default_dark</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Dialog} that has a nice minimum width for a
     regular dialog. -->
-    <style name="Theme.DeviceDefault.Dialog.MinWidth">
-        <item name="windowMinWidthMajor">@dimen/dialog_min_width_major</item>
-        <item name="windowMinWidthMinor">@dimen/dialog_min_width_minor</item>
+    <style name="Theme.DeviceDefault.Dialog.MinWidth" parent="Theme.Material.Dialog.MinWidth">
+        <!-- Color palette -->
+        <item name="colorPrimary">@color/primary_device_default_dark</item>
+        <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
+        <item name="colorAccent">@color/accent_device_default_dark</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Dialog} without an action bar -->
-    <style name="Theme.DeviceDefault.Dialog.NoActionBar">
-        <item name="windowActionBar">false</item>
-        <item name="windowNoTitle">true</item>
+    <style name="Theme.DeviceDefault.Dialog.NoActionBar" parent="Theme.Material.Dialog.NoActionBar">
+        <!-- Color palette -->
+        <item name="colorPrimary">@color/primary_device_default_dark</item>
+        <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
+        <item name="colorAccent">@color/accent_device_default_dark</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Dialog_NoActionBar} that has a nice minimum width
     for a regular dialog. -->
-    <style name="Theme.DeviceDefault.Dialog.NoActionBar.MinWidth">
-        <item name="windowMinWidthMajor">@dimen/dialog_min_width_major</item>
-        <item name="windowMinWidthMinor">@dimen/dialog_min_width_minor</item>
+    <style name="Theme.DeviceDefault.Dialog.NoActionBar.MinWidth" parent="Theme.Material.Dialog.NoActionBar.MinWidth">
+        <!-- Color palette -->
+        <item name="colorPrimary">@color/primary_device_default_dark</item>
+        <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
+        <item name="colorAccent">@color/accent_device_default_dark</item>
     </style>
 
     <!-- Variant of Theme.DeviceDefault.Dialog that has a fixed size. -->
@@ -302,68 +307,92 @@
 
     <!-- DeviceDefault theme for a window that will be displayed either full-screen on smaller
     screens (small, normal) or as a dialog on larger screens (large, xlarge). -->
-    <style name="Theme.DeviceDefault.DialogWhenLarge" parent="@style/Theme.DeviceDefault" />
+    <style name="Theme.DeviceDefault.DialogWhenLarge" parent="Theme.Material.DialogWhenLarge">
+        <!-- Color palette -->
+        <item name="colorPrimary">@color/primary_device_default_dark</item>
+        <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
+        <item name="colorAccent">@color/accent_device_default_dark</item>
+    </style>
 
     <!-- DeviceDefault theme for a window without an action bar that will be displayed either
     full-screen on smaller screens (small, normal) or as a dialog on larger screens (large,
     xlarge). -->
-    <style name="Theme.DeviceDefault.DialogWhenLarge.NoActionBar" parent="@style/Theme.DeviceDefault.NoActionBar" />
+    <style name="Theme.DeviceDefault.DialogWhenLarge.NoActionBar" parent="Theme.Material.DialogWhenLarge.NoActionBar">
+        <!-- Color palette -->
+        <item name="colorPrimary">@color/primary_device_default_dark</item>
+        <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
+        <item name="colorAccent">@color/accent_device_default_dark</item>
+    </style>
 
     <!-- DeviceDefault theme for a presentation window on a secondary display. -->
-    <style name="Theme.DeviceDefault.Dialog.Presentation" parent="@style/Theme.DeviceDefault.NoActionBar.Fullscreen" />
+    <style name="Theme.DeviceDefault.Dialog.Presentation" parent="Theme.Material.Dialog.Presentation">
+        <!-- Color palette -->
+        <item name="colorPrimary">@color/primary_device_default_dark</item>
+        <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
+        <item name="colorAccent">@color/accent_device_default_dark</item>
+    </style>
 
     <!-- DeviceDefault theme for panel windows. This removes all extraneous window
     decorations, so you basically have an empty rectangle in which to place your content. It makes
     the window floating, with a transparent background, and turns off dimming behind the window. -->
-    <style name="Theme.DeviceDefault.Panel">
-        <item name="windowBackground">@color/transparent</item>
-        <item name="colorBackgroundCacheHint">@null</item>
-        <item name="windowFrame">@null</item>
-        <item name="windowContentOverlay">@null</item>
-        <item name="windowAnimationStyle">@null</item>
-        <item name="windowIsFloating">true</item>
-        <item name="backgroundDimEnabled">false</item>
-        <item name="windowIsTranslucent">true</item>
-        <item name="windowNoTitle">true</item>
+    <style name="Theme.DeviceDefault.Panel" parent="Theme.Material.Panel">
+        <!-- Color palette -->
+        <item name="colorPrimary">@color/primary_device_default_dark</item>
+        <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
+        <item name="colorAccent">@color/accent_device_default_dark</item>
     </style>
 
     <!-- DeviceDefault theme for windows that want to have the user's selected wallpaper appear
     behind them. -->
-    <style name="Theme.DeviceDefault.Wallpaper">
-        <item name="windowBackground">@color/transparent</item>
-        <item name="colorBackgroundCacheHint">@null</item>
-        <item name="windowShowWallpaper">true</item>
+    <style name="Theme.DeviceDefault.Wallpaper" parent="Theme.Material.Wallpaper">
+        <!-- Color palette -->
+        <item name="colorPrimary">@color/primary_device_default_dark</item>
+        <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
+        <item name="colorAccent">@color/accent_device_default_dark</item>
     </style>
 
     <!-- DeviceDefault theme for windows that want to have the user's selected wallpaper appear
     behind them and without an action bar. -->
-    <style name="Theme.DeviceDefault.Wallpaper.NoTitleBar">
-        <item name="windowNoTitle">true</item>
+    <style name="Theme.DeviceDefault.Wallpaper.NoTitleBar" parent="Theme.Material.Wallpaper.NoTitleBar">
+        <!-- Color palette -->
+        <item name="colorPrimary">@color/primary_device_default_dark</item>
+        <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
+        <item name="colorAccent">@color/accent_device_default_dark</item>
     </style>
 
     <!-- DeviceDefault style for input methods, which is used by the
          {@link android.inputmethodservice.InputMethodService} class.-->
-    <style name="Theme.DeviceDefault.InputMethod">
-        <item name="windowAnimationStyle">@style/Animation.InputMethod</item>
-        <item name="imeFullscreenBackground">@drawable/screen_background_selector_light</item>
-        <item name="imeExtractEnterAnimation">@anim/input_method_extract_enter</item>
-        <item name="imeExtractExitAnimation">@anim/input_method_extract_exit</item>
-    </style>
-
-    <!-- DeviceDefault style for input methods, which is used by the
-         {@link android.service.voice.VoiceInteractionSession} class.-->
-    <style name="Theme.DeviceDefault.VoiceInteractionSession" parent="Theme.Material.VoiceInteractionSession">
+    <style name="Theme.DeviceDefault.InputMethod" parent="Theme.Material.InputMethod">
+        <!-- Color palette -->
         <item name="colorPrimary">@color/primary_device_default_light</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
     </style>
 
-    <style name="Theme.DeviceDefault.Dialog.Alert">
-        <item name="windowMinWidthMajor">@dimen/dialog_min_width_major</item>
-        <item name="windowMinWidthMinor">@dimen/dialog_min_width_minor</item>
+    <!-- DeviceDefault style for input methods, which is used by the
+         {@link android.service.voice.VoiceInteractionSession} class.-->
+    <style name="Theme.DeviceDefault.VoiceInteractionSession" parent="Theme.Material.VoiceInteractionSession">
+        <!-- Color palette -->
+        <item name="colorPrimary">@color/primary_device_default_light</item>
+        <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
+        <item name="colorAccent">@color/accent_device_default_light</item>
     </style>
 
-    <style name="Theme.DeviceDefault.SearchBar" parent="Theme.DeviceDefault.Panel"/>
+    <style name="Theme.DeviceDefault.Dialog.Alert" parent="Theme.Material.Dialog.Alert">
+        <item name="windowTitleStyle">@style/DialogWindowTitle.DeviceDefault</item>
+
+        <!-- Color palette -->
+        <item name="colorPrimary">@color/primary_device_default_dark</item>
+        <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
+        <item name="colorAccent">@color/accent_device_default_dark</item>
+    </style>
+
+    <style name="Theme.DeviceDefault.SearchBar" parent="Theme.Material.SearchBar">
+        <!-- Color palette -->
+        <item name="colorPrimary">@color/primary_device_default_dark</item>
+        <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
+        <item name="colorAccent">@color/accent_device_default_dark</item>
+    </style>
 
     <style name="Theme.DeviceDefault.Dialog.NoFrame" parent="Theme.Material.Dialog.NoFrame">
         <!-- Color palette -->
@@ -522,59 +551,53 @@
         <item name="colorPrimary">@color/primary_device_default_light</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
-        <item name="colorBackground">@color/background_device_default_light</item>
-        <item name="colorBackgroundFloating">@color/background_floating_device_default_light</item>
-        <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item>
-        <item name="colorButtonNormal">@color/button_normal_device_default_light</item>
     </style>
 
     <!-- Variant of the DeviceDefault (light) theme that has a solid (opaque) action bar with an
     inverse color profile. -->
-    <style name="Theme.DeviceDefault.Light.DarkActionBar">
-        <item name="actionBarWidgetTheme">@null</item>
-        <item name="actionBarTheme">@style/ThemeOverlay.Material.Dark.ActionBar</item>
-        <item name="popupTheme">@style/ThemeOverlay.Material.Light</item>
-
+    <style name="Theme.DeviceDefault.Light.DarkActionBar" parent="Theme.Material.Light.DarkActionBar">
         <!-- Color palette -->
         <item name="colorPrimary">@color/primary_device_default_dark</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_dark</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
-        <item name="colorBackground">@color/background_device_default_dark</item>
-        <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
-        <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item>
-        <item name="colorButtonNormal">@color/button_normal_device_default_dark</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar -->
-    <style name="Theme.DeviceDefault.Light.NoActionBar">
-        <item name="windowActionBar">false</item>
-        <item name="windowNoTitle">true</item>
+    <style name="Theme.DeviceDefault.Light.NoActionBar" parent="Theme.Material.Light.NoActionBar">
+        <!-- Color palette -->
+        <item name="colorPrimary">@color/primary_device_default_light</item>
+        <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
+        <item name="colorAccent">@color/accent_device_default_light</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar and no status bar.
          This theme sets {@link android.R.attr#windowFullscreen} to true.  -->
-    <style name="Theme.DeviceDefault.Light.NoActionBar.Fullscreen">
-        <item name="windowFullscreen">true</item>
-        <item name="windowContentOverlay">@null</item>
+    <style name="Theme.DeviceDefault.Light.NoActionBar.Fullscreen" parent="Theme.Material.Light.NoActionBar.Fullscreen">
+        <!-- Color palette -->
+        <item name="colorPrimary">@color/primary_device_default_light</item>
+        <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
+        <item name="colorAccent">@color/accent_device_default_light</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Light} with no action bar and no status bar
     and extending in to overscan region.  This theme
     sets {@link android.R.attr#windowFullscreen} and {@link android.R.attr#windowOverscan}
     to true. -->
-    <style name="Theme.DeviceDefault.Light.NoActionBar.Overscan">
-        <item name="windowFullscreen">true</item>
-        <item name="windowOverscan">true</item>
-        <item name="windowContentOverlay">@null</item>
+    <style name="Theme.DeviceDefault.Light.NoActionBar.Overscan" parent="Theme.Material.Light.NoActionBar.Overscan">
+        <!-- Color palette -->
+        <item name="colorPrimary">@color/primary_device_default_light</item>
+        <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
+        <item name="colorAccent">@color/accent_device_default_light</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Light} that has no title bar and translucent
          system decor.  This theme sets {@link android.R.attr#windowTranslucentStatus} and
          {@link android.R.attr#windowTranslucentNavigation} to true. -->
-    <style name="Theme.DeviceDefault.Light.NoActionBar.TranslucentDecor">
-        <item name="windowTranslucentStatus">true</item>
-        <item name="windowTranslucentNavigation">true</item>
-        <item name="windowContentOverlay">@null</item>
+    <style name="Theme.DeviceDefault.Light.NoActionBar.TranslucentDecor" parent="Theme.Material.Light.NoActionBar.TranslucentDecor">
+        <!-- Color palette -->
+        <item name="colorPrimary">@color/primary_device_default_light</item>
+        <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
+        <item name="colorAccent">@color/accent_device_default_light</item>
     </style>
 
     <!-- DeviceDefault light theme for dialog windows and activities. This changes the window to be
@@ -594,30 +617,32 @@
         <item name="colorPrimary">@color/primary_device_default_light</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
         <item name="colorAccent">@color/accent_device_default_light</item>
-        <item name="colorBackground">@color/background_device_default_dark</item>
-        <item name="colorBackgroundFloating">@color/background_floating_device_default_dark</item>
-        <item name="colorBackgroundCacheHint">@color/background_cache_hint_selector_device_default</item>
-        <item name="colorButtonNormal">@color/button_normal_device_default_light</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog} that has a nice minimum width for a
     regular dialog. -->
-    <style name="Theme.DeviceDefault.Light.Dialog.MinWidth">
-        <item name="windowMinWidthMajor">@dimen/dialog_min_width_major</item>
-        <item name="windowMinWidthMinor">@dimen/dialog_min_width_minor</item>
+    <style name="Theme.DeviceDefault.Light.Dialog.MinWidth" parent="Theme.Material.Light.Dialog.MinWidth">
+        <!-- Color palette -->
+        <item name="colorPrimary">@color/primary_device_default_light</item>
+        <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
+        <item name="colorAccent">@color/accent_device_default_light</item>
     </style>
 
      <!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog} without an action bar -->
-    <style name="Theme.DeviceDefault.Light.Dialog.NoActionBar">
-        <item name="windowActionBar">false</item>
-        <item name="windowNoTitle">true</item>
+    <style name="Theme.DeviceDefault.Light.Dialog.NoActionBar" parent="Theme.Material.Light.Dialog.NoActionBar">
+        <!-- Color palette -->
+        <item name="colorPrimary">@color/primary_device_default_light</item>
+        <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
+        <item name="colorAccent">@color/accent_device_default_light</item>
     </style>
 
     <!-- Variant of {@link #Theme_DeviceDefault_Light_Dialog_NoActionBar} that has a nice minimum
     width for a regular dialog. -->
-    <style name="Theme.DeviceDefault.Light.Dialog.NoActionBar.MinWidth">
-        <item name="windowMinWidthMajor">@dimen/dialog_min_width_major</item>
-        <item name="windowMinWidthMinor">@dimen/dialog_min_width_minor</item>
+    <style name="Theme.DeviceDefault.Light.Dialog.NoActionBar.MinWidth" parent="Theme.Material.Light.Dialog.NoActionBar.MinWidth">
+        <!-- Color palette -->
+        <item name="colorPrimary">@color/primary_device_default_light</item>
+        <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
+        <item name="colorAccent">@color/accent_device_default_light</item>
     </style>
 
     <!-- Variant of Theme.DeviceDefault.Dialog that has a fixed size. -->
@@ -626,6 +651,11 @@
         <item name="windowFixedWidthMinor">@dimen/dialog_fixed_width_minor</item>
         <item name="windowFixedHeightMajor">@dimen/dialog_fixed_height_major</item>
         <item name="windowFixedHeightMinor">@dimen/dialog_fixed_height_minor</item>
+
+        <!-- Color palette -->
+        <item name="colorPrimary">@color/primary_device_default_light</item>
+        <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
+        <item name="colorAccent">@color/accent_device_default_light</item>
     </style>
 
     <!-- Variant of Theme.DeviceDefault.Dialog.NoActionBar that has a fixed size. -->
@@ -634,78 +664,128 @@
         <item name="windowFixedWidthMinor">@dimen/dialog_fixed_width_minor</item>
         <item name="windowFixedHeightMajor">@dimen/dialog_fixed_height_major</item>
         <item name="windowFixedHeightMinor">@dimen/dialog_fixed_height_minor</item>
+
+        <!-- Color palette -->
+        <item name="colorPrimary">@color/primary_device_default_light</item>
+        <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
+        <item name="colorAccent">@color/accent_device_default_light</item>
     </style>
 
     <!-- DeviceDefault light theme for a window that will be displayed either full-screen on smaller
     screens (small, normal) or as a dialog on larger screens (large, xlarge). -->
-    <style name="Theme.DeviceDefault.Light.DialogWhenLarge" parent="@style/Theme.DeviceDefault.Light" />
+    <style name="Theme.DeviceDefault.Light.DialogWhenLarge" parent="Theme.Material.Light.DialogWhenLarge">
+        <!-- Color palette -->
+        <item name="colorPrimary">@color/primary_device_default_light</item>
+        <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
+        <item name="colorAccent">@color/accent_device_default_light</item>
+    </style>
 
     <!-- DeviceDefault light theme for a window without an action bar that will be displayed either
     full-screen on smaller screens (small, normal) or as a dialog on larger screens (large,
     xlarge). -->
-    <style name="Theme.DeviceDefault.Light.DialogWhenLarge.NoActionBar" parent="@style/Theme.DeviceDefault.Light.NoActionBar" />
+    <style name="Theme.DeviceDefault.Light.DialogWhenLarge.NoActionBar" parent="Theme.Material.Light.DialogWhenLarge.NoActionBar">
+        <!-- Color palette -->
+        <item name="colorPrimary">@color/primary_device_default_light</item>
+        <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
+        <item name="colorAccent">@color/accent_device_default_light</item>
+    </style>
 
     <!-- DeviceDefault light theme for a presentation window on a secondary display. -->
-    <style name="Theme.DeviceDefault.Light.Dialog.Presentation" parent="@style/Theme.DeviceDefault.Light.NoActionBar.Fullscreen" />
+    <style name="Theme.DeviceDefault.Light.Dialog.Presentation" parent="Theme.Material.Light.Dialog.Presentation">
+        <!-- Color palette -->
+        <item name="colorPrimary">@color/primary_device_default_light</item>
+        <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
+        <item name="colorAccent">@color/accent_device_default_light</item>
+    </style>
 
     <!-- DeviceDefault light theme for panel windows. This removes all extraneous window
     decorations, so you basically have an empty rectangle in which to place your content. It makes
     the window floating, with a transparent background, and turns off dimming behind the window. -->
     <style name="Theme.DeviceDefault.Light.Panel" parent="Theme.Material.Light.Panel">
-        <item name="windowBackground">@color/transparent</item>
-        <item name="colorBackgroundCacheHint">@null</item>
-        <item name="windowFrame">@null</item>
-        <item name="windowContentOverlay">@null</item>
-        <item name="windowAnimationStyle">@null</item>
-        <item name="windowIsFloating">true</item>
-        <item name="backgroundDimEnabled">false</item>
-        <item name="windowIsTranslucent">true</item>
-        <item name="windowNoTitle">true</item>
+        <!-- Color palette -->
+        <item name="colorPrimary">@color/primary_device_default_light</item>
+        <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
+        <item name="colorAccent">@color/accent_device_default_light</item>
     </style>
 
-    <style name="Theme.DeviceDefault.Light.Dialog.Alert">
-        <item name="windowMinWidthMajor">@dimen/dialog_min_width_major</item>
-        <item name="windowMinWidthMinor">@dimen/dialog_min_width_minor</item>
+    <style name="Theme.DeviceDefault.Light.Dialog.Alert" parent="Theme.Material.Light.Dialog.Alert">
+        <item name="windowTitleStyle">@style/DialogWindowTitle.DeviceDefault.Light</item>
+
+        <!-- Color palette -->
+        <item name="colorPrimary">@color/primary_device_default_light</item>
+        <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
+        <item name="colorAccent">@color/accent_device_default_light</item>
     </style>
 
-    <style name="Theme.DeviceDefault.Light.SearchBar" parent="@style/Theme.DeviceDefault.Light.Panel"/>
+    <style name="Theme.DeviceDefault.Light.SearchBar" parent="Theme.Material.Light.SearchBar">
+        <!-- Color palette -->
+        <item name="colorPrimary">@color/primary_device_default_light</item>
+        <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
+        <item name="colorAccent">@color/accent_device_default_light</item>
+    </style>
 
-    <style name="Theme.DeviceDefault.Light.Voice" parent="@style/Theme.DeviceDefault.Light.Dialog">
-        <item name="windowAnimationStyle">@style/Animation.VoiceActivity</item>
-        <item name="backgroundDimEnabled">false</item>
+    <style name="Theme.DeviceDefault.Light.Voice" parent="Theme.Material.Light.Voice">
+        <!-- Color palette -->
+        <item name="colorPrimary">@color/primary_device_default_light</item>
+        <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
+        <item name="colorAccent">@color/accent_device_default_light</item>
     </style>
 
     <!-- DeviceDefault theme for a window that should look like the Settings app.  -->
-    <style name="Theme.DeviceDefault.Settings" parent="Theme.DeviceDefault.Light.DarkActionBar">
-        <item name="presentationTheme">@style/Theme.Material.Settings.Dialog.Presentation</item>
-        <item name="searchDialogTheme">@style/Theme.Material.Settings.SearchBar</item>
-        <item name="panelMenuListTheme">@style/Theme.Material.Settings.CompactMenu</item>
+    <style name="Theme.DeviceDefault.Settings" parent="Theme.Material.Settings">
+        <!-- Color palette -->
+        <item name="colorPrimary">@color/primary_device_default_settings</item>
+        <item name="colorPrimaryDark">@color/primary_dark_device_default_settings</item>
+        <item name="colorSecondary">@color/secondary_device_default_settings</item>
+        <item name="colorAccent">@color/accent_device_default_light</item>
     </style>
 
     <!-- DeviceDefault theme for a window that should use Settings theme colors but has
          a full dark palette (instead of Light with dark action bar like
          Theme.DeviceDefault.Settings.  -->
-    <style name="Theme.DeviceDefault.Settings.Dark" parent="Theme.DeviceDefault"/>
-
-    <!-- Variant of {@link #Theme_DeviceDefault_Settings_Dark} with no action bar -->
-    <style name="Theme.DeviceDefault.Settings.Dark.NoActionBar" parent="Theme.DeviceDefault.NoActionBar"/>
-
-    <style name="Theme.DeviceDefault.Settings.Dialog" parent="Theme.DeviceDefault.Light.Dialog">
+    <style name="Theme.DeviceDefault.Settings.Dark" parent="Theme.Material">
+        <!-- Color palette -->
         <item name="colorPrimary">@color/primary_device_default_settings</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_settings</item>
         <item name="colorSecondary">@color/secondary_device_default_settings</item>
+        <item name="colorAccent">@color/accent_device_default_dark</item>
     </style>
 
-    <style name="Theme.DeviceDefault.Settings.DialogWhenLarge" parent="Theme.DeviceDefault.Light"/>
-
-    <style name="Theme.DeviceDefault.Settings.Dialog.Alert" parent="Theme.DeviceDefault.Light.Dialog.Alert">
+    <!-- Variant of {@link #Theme_DeviceDefault_Settings_Dark} with no action bar -->
+    <style name="Theme.DeviceDefault.Settings.Dark.NoActionBar" parent="Theme.Material.NoActionBar">
+        <!-- Color palette -->
         <item name="colorPrimary">@color/primary_device_default_settings</item>
         <item name="colorPrimaryDark">@color/primary_dark_device_default_settings</item>
         <item name="colorSecondary">@color/secondary_device_default_settings</item>
+        <item name="colorAccent">@color/accent_device_default_dark</item>
+    </style>
+
+    <style name="Theme.DeviceDefault.Settings.Dialog" parent="Theme.Material.Settings.Dialog">
+        <!-- Color palette -->
+        <item name="colorPrimary">@color/primary_device_default_settings</item>
+        <item name="colorPrimaryDark">@color/primary_dark_device_default_settings</item>
+        <item name="colorSecondary">@color/secondary_device_default_settings</item>
+        <item name="colorAccent">@color/accent_device_default_light</item>
+    </style>
+
+    <style name="Theme.DeviceDefault.Settings.DialogWhenLarge" parent="Theme.Material.Settings.DialogWhenLarge">
+        <!-- Color palette -->
+        <item name="colorPrimary">@color/primary_device_default_settings</item>
+        <item name="colorPrimaryDark">@color/primary_dark_device_default_settings</item>
+        <item name="colorSecondary">@color/secondary_device_default_settings</item>
+        <item name="colorAccent">@color/accent_device_default_light</item>
+    </style>
+
+    <style name="Theme.DeviceDefault.Settings.Dialog.Alert" parent="Theme.Material.Settings.Dialog.Alert">
+        <!-- Color palette -->
+        <item name="colorPrimary">@color/primary_device_default_settings</item>
+        <item name="colorPrimaryDark">@color/primary_dark_device_default_settings</item>
+        <item name="colorSecondary">@color/secondary_device_default_settings</item>
+        <item name="colorAccent">@color/accent_device_default_light</item>
     </style>
 
     <!-- Theme used for the intent picker activity. -->
-    <style name="Theme.DeviceDefault.Resolver" parent="Theme.DeviceDefault.Light">
+    <style name="Theme.DeviceDefault.Resolver" parent="Theme.Material.Light">
         <item name="windowIsTranslucent">true</item>
         <item name="windowNoTitle">true</item>
         <item name="windowBackground">@color/transparent</item>
@@ -715,6 +795,11 @@
         <item name="colorControlActivated">?attr/colorControlHighlight</item>
         <item name="listPreferredItemPaddingStart">?attr/dialogPreferredPadding</item>
         <item name="listPreferredItemPaddingEnd">?attr/dialogPreferredPadding</item>
+
+        <!-- Color palette -->
+        <item name="colorPrimary">@color/primary_device_default_light</item>
+        <item name="colorPrimaryDark">@color/primary_dark_device_default_light</item>
+        <item name="colorAccent">@color/accent_device_default_light</item>
     </style>
 
     <!-- DeviceDefault theme for the default system theme.  -->
diff --git a/core/tests/coretests/src/com/android/internal/os/DebugTest.java b/core/tests/coretests/src/com/android/internal/os/DebugTest.java
index 88c7d1b..efb78d7 100644
--- a/core/tests/coretests/src/com/android/internal/os/DebugTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/DebugTest.java
@@ -64,4 +64,12 @@
     public void testGetCallers() {
         assertTrue(callDepth1().matches(EXPECTED_GET_CALLERS));
     }
+
+    /**
+     * Regression test for b/31943543. Note: must be run under CheckJNI to detect the issue.
+     */
+    public void testGetMemoryInfo() {
+        Debug.MemoryInfo info = new Debug.MemoryInfo();
+        Debug.getMemoryInfo(-1, info);
+    }
 }
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index c24d313..40a2833 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -57,6 +57,9 @@
 import com.android.internal.R;
 
 import com.android.internal.util.VirtualRefBasePtr;
+
+import dalvik.annotation.optimization.FastNative;
+
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 
@@ -1723,22 +1726,30 @@
     private static native void nAddAnimator(long setPtr, long propertyValuesHolder,
             long nativeInterpolator, long startDelay, long duration, int repeatCount,
             int repeatMode);
-
-    private static native long nCreateGroupPropertyHolder(long nativePtr, int propertyId,
-            float startValue, float endValue);
-
-    private static native long nCreatePathDataPropertyHolder(long nativePtr, long startValuePtr,
-            long endValuePtr);
-    private static native long nCreatePathColorPropertyHolder(long nativePtr, int propertyId,
-            int startValue, int endValue);
-    private static native long nCreatePathPropertyHolder(long nativePtr, int propertyId,
-            float startValue, float endValue);
-    private static native long nCreateRootAlphaPropertyHolder(long nativePtr, float startValue,
-            float endValue);
     private static native void nSetPropertyHolderData(long nativePtr, float[] data, int length);
     private static native void nSetPropertyHolderData(long nativePtr, int[] data, int length);
     private static native void nStart(long animatorSetPtr, VectorDrawableAnimatorRT set, int id);
     private static native void nReverse(long animatorSetPtr, VectorDrawableAnimatorRT set, int id);
+
+    // ------------- @FastNative -------------------
+
+    @FastNative
+    private static native long nCreateGroupPropertyHolder(long nativePtr, int propertyId,
+            float startValue, float endValue);
+    @FastNative
+    private static native long nCreatePathDataPropertyHolder(long nativePtr, long startValuePtr,
+            long endValuePtr);
+    @FastNative
+    private static native long nCreatePathColorPropertyHolder(long nativePtr, int propertyId,
+            int startValue, int endValue);
+    @FastNative
+    private static native long nCreatePathPropertyHolder(long nativePtr, int propertyId,
+            float startValue, float endValue);
+    @FastNative
+    private static native long nCreateRootAlphaPropertyHolder(long nativePtr, float startValue,
+            float endValue);
+    @FastNative
     private static native void nEnd(long animatorSetPtr);
+    @FastNative
     private static native void nReset(long animatorSetPtr);
 }
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index 1ca1552..e83104d 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -55,6 +55,7 @@
 import java.util.HashMap;
 import java.util.Stack;
 
+import dalvik.annotation.optimization.FastNative;
 import dalvik.system.VMRuntime;
 
 /**
@@ -2150,41 +2151,61 @@
         abstract Property getProperty(String propertyName);
     }
 
-    private static native long nCreateTree(long rootGroupPtr);
-    private static native long nCreateTreeFromCopy(long treeToCopy, long rootGroupPtr);
-    private static native void nSetRendererViewportSize(long rendererPtr, float viewportWidth,
-            float viewportHeight);
-    private static native boolean nSetRootAlpha(long rendererPtr, float alpha);
-    private static native float nGetRootAlpha(long rendererPtr);
-    private static native void nSetAllowCaching(long rendererPtr, boolean allowCaching);
-
     private static native int nDraw(long rendererPtr, long canvasWrapperPtr,
             long colorFilterPtr, Rect bounds, boolean needsMirroring, boolean canReuseCache);
-    private static native long nCreateFullPath();
-    private static native long nCreateFullPath(long nativeFullPathPtr);
     private static native boolean nGetFullPathProperties(long pathPtr, byte[] properties,
             int length);
+    private static native void nSetName(long nodePtr, String name);
+    private static native boolean nGetGroupProperties(long groupPtr, float[] properties,
+            int length);
+    private static native void nSetPathString(long pathPtr, String pathString, int length);
 
+    // ------------- @FastNative ------------------
+
+    @FastNative
+    private static native long nCreateTree(long rootGroupPtr);
+    @FastNative
+    private static native long nCreateTreeFromCopy(long treeToCopy, long rootGroupPtr);
+    @FastNative
+    private static native void nSetRendererViewportSize(long rendererPtr, float viewportWidth,
+            float viewportHeight);
+    @FastNative
+    private static native boolean nSetRootAlpha(long rendererPtr, float alpha);
+    @FastNative
+    private static native float nGetRootAlpha(long rendererPtr);
+    @FastNative
+    private static native void nSetAllowCaching(long rendererPtr, boolean allowCaching);
+
+    @FastNative
+    private static native long nCreateFullPath();
+    @FastNative
+    private static native long nCreateFullPath(long nativeFullPathPtr);
+
+    @FastNative
     private static native void nUpdateFullPathProperties(long pathPtr, float strokeWidth,
             int strokeColor, float strokeAlpha, int fillColor, float fillAlpha, float trimPathStart,
             float trimPathEnd, float trimPathOffset, float strokeMiterLimit, int strokeLineCap,
             int strokeLineJoin, int fillType);
+    @FastNative
     private static native void nUpdateFullPathFillGradient(long pathPtr, long fillGradientPtr);
+    @FastNative
     private static native void nUpdateFullPathStrokeGradient(long pathPtr, long strokeGradientPtr);
 
+    @FastNative
     private static native long nCreateClipPath();
+    @FastNative
     private static native long nCreateClipPath(long clipPathPtr);
 
+    @FastNative
     private static native long nCreateGroup();
+    @FastNative
     private static native long nCreateGroup(long groupPtr);
-    private static native void nSetName(long nodePtr, String name);
-    private static native boolean nGetGroupProperties(long groupPtr, float[] properties,
-            int length);
+    @FastNative
     private static native void nUpdateGroupProperties(long groupPtr, float rotate, float pivotX,
             float pivotY, float scaleX, float scaleY, float translateX, float translateY);
 
+    @FastNative
     private static native void nAddChild(long groupPtr, long nodePtr);
-    private static native void nSetPathString(long pathPtr, String pathString, int length);
 
     /**
      * The setters and getters below for paths and groups are here temporarily, and will be
@@ -2193,37 +2214,68 @@
      * for VD during animation, and these setters and getters will be obsolete.
      */
     // Setters and getters during animation.
+    @FastNative
     private static native float nGetRotation(long groupPtr);
+    @FastNative
     private static native void nSetRotation(long groupPtr, float rotation);
+    @FastNative
     private static native float nGetPivotX(long groupPtr);
+    @FastNative
     private static native void nSetPivotX(long groupPtr, float pivotX);
+    @FastNative
     private static native float nGetPivotY(long groupPtr);
+    @FastNative
     private static native void nSetPivotY(long groupPtr, float pivotY);
+    @FastNative
     private static native float nGetScaleX(long groupPtr);
+    @FastNative
     private static native void nSetScaleX(long groupPtr, float scaleX);
+    @FastNative
     private static native float nGetScaleY(long groupPtr);
+    @FastNative
     private static native void nSetScaleY(long groupPtr, float scaleY);
+    @FastNative
     private static native float nGetTranslateX(long groupPtr);
+    @FastNative
     private static native void nSetTranslateX(long groupPtr, float translateX);
+    @FastNative
     private static native float nGetTranslateY(long groupPtr);
+    @FastNative
     private static native void nSetTranslateY(long groupPtr, float translateY);
 
     // Setters and getters for VPath during animation.
+    @FastNative
     private static native void nSetPathData(long pathPtr, long pathDataPtr);
+    @FastNative
     private static native float nGetStrokeWidth(long pathPtr);
+    @FastNative
     private static native void nSetStrokeWidth(long pathPtr, float width);
+    @FastNative
     private static native int nGetStrokeColor(long pathPtr);
+    @FastNative
     private static native void nSetStrokeColor(long pathPtr, int strokeColor);
+    @FastNative
     private static native float nGetStrokeAlpha(long pathPtr);
+    @FastNative
     private static native void nSetStrokeAlpha(long pathPtr, float alpha);
+    @FastNative
     private static native int nGetFillColor(long pathPtr);
+    @FastNative
     private static native void nSetFillColor(long pathPtr, int fillColor);
+    @FastNative
     private static native float nGetFillAlpha(long pathPtr);
+    @FastNative
     private static native void nSetFillAlpha(long pathPtr, float fillAlpha);
+    @FastNative
     private static native float nGetTrimPathStart(long pathPtr);
+    @FastNative
     private static native void nSetTrimPathStart(long pathPtr, float trimPathStart);
+    @FastNative
     private static native float nGetTrimPathEnd(long pathPtr);
+    @FastNative
     private static native void nSetTrimPathEnd(long pathPtr, float trimPathEnd);
+    @FastNative
     private static native float nGetTrimPathOffset(long pathPtr);
+    @FastNative
     private static native void nSetTrimPathOffset(long pathPtr, float trimPathOffset);
 }
diff --git a/libs/hwui/SpotShadow.cpp b/libs/hwui/SpotShadow.cpp
index e2ee5bf..7b0a1bc 100644
--- a/libs/hwui/SpotShadow.cpp
+++ b/libs/hwui/SpotShadow.cpp
@@ -927,9 +927,13 @@
         AlphaVertex::set(&shadowVertices[vertexBufferIndex++], newPenumbra[i].x,
                 newPenumbra[i].y, PENUMBRA_ALPHA);
     }
+    // Since the umbra can be a faked one when the occluder is too high, the umbra should be lighter
+    // in this case.
+    float scaledUmbraAlpha = UMBRA_ALPHA * shadowStrengthScale;
+
     for (int i = 0; i < umbraLength; i++) {
         AlphaVertex::set(&shadowVertices[vertexBufferIndex++], umbra[i].x, umbra[i].y,
-                UMBRA_ALPHA);
+                scaledUmbraAlpha);
     }
 
     for (int i = 0; i < verticesPairIndex; i++) {
@@ -969,14 +973,14 @@
             indexBuffer[indexBufferIndex++] = newPenumbraLength + i;
             indexBuffer[indexBufferIndex++] = vertexBufferIndex;
             AlphaVertex::set(&shadowVertices[vertexBufferIndex++],
-                    closerVertex.x, closerVertex.y, UMBRA_ALPHA);
+                    closerVertex.x, closerVertex.y, scaledUmbraAlpha);
         }
     } else {
         // If there is no occluded umbra at all, then draw the triangle fan
         // starting from the centroid to all umbra vertices.
         int lastCentroidIndex = vertexBufferIndex;
         AlphaVertex::set(&shadowVertices[vertexBufferIndex++], centroid.x,
-                centroid.y, UMBRA_ALPHA);
+                centroid.y, scaledUmbraAlpha);
         for (int i = 0; i < umbraLength; i++) {
             indexBuffer[indexBufferIndex++] = newPenumbraLength + i;
             indexBuffer[indexBufferIndex++] = lastCentroidIndex;
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
index 04f32a1..91c943d 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -174,6 +174,7 @@
         final AlertDialog dialog = new AlertDialog.Builder(mContext)
             .setTitle(title)
             .setMessage(message)
+            .setCancelable(false)
             .setNeutralButton(R.string.ok, null)
             .create();
         if (!(mContext instanceof Activity)) {
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 288b954..66e56e0 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -16,6 +16,7 @@
 
 package com.android.keyguard;
 
+import static android.content.Intent.ACTION_USER_UNLOCKED;
 import static android.os.BatteryManager.BATTERY_HEALTH_UNKNOWN;
 import static android.os.BatteryManager.BATTERY_STATUS_FULL;
 import static android.os.BatteryManager.BATTERY_STATUS_UNKNOWN;
@@ -136,6 +137,7 @@
     private static final int MSG_SCREEN_TURNED_ON = 331;
     private static final int MSG_SCREEN_TURNED_OFF = 332;
     private static final int MSG_DREAMING_STATE_CHANGED = 333;
+    private static final int MSG_USER_UNLOCKED = 334;
 
     /** Fingerprint state: Not listening to fingerprint. */
     private static final int FINGERPRINT_STATE_STOPPED = 0;
@@ -291,6 +293,9 @@
                 case MSG_DREAMING_STATE_CHANGED:
                     handleDreamingStateChanged(msg.arg1);
                     break;
+                case MSG_USER_UNLOCKED:
+                    handleUserUnlocked();
+                    break;
             }
         }
     };
@@ -723,6 +728,8 @@
             } else if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED
                     .equals(action)) {
                 mHandler.sendEmptyMessage(MSG_DPM_STATE_CHANGED);
+            } else if (ACTION_USER_UNLOCKED.equals(action)) {
+                mHandler.sendEmptyMessage(MSG_USER_UNLOCKED);
             }
         }
     };
@@ -1025,6 +1032,16 @@
         }
     }
 
+    private void handleUserUnlocked() {
+        mNeedsSlowUnlockTransition = resolveNeedsSlowUnlockTransition();
+        for (int i = 0; i < mCallbacks.size(); i++) {
+            KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
+            if (cb != null) {
+                cb.onUserUnlocked();
+            }
+        }
+    }
+
     private KeyguardUpdateMonitor(Context context) {
         mContext = context;
         mSubscriptionManager = SubscriptionManager.from(context);
@@ -1065,6 +1082,7 @@
         allUserFilter.addAction(ACTION_FACE_UNLOCK_STARTED);
         allUserFilter.addAction(ACTION_FACE_UNLOCK_STOPPED);
         allUserFilter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
+        allUserFilter.addAction(ACTION_USER_UNLOCKED);
         context.registerReceiverAsUser(mBroadcastAllReceiver, UserHandle.ALL, allUserFilter,
                 null, null);
 
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
index eb29d9b..14d6b59 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitorCallback.java
@@ -128,6 +128,11 @@
     public void onUserInfoChanged(int userId) { }
 
     /**
+     * Called when a user got unlocked.
+     */
+    public void onUserUnlocked() { }
+
+    /**
      * Called when boot completed.
      *
      * Note, this callback will only be received if boot complete occurs after registering with
diff --git a/packages/SettingsLib/res/values/config.xml b/packages/SettingsLib/res/values/config.xml
index 0cf4a41..e2e721c 100755
--- a/packages/SettingsLib/res/values/config.xml
+++ b/packages/SettingsLib/res/values/config.xml
@@ -37,4 +37,7 @@
 
     <!-- Intent key for package name values -->
     <string name="config_helpIntentNameKey" translatable="false"></string>
-</resources>
+
+    <!-- The apps that need to be hided when they are disabled -->
+    <string-array name="config_hideWhenDisabled_packageNames"></string-array>
+</resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
index a22a051..f0ec1078 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
@@ -47,6 +47,7 @@
 import android.util.SparseArray;
 
 import com.android.internal.util.ArrayUtils;
+import com.android.settingslib.R;
 
 import java.io.File;
 import java.text.Collator;
@@ -621,7 +622,7 @@
             }
 
             if (filter != null) {
-                filter.init();
+                filter.init(mContext);
             }
 
             List<AppEntry> apps;
@@ -1280,6 +1281,9 @@
 
     public interface AppFilter {
         void init();
+        default void init(Context context) {
+            init();
+        }
         boolean filterApp(AppEntry info);
     }
 
@@ -1398,6 +1402,33 @@
         }
     };
 
+    public static final AppFilter FILTER_NOT_HIDE = new AppFilter() {
+        private String[] mHidePackageNames;
+
+        public void init(Context context) {
+            mHidePackageNames = context.getResources()
+                .getStringArray(R.array.config_hideWhenDisabled_packageNames);
+        }
+
+        @Override
+        public void init() {
+        }
+
+        @Override
+        public boolean filterApp(AppEntry entry) {
+            if (ArrayUtils.contains(mHidePackageNames, entry.info.packageName)) {
+                if (!entry.info.enabled) {
+                    return false;
+                } else if (entry.info.enabledSetting ==
+                    PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
+                    return false;
+                }
+            }
+
+            return true;
+        }
+    };
+
     public static class VolumeFilter implements AppFilter {
         private final String mVolumeUuid;
 
@@ -1425,6 +1456,12 @@
         }
 
         @Override
+        public void init(Context context) {
+            mFirstFilter.init(context);
+            mSecondFilter.init(context);
+        }
+
+        @Override
         public void init() {
             mFirstFilter.init();
             mSecondFilter.init();
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index a879d16f..52e686c9b 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -102,9 +102,6 @@
     private static final long MAX_UUID_DELAY_FOR_AUTO_CONNECT = 5000;
     private static final long MAX_HOGP_DELAY_FOR_AUTO_CONNECT = 30000;
 
-    /** Auto-connect after pairing only if locally initiated. */
-    private boolean mConnectAfterPairing;
-
     /**
      * Describes the current device and profile for logging.
      *
@@ -300,7 +297,6 @@
             return false;
         }
 
-        mConnectAfterPairing = true;  // auto-connect after pairing
         return true;
     }
 
@@ -309,7 +305,7 @@
      * slightly different for local vs. remote initiated pairing dialogs.
      */
     boolean isUserInitiatedPairing() {
-        return mConnectAfterPairing;
+        return mDevice.isBondingInitiatedLocally();
     }
 
     public void unpair() {
@@ -549,7 +545,6 @@
     void onBondingStateChanged(int bondState) {
         if (bondState == BluetoothDevice.BOND_NONE) {
             mProfiles.clear();
-            mConnectAfterPairing = false;  // cancel auto-connect
             setPhonebookPermissionChoice(ACCESS_UNKNOWN);
             setMessagePermissionChoice(ACCESS_UNKNOWN);
             setSimPermissionChoice(ACCESS_UNKNOWN);
@@ -562,10 +557,9 @@
         if (bondState == BluetoothDevice.BOND_BONDED) {
             if (mDevice.isBluetoothDock()) {
                 onBondingDockConnect();
-            } else if (mConnectAfterPairing) {
+            } else if (mDevice.isBondingInitiatedLocally()) {
                 connect(false);
             }
-            mConnectAfterPairing = false;
         }
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java b/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java
index 26e8303..857ca49 100644
--- a/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java
+++ b/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java
@@ -40,23 +40,47 @@
 import java.util.Set;
 import java.util.TimeZone;
 
+/**
+ * ZoneGetter is the utility class to get time zone and zone list, and both of them have display
+ * name in time zone. In this class, we will keep consistency about display names for all
+ * the methods.
+ *
+ * The display name chosen for each zone entry depends on whether the zone is one associated
+ * with the country of the user's chosen locale. For "local" zones we prefer the "long name"
+ * (e.g. "Europe/London" -> "British Summer Time" for people in the UK). For "non-local"
+ * zones we prefer the exemplar location (e.g. "Europe/London" -> "London" for English
+ * speakers from outside the UK). This heuristic is based on the fact that people are
+ * typically familiar with their local timezones and exemplar locations don't always match
+ * modern-day expectations for people living in the country covered. Large countries like
+ * China that mostly use a single timezone (olson id: "Asia/Shanghai") may not live near
+ * "Shanghai" and prefer the long name over the exemplar location. The only time we don't
+ * follow this policy for local zones is when Android supplies multiple olson IDs to choose
+ * from and the use of a zone's long name leads to ambiguity. For example, at the time of
+ * writing Android lists 5 olson ids for Australia which collapse to 2 different zone names
+ * in winter but 4 different zone names in summer. The ambiguity leads to the users
+ * selecting the wrong olson ids.
+ *
+ */
 public class ZoneGetter {
     private static final String TAG = "ZoneGetter";
 
-    private static final String XMLTAG_TIMEZONE = "timezone";
-
     public static final String KEY_ID = "id";  // value: String
     public static final String KEY_DISPLAYNAME = "name";  // value: String
     public static final String KEY_GMT = "gmt";  // value: String
     public static final String KEY_OFFSET = "offset";  // value: int (Integer)
 
-    private ZoneGetter() {}
+    private static final String XMLTAG_TIMEZONE = "timezone";
 
-    public static String getTimeZoneOffsetAndName(TimeZone tz, Date now) {
-        Locale locale = Locale.getDefault();
-        String gmtString = getGmtOffsetString(locale, tz, now);
-        TimeZoneNames timeZoneNames = TimeZoneNames.getInstance(locale);
-        String zoneNameString = getZoneLongName(timeZoneNames, tz, now);
+    public static String getTimeZoneOffsetAndName(Context context, TimeZone tz, Date now) {
+        final Locale locale = Locale.getDefault();
+        final String gmtString = getGmtOffsetString(locale, tz, now);
+        final TimeZoneNames timeZoneNames = TimeZoneNames.getInstance(locale);
+        final ZoneGetterData data = new ZoneGetterData(context);
+
+        final boolean useExemplarLocationForLocalNames =
+                shouldUseExemplarLocationForLocalNames(data, timeZoneNames);
+        final String zoneNameString = getTimeZoneDisplayName(data, timeZoneNames,
+                useExemplarLocationForLocalNames, tz, tz.getID());
         if (zoneNameString == null) {
             return gmtString;
         }
@@ -69,82 +93,20 @@
         final Locale locale = Locale.getDefault();
         final Date now = new Date();
         final TimeZoneNames timeZoneNames = TimeZoneNames.getInstance(locale);
-
-        // The display name chosen for each zone entry depends on whether the zone is one associated
-        // with the country of the user's chosen locale. For "local" zones we prefer the "long name"
-        // (e.g. "Europe/London" -> "British Summer Time" for people in the UK). For "non-local"
-        // zones we prefer the exemplar location (e.g. "Europe/London" -> "London" for English
-        // speakers from outside the UK). This heuristic is based on the fact that people are
-        // typically familiar with their local timezones and exemplar locations don't always match
-        // modern-day expectations for people living in the country covered. Large countries like
-        // China that mostly use a single timezone (olson id: "Asia/Shanghai") may not live near
-        // "Shanghai" and prefer the long name over the exemplar location. The only time we don't
-        // follow this policy for local zones is when Android supplies multiple olson IDs to choose
-        // from and the use of a zone's long name leads to ambiguity. For example, at the time of
-        // writing Android lists 5 olson ids for Australia which collapse to 2 different zone names
-        // in winter but 4 different zone names in summer. The ambiguity leads to the users
-        // selecting the wrong olson ids.
-
-        // Get the list of olson ids to display to the user.
-        List<String> olsonIdsToDisplayList = readTimezonesToDisplay(context);
-
-        // Store the information we are going to need more than once.
-        final int zoneCount = olsonIdsToDisplayList.size();
-        final String[] olsonIdsToDisplay = new String[zoneCount];
-        final TimeZone[] timeZones = new TimeZone[zoneCount];
-        final String[] gmtOffsetStrings = new String[zoneCount];
-        for (int i = 0; i < zoneCount; i++) {
-            String olsonId = olsonIdsToDisplayList.get(i);
-            olsonIdsToDisplay[i] = olsonId;
-            TimeZone tz = TimeZone.getTimeZone(olsonId);
-            timeZones[i] = tz;
-            gmtOffsetStrings[i] = getGmtOffsetString(locale, tz, now);
-        }
-
-        // Create a lookup of local zone IDs.
-        Set<String> localZoneIds = new HashSet<String>();
-        for (String olsonId : libcore.icu.TimeZoneNames.forLocale(locale)) {
-            localZoneIds.add(olsonId);
-        }
+        final ZoneGetterData data = new ZoneGetterData(context);
 
         // Work out whether the display names we would show by default would be ambiguous.
-        Set<String> localZoneNames = new HashSet<String>();
-        boolean useExemplarLocationForLocalNames = false;
-        for (int i = 0; i < zoneCount; i++) {
-            String olsonId = olsonIdsToDisplay[i];
-            if (localZoneIds.contains(olsonId)) {
-                TimeZone tz = timeZones[i];
-                String displayName = getZoneLongName(timeZoneNames, tz, now);
-                if (displayName == null) {
-                    displayName = gmtOffsetStrings[i];
-                }
-                boolean nameIsUnique = localZoneNames.add(displayName);
-                if (!nameIsUnique) {
-                    useExemplarLocationForLocalNames = true;
-                    break;
-                }
-            }
-        }
+        final boolean useExemplarLocationForLocalNames =
+                shouldUseExemplarLocationForLocalNames(data, timeZoneNames);
 
         // Generate the list of zone entries to return.
         List<Map<String, Object>> zones = new ArrayList<Map<String, Object>>();
-        for (int i = 0; i < zoneCount; i++) {
-            String olsonId = olsonIdsToDisplay[i];
-            TimeZone tz = timeZones[i];
-            String gmtOffsetString = gmtOffsetStrings[i];
+        for (int i = 0; i < data.zoneCount; i++) {
+            TimeZone tz = data.timeZones[i];
+            String gmtOffsetString = data.gmtOffsetStrings[i];
 
-            boolean isLocalZoneId = localZoneIds.contains(olsonId);
-            boolean preferLongName = isLocalZoneId && !useExemplarLocationForLocalNames;
-            String displayName;
-            if (preferLongName) {
-                displayName = getZoneLongName(timeZoneNames, tz, now);
-            } else {
-                displayName = timeZoneNames.getExemplarLocationName(tz.getID());
-                if (displayName == null || displayName.isEmpty()) {
-                    // getZoneExemplarLocation can return null. Fall back to the long name.
-                    displayName = getZoneLongName(timeZoneNames, tz, now);
-                }
-            }
+            String displayName = getTimeZoneDisplayName(data, timeZoneNames,
+                    useExemplarLocationForLocalNames, tz, data.olsonIdsToDisplay[i]);
             if (displayName == null  || displayName.isEmpty()) {
                 displayName = gmtOffsetString;
             }
@@ -198,28 +160,103 @@
         return olsonIds;
     }
 
+    private static boolean shouldUseExemplarLocationForLocalNames(ZoneGetterData data,
+            TimeZoneNames timeZoneNames) {
+        final Set<String> localZoneNames = new HashSet<String>();
+        final Date now = new Date();
+        for (int i = 0; i < data.zoneCount; i++) {
+            final String olsonId = data.olsonIdsToDisplay[i];
+            if (data.localZoneIds.contains(olsonId)) {
+                final TimeZone tz = data.timeZones[i];
+                String displayName = getZoneLongName(timeZoneNames, tz, now);
+                if (displayName == null) {
+                    displayName = data.gmtOffsetStrings[i];
+                }
+                final boolean nameIsUnique = localZoneNames.add(displayName);
+                if (!nameIsUnique) {
+                    return true;
+                }
+            }
+        }
+
+        return false;
+    }
+
+    private static String getTimeZoneDisplayName(ZoneGetterData data, TimeZoneNames timeZoneNames,
+            boolean useExemplarLocationForLocalNames, TimeZone tz, String olsonId) {
+        final Date now = new Date();
+        final boolean isLocalZoneId = data.localZoneIds.contains(olsonId);
+        final boolean preferLongName = isLocalZoneId && !useExemplarLocationForLocalNames;
+        String displayName;
+
+        if (preferLongName) {
+            displayName = getZoneLongName(timeZoneNames, tz, now);
+        } else {
+            displayName = timeZoneNames.getExemplarLocationName(tz.getID());
+            if (displayName == null || displayName.isEmpty()) {
+                // getZoneExemplarLocation can return null. Fall back to the long name.
+                displayName = getZoneLongName(timeZoneNames, tz, now);
+            }
+        }
+
+        return displayName;
+    }
+
     /**
      * Returns the long name for the timezone for the given locale at the time specified.
      * Can return {@code null}.
      */
     private static String getZoneLongName(TimeZoneNames names, TimeZone tz, Date now) {
-        TimeZoneNames.NameType nameType =
+        final TimeZoneNames.NameType nameType =
                 tz.inDaylightTime(now) ? TimeZoneNames.NameType.LONG_DAYLIGHT
-                : TimeZoneNames.NameType.LONG_STANDARD;
+                        : TimeZoneNames.NameType.LONG_STANDARD;
         return names.getDisplayName(tz.getID(), nameType, now.getTime());
     }
 
     private static String getGmtOffsetString(Locale locale, TimeZone tz, Date now) {
         // Use SimpleDateFormat to format the GMT+00:00 string.
-        SimpleDateFormat gmtFormatter = new SimpleDateFormat("ZZZZ");
+        final SimpleDateFormat gmtFormatter = new SimpleDateFormat("ZZZZ");
         gmtFormatter.setTimeZone(tz);
         String gmtString = gmtFormatter.format(now);
 
         // Ensure that the "GMT+" stays with the "00:00" even if the digits are RTL.
-        BidiFormatter bidiFormatter = BidiFormatter.getInstance();
+        final BidiFormatter bidiFormatter = BidiFormatter.getInstance();
         boolean isRtl = TextUtils.getLayoutDirectionFromLocale(locale) == View.LAYOUT_DIRECTION_RTL;
         gmtString = bidiFormatter.unicodeWrap(gmtString,
                 isRtl ? TextDirectionHeuristics.RTL : TextDirectionHeuristics.LTR);
         return gmtString;
     }
-}
+
+    private static final class ZoneGetterData {
+        public final String[] olsonIdsToDisplay;
+        public final String[] gmtOffsetStrings;
+        public final TimeZone[] timeZones;
+        public final Set<String> localZoneIds;
+        public final int zoneCount;
+
+        public ZoneGetterData(Context context) {
+            final Locale locale = Locale.getDefault();
+            final Date now = new Date();
+            final List<String> olsonIdsToDisplayList = readTimezonesToDisplay(context);
+
+            // Load all the data needed to display time zones
+            zoneCount = olsonIdsToDisplayList.size();
+            olsonIdsToDisplay = new String[zoneCount];
+            timeZones = new TimeZone[zoneCount];
+            gmtOffsetStrings = new String[zoneCount];
+            for (int i = 0; i < zoneCount; i++) {
+                final String olsonId = olsonIdsToDisplayList.get(i);
+                olsonIdsToDisplay[i] = olsonId;
+                final TimeZone tz = TimeZone.getTimeZone(olsonId);
+                timeZones[i] = tz;
+                gmtOffsetStrings[i] = getGmtOffsetString(locale, tz, now);
+            }
+
+            // Create a lookup of local zone IDs.
+            localZoneIds = new HashSet<String>();
+            for (String olsonId : libcore.icu.TimeZoneNames.forLocale(locale)) {
+                localZoneIds.add(olsonId);
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/packages/SettingsLib/tests/AndroidManifest.xml b/packages/SettingsLib/tests/AndroidManifest.xml
index 18bbbed..9fd5a41 100644
--- a/packages/SettingsLib/tests/AndroidManifest.xml
+++ b/packages/SettingsLib/tests/AndroidManifest.xml
@@ -20,6 +20,7 @@
     <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
     <uses-permission android:name="android.permission.MANAGE_USERS" />
     <uses-permission android:name="android.permission.MANAGE_NETWORK_POLICY"/>
+    <uses-permission android:name="android.permission.SET_TIME_ZONE" />
 
     <application>
         <uses-library android:name="android.test.runner" />
diff --git a/packages/SettingsLib/tests/src/com/android/settingslib/utils/ZoneGetterTest.java b/packages/SettingsLib/tests/src/com/android/settingslib/utils/ZoneGetterTest.java
new file mode 100644
index 0000000..57e06dd
--- /dev/null
+++ b/packages/SettingsLib/tests/src/com/android/settingslib/utils/ZoneGetterTest.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2016 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.settingslib.utils;
+
+import android.content.Context;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.test.filters.SmallTest;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.*;
+import com.android.settingslib.datetime.ZoneGetter;
+
+import static junit.framework.Assert.assertTrue;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class ZoneGetterTest {
+    private static final String TIME_ZONE_LONDON_ID = "Europe/London";
+    private static final String TIME_ZONE_LA_ID = "America/Los_Angeles";
+    private Locale mLocaleEnUs;
+    private Calendar mCalendar;
+
+    @Before
+    public void setUp() {
+        mLocaleEnUs = new Locale("en", "us");
+        Locale.setDefault(mLocaleEnUs);
+        mCalendar = new GregorianCalendar(2016, 9, 1);
+    }
+
+    @Test
+    public void getTimeZoneOffsetAndName_setLondon_returnLondon() {
+        // Check it will ends with 'London', not 'British Summer Time' or sth else
+        testTimeZoneOffsetAndNameInner(TIME_ZONE_LONDON_ID, "London");
+    }
+
+    @Test
+    public void getTimeZoneOffsetAndName_setLosAngeles_returnPacificDaylightTime() {
+        // Check it will ends with 'Pacific Daylight Time', not 'Los_Angeles'
+        testTimeZoneOffsetAndNameInner(TIME_ZONE_LA_ID, "Pacific Daylight Time");
+    }
+
+    private void testTimeZoneOffsetAndNameInner(String timeZoneId, String expectedName) {
+        final Context context = InstrumentationRegistry.getContext();
+        final TimeZone timeZone = TimeZone.getTimeZone(timeZoneId);
+
+        String timeZoneString = ZoneGetter.getTimeZoneOffsetAndName(context, timeZone,
+                mCalendar.getTime());
+
+        assertTrue(timeZoneString.endsWith(expectedName));
+    }
+
+}
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_0.xml b/packages/SystemUI/res/drawable/ic_qs_signal_0.xml
index f63dfb12..b78d3bf 100644
--- a/packages/SystemUI/res/drawable/ic_qs_signal_0.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_signal_0.xml
@@ -1,7 +1,7 @@
 <!--
-Copyright (C) 2014 The Android Open Source Project
+    Copyright (C) 2016 The Android Open Source Project
 
-   Licensed under the Apache License, Version 2.0 (the "License");
+    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
 
@@ -15,17 +15,15 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:autoMirrored="true"
-        android:width="32dp"
-        android:height="32dp"
+        android:width="32.0dp"
+        android:height="32.0dp"
         android:viewportWidth="24.0"
         android:viewportHeight="24.0">
     <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M19.700001,20.000000l2.000000,0.000000l0.000000,2.000000l-2.000000,0.000000z"/>
+        android:pathData="M14.1,14.1l7.9,0.0 0.0,-11.5 -20.0,20.0 12.1,0.0z"
+        android:fillAlpha="0.3"
+        android:fillColor="#FFFFFF"/>
     <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M19.700001,10.000000l2.000000,0.000000l0.000000,8.100000l-2.000000,0.000000z"/>
-    <path
-        android:pathData="M17.700001,8.000000l4.299999,0.000000 0.000000,-6.000000 -20.000000,20.000000 15.700001,0.000000z"
-        android:fillColor="#4DFFFFFF"/>
+        android:pathData="M21.9,17.0l-1.1,-1.1 -1.9,1.9 -1.9,-1.9 -1.1,1.1 1.9,1.9 -1.9,1.9 1.1,1.1 1.9,-1.9 1.9,1.9 1.1,-1.1 -1.9,-1.9z"
+        android:fillColor="#FFFFFF"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_1.xml b/packages/SystemUI/res/drawable/ic_qs_signal_1.xml
index 7fb423e..e055de7 100644
--- a/packages/SystemUI/res/drawable/ic_qs_signal_1.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_signal_1.xml
@@ -1,7 +1,7 @@
 <!--
-Copyright (C) 2014 The Android Open Source Project
+    Copyright (C) 2016 The Android Open Source Project
 
-   Licensed under the Apache License, Version 2.0 (the "License");
+    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
 
@@ -15,20 +15,18 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:autoMirrored="true"
-        android:width="32dp"
-        android:height="32dp"
+        android:width="32.0dp"
+        android:height="32.0dp"
         android:viewportWidth="24.0"
         android:viewportHeight="24.0">
     <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M19.7,20.0l2.0,0.0l0.0,2.0l-2.0,0.0z"/>
+        android:pathData="M10.0,14.6l-8.0,8.0l8.0,0.0l0,-8z"
+        android:fillColor="#FFFFFF"/>
     <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M19.7,10.0l2.0,0.0l0.0,8.1l-2.0,0.0z"/>
+        android:pathData="M14.1,14.1l7.9,0.0 0.0,-11.5 -20.0,20.0 12.1,0.0z"
+        android:fillAlpha="0.3"
+        android:fillColor="#FFFFFF"/>
     <path
-        android:fillColor="#4DFFFFFF"
-        android:pathData="M17.7,8.0l4.299999,0.0 0.0,-6.0 -20.0,20.0 15.700001,0.0z"/>
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M10.1,13.9l-8.1,8.1 8.1,0.0z"/>
+        android:pathData="M21.9,17.0l-1.1,-1.1 -1.9,1.9 -1.9,-1.9 -1.1,1.1 1.9,1.9 -1.9,1.9 1.1,1.1 1.9,-1.9 1.9,1.9 1.1,-1.1 -1.9,-1.9z"
+        android:fillColor="#FFFFFF"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_2.xml b/packages/SystemUI/res/drawable/ic_qs_signal_2.xml
index 3358d65..8a48817 100644
--- a/packages/SystemUI/res/drawable/ic_qs_signal_2.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_signal_2.xml
@@ -1,7 +1,7 @@
 <!--
-Copyright (C) 2014 The Android Open Source Project
+    Copyright (C) 2016 The Android Open Source Project
 
-   Licensed under the Apache License, Version 2.0 (the "License");
+    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
 
@@ -15,20 +15,18 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:autoMirrored="true"
-        android:width="32dp"
-        android:height="32dp"
+        android:width="32.0dp"
+        android:height="32.0dp"
         android:viewportWidth="24.0"
         android:viewportHeight="24.0">
     <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M19.700001,20.000000l2.000000,0.000000l0.000000,2.000000l-2.000000,0.000000z"/>
+        android:pathData="M14.0,10.6l-12.0,12.0l12.0,0.0L14.0,10.6z"
+        android:fillColor="#FFFFFF"/>
     <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M19.700001,10.000000l2.000000,0.000000l0.000000,8.100000l-2.000000,0.000000z"/>
+        android:pathData="M14.1,14.1l7.9,0.0 0.0,-11.5 -20.0,20.0 12.1,0.0z"
+        android:fillAlpha="0.3"
+        android:fillColor="#FFFFFF"/>
     <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M13.900000,10.000000l-11.900000,12.000000 11.900000,0.000000z"/>
-    <path
-        android:pathData="M17.700001,8.000000l4.299999,0.000000 0.000000,-6.000000 -20.000000,20.000000 15.700001,0.000000z"
-        android:fillColor="#4DFFFFFF"/>
+        android:pathData="M21.9,17.0l-1.1,-1.1 -1.9,1.9 -1.9,-1.9 -1.1,1.1 1.9,1.9 -1.9,1.9 1.1,1.1 1.9,-1.9 1.9,1.9 1.1,-1.1 -1.9,-1.9z"
+        android:fillColor="#FFFFFF"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_3.xml b/packages/SystemUI/res/drawable/ic_qs_signal_3.xml
index 63838a9..39cc94c 100644
--- a/packages/SystemUI/res/drawable/ic_qs_signal_3.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_signal_3.xml
@@ -1,7 +1,7 @@
 <!--
-Copyright (C) 2014 The Android Open Source Project
+    Copyright (C) 2016 The Android Open Source Project
 
-   Licensed under the Apache License, Version 2.0 (the "License");
+    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
 
@@ -15,20 +15,18 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:autoMirrored="true"
-        android:width="32dp"
-        android:height="32dp"
+        android:width="32.0dp"
+        android:height="32.0dp"
         android:viewportWidth="24.0"
         android:viewportHeight="24.0">
     <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M19.700001,19.900000l2.000000,0.000000l0.000000,2.000000l-2.000000,0.000000z"/>
+        android:pathData="M14.1,14.1l7.9,0.0 0.0,-11.5 -20.0,20.0 12.1,0.0z"
+        android:fillAlpha="0.3"
+        android:fillColor="#FFFFFF"/>
     <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M19.700001,9.900000l2.000000,0.000000l0.000000,8.100000l-2.000000,0.000000z"/>
+        android:pathData="M21.9,17.0l-1.1,-1.1 -1.9,1.9 -1.9,-1.9 -1.1,1.1 1.9,1.9 -1.9,1.9 1.1,1.1 1.9,-1.9 1.9,1.9 1.1,-1.1 -1.9,-1.9z"
+        android:fillColor="#FFFFFF"/>
     <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M16.700001,7.200000l-14.700001,14.700000 14.700001,0.000000z"/>
-    <path
-        android:pathData="M17.700001,7.900000l4.299999,0.000000 0.000000,-6.000000 -20.000000,20.000000 15.700001,0.000000z"
-        android:fillColor="#4DFFFFFF"/>
+        android:pathData="M14.1,14.1l2.9,0.0 0.0,-6.5 -15.0,15.0 12.1,0.0z"
+        android:fillColor="#FFFFFF"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_signal_4.xml b/packages/SystemUI/res/drawable/ic_qs_signal_4.xml
index 76690cc..012e95e 100644
--- a/packages/SystemUI/res/drawable/ic_qs_signal_4.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_signal_4.xml
@@ -1,7 +1,7 @@
 <!--
-Copyright (C) 2014 The Android Open Source Project
+    Copyright (C) 2016 The Android Open Source Project
 
-   Licensed under the Apache License, Version 2.0 (the "License");
+    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
 
@@ -15,17 +15,14 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:autoMirrored="true"
-        android:width="32dp"
-        android:height="32dp"
+        android:width="32.0dp"
+        android:height="32.0dp"
         android:viewportWidth="24.0"
         android:viewportHeight="24.0">
     <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M19.700001,20.000000l2.000000,0.000000l0.000000,2.000000l-2.000000,0.000000z"/>
+        android:pathData="M14.1,14.1l7.9,0.0 0.0,-11.5 -20.0,20.0 12.1,0.0z"
+        android:fillColor="#FFFFFF"/>
     <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M19.700001,10.000000l2.000000,0.000000l0.000000,8.100000l-2.000000,0.000000z"/>
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M2.000000,22.000000l15.700001,0.000000 0.000000,-14.000000 4.299999,0.000000 0.000000,-6.000000z"/>
+        android:pathData="M21.9,17.0l-1.1,-1.1 -1.9,1.9 -1.9,-1.9 -1.1,1.1 1.9,1.9 -1.9,1.9 1.1,1.1 1.9,-1.9 1.9,1.9 1.1,-1.1 -1.9,-1.9z"
+        android:fillColor="#FFFFFF"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_0.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_0.xml
index 50c427e..e6f9292 100644
--- a/packages/SystemUI/res/drawable/ic_qs_wifi_0.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_wifi_0.xml
@@ -1,7 +1,7 @@
 <!--
-Copyright (C) 2014 The Android Open Source Project
+    Copyright (C) 2016 The Android Open Source Project
 
-   Licensed under the Apache License, Version 2.0 (the "License");
+    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
 
@@ -14,17 +14,15 @@
     limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="32.0dp"
-        android:height="29.5dp"
-        android:viewportWidth="26.0"
+        android:width="24.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="24.0"
         android:viewportHeight="24.0">
     <path
-        android:fillColor="#4DFFFFFF"
-        android:pathData="M19.000000,8.000000l5.300000,0.000000l1.200000,-1.500000C25.100000,6.100000 20.299999,2.100000 13.000000,2.100000S0.900000,6.100000 0.400000,6.500000L13.000000,22.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l6.000000,-7.400000L19.000000,8.000000z"/>
+        android:pathData="M13.8,12.2l5.7,0.0L23.6,7.0C23.2,6.7 18.7,3.0 12.0,3.0C5.3,3.0 0.8,6.7 0.4,7.0L12.0,21.5l0.0,0.0l0.0,0.0l1.8,-2.2L13.8,12.2z"
+        android:fillAlpha="0.3"
+        android:fillColor="#FFFFFF"/>
     <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M21.000000,20.000000l2.000000,0.000000l0.000000,2.000000l-2.000000,0.000000z"/>
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M21.000000,10.000000l2.000000,0.000000l0.000000,8.100000l-2.000000,0.000000z"/>
+        android:pathData="M21.9,15.4l-1.1,-1.2 -1.9,1.900001 -1.9,-1.900001 -1.1,1.2 1.9,1.9 -1.9,1.800001 1.1,1.199999 1.9,-1.9 1.9,1.9 1.1,-1.199999 -1.799999,-1.800001z"
+        android:fillColor="#FFFFFF"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_1.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_1.xml
index a2d11a0..d423ccb 100644
--- a/packages/SystemUI/res/drawable/ic_qs_wifi_1.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_wifi_1.xml
@@ -1,7 +1,7 @@
 <!--
-Copyright (C) 2014 The Android Open Source Project
+    Copyright (C) 2016 The Android Open Source Project
 
-   Licensed under the Apache License, Version 2.0 (the "License");
+    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
 
@@ -14,20 +14,18 @@
     limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="32.0dp"
-        android:height="29.5dp"
-        android:viewportWidth="26.0"
+        android:width="24.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="24.0"
         android:viewportHeight="24.0">
     <path
-        android:fillColor="#4DFFFFFF"
-        android:pathData="M19.000000,8.000000l5.300000,0.000000l1.300000,-1.600000C25.100000,6.000000 20.299999,2.000000 13.000000,2.000000S0.900000,6.000000 0.400000,6.400000L13.000000,22.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l6.000000,-7.400000L19.000000,8.000000z"/>
+        android:pathData="M13.8,13.2c-0.1,0.0 -0.3,-0.1 -0.4,-0.1c-0.1,0.0 -0.3,0.0 -0.4,-0.1c-0.3,0.0 -0.6,-0.1 -0.9,-0.1c0.0,0.0 0.0,0.0 -0.1,0.0c0.0,0.0 0.0,0.0 0.0,0.0s0.0,0.0 0.0,0.0c0.0,0.0 0.0,0.0 -0.1,0.0c-0.3,0.0 -0.6,0.0 -0.9,0.1c-0.1,0.0 -0.3,0.0 -0.4,0.1c-0.2,0.0 -0.3,0.1 -0.5,0.1c-0.2,0.0 -0.3,0.1 -0.5,0.1c-0.1,0.0 -0.1,0.0 -0.2,0.1c-1.6,0.5 -2.7,1.3 -2.8,1.5l5.3,6.6l0.0,0.0l0.0,0.0l0.0,0.0l0.0,0.0l1.8,-2.2L13.700002,13.2z"
+        android:fillColor="#FFFFFF"/>
     <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M13.000000,22.000000l5.500000,-6.800000c-0.200000,-0.200000 -2.300000,-1.900000 -5.500000,-1.900000s-5.300000,1.800000 -5.500000,1.900000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000z"/>
+        android:pathData="M13.8,12.2l5.7,0.0L23.6,7.0C23.2,6.7 18.7,3.0 12.0,3.0C5.3,3.0 0.8,6.7 0.4,7.0L12.0,21.5l0.0,0.0l0.0,0.0l1.8,-2.2L13.8,12.2z"
+        android:fillAlpha="0.3"
+        android:fillColor="#FFFFFF"/>
     <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M21.000000,20.000000l2.000000,0.000000l0.000000,2.000000l-2.000000,0.000000z"/>
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M21.000000,10.000000l2.000000,0.000000l0.000000,8.100000l-2.000000,0.000000z"/>
+        android:pathData="M21.9,15.4l-1.1,-1.2 -1.9,1.900001 -1.9,-1.900001 -1.1,1.2 1.9,1.9 -1.9,1.800001 1.1,1.199999 1.9,-1.9 1.9,1.9 1.1,-1.199999 -1.799999,-1.800001z"
+        android:fillColor="#FFFFFF"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_2.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_2.xml
index f2043fc..1982130 100644
--- a/packages/SystemUI/res/drawable/ic_qs_wifi_2.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_wifi_2.xml
@@ -1,7 +1,7 @@
 <!--
-Copyright (C) 2014 The Android Open Source Project
+    Copyright (C) 2016 The Android Open Source Project
 
-   Licensed under the Apache License, Version 2.0 (the "License");
+    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
 
@@ -14,20 +14,18 @@
     limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="32.0dp"
-        android:height="29.5dp"
-        android:viewportWidth="26.0"
+        android:width="24.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="24.0"
         android:viewportHeight="24.0">
     <path
-        android:fillColor="#4DFFFFFF"
-        android:pathData="M19.000000,8.000000l5.300000,0.000000l1.300000,-1.600000C25.100000,6.000000 20.299999,2.000000 13.000000,2.000000S0.900000,6.000000 0.400000,6.400000L13.000000,22.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l6.000000,-7.400000L19.000000,8.000000z"/>
+        android:pathData="M13.8,12.2l4.9,0.0c-1.0,-0.7 -3.4,-2.2 -6.7,-2.2c-4.1,0.0 -6.9,2.2 -7.2,2.5l7.2,9.0l0.0,0.0l0.0,0.0l1.8,-2.2L13.800001,12.2z"
+        android:fillColor="#FFFFFF"/>
     <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M19.000000,11.600000c-1.300000,-0.700000 -3.400000,-1.600000 -6.000000,-1.600000c-4.400000,0.000000 -7.300000,2.400000 -7.600000,2.700000L13.000000,22.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l6.000000,-7.400000L19.000000,11.600000z"/>
+        android:pathData="M13.8,12.2l5.7,0.0L23.6,7.0C23.2,6.7 18.7,3.0 12.0,3.0C5.3,3.0 0.8,6.7 0.4,7.0L12.0,21.5l0.0,0.0l0.0,0.0l1.8,-2.2L13.8,12.2z"
+        android:fillAlpha="0.3"
+        android:fillColor="#FFFFFF"/>
     <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M21.000000,20.000000l2.000000,0.000000l0.000000,2.000000l-2.000000,0.000000z"/>
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M21.000000,10.000000l2.000000,0.000000l0.000000,8.100000l-2.000000,0.000000z"/>
+        android:pathData="M21.9,15.4l-1.1,-1.2 -1.9,1.900001 -1.9,-1.900001 -1.1,1.2 1.800001,1.9 -1.800001,1.800001 1.1,1.199999 1.9,-1.9 1.9,1.9 1.1,-1.199999 -1.9,-1.800001z"
+        android:fillColor="#FFFFFF"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_3.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_3.xml
index b7a4f4c..b350111 100644
--- a/packages/SystemUI/res/drawable/ic_qs_wifi_3.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_wifi_3.xml
@@ -1,7 +1,7 @@
 <!--
-Copyright (C) 2014 The Android Open Source Project
+    Copyright (C) 2016 The Android Open Source Project
 
-   Licensed under the Apache License, Version 2.0 (the "License");
+    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
 
@@ -14,20 +14,18 @@
     limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="32.0dp"
-        android:height="29.5dp"
-        android:viewportWidth="26.0"
+        android:width="24.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="24.0"
         android:viewportHeight="24.0">
     <path
-        android:fillColor="#4DFFFFFF"
-        android:pathData="M19.000000,8.000000l5.300000,0.000000l1.300000,-1.600000C25.100000,6.000000 20.299999,2.000000 13.000000,2.000000S0.900000,6.000000 0.400000,6.400000L13.000000,22.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l6.000000,-7.400000L19.000000,8.000000z"/>
+        android:pathData="M13.8,12.2l5.7,0.0l1.0,-1.2C20.0,10.6 16.8,8.0 12.0,8.0s-8.0,2.6 -8.5,3.0L12.0,21.5l0.0,0.0l0.0,0.0l1.8,-2.2L13.8,12.2z"
+        android:fillColor="#FFFFFF"/>
     <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M19.000000,8.600000c-1.600000,-0.700000 -3.600000,-1.300000 -6.000000,-1.300000c-5.300000,0.000000 -8.900000,3.000000 -9.200000,3.200000L13.000000,22.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l6.000000,-7.400000L19.000000,8.600000z"/>
+        android:pathData="M13.8,12.2l5.7,0.0L23.6,7.0C23.2,6.7 18.7,3.0 12.0,3.0C5.3,3.0 0.8,6.7 0.4,7.0L12.0,21.5l0.0,0.0l0.0,0.0l1.8,-2.2L13.8,12.2z"
+        android:fillAlpha="0.3"
+        android:fillColor="#FFFFFF"/>
     <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M21.000000,20.000000l2.000000,0.000000l0.000000,2.000000l-2.000000,0.000000z"/>
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M21.000000,10.000000l2.000000,0.000000l0.000000,8.100000l-2.000000,0.000000z"/>
+        android:pathData="M21.9,15.4l-1.1,-1.2 -1.9,1.900001 -1.9,-1.900001 -1.1,1.2 1.9,1.9 -1.9,1.800001 1.1,1.199999 1.9,-1.9 1.9,1.9 1.1,-1.199999 -1.9,-1.800001z"
+        android:fillColor="#FFFFFF"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_wifi_4.xml b/packages/SystemUI/res/drawable/ic_qs_wifi_4.xml
index 35a9138..136a004 100644
--- a/packages/SystemUI/res/drawable/ic_qs_wifi_4.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_wifi_4.xml
@@ -1,7 +1,7 @@
 <!--
-Copyright (C) 2014 The Android Open Source Project
+    Copyright (C) 2016 The Android Open Source Project
 
-   Licensed under the Apache License, Version 2.0 (the "License");
+    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
 
@@ -14,17 +14,14 @@
     limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="32.0dp"
-        android:height="29.5dp"
-        android:viewportWidth="26.0"
+        android:width="24.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="24.0"
         android:viewportHeight="24.0">
     <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M19.000000,8.000000l5.300000,0.000000l1.300000,-1.600000C25.100000,6.000000 20.299999,2.000000 13.000000,2.000000S0.900000,6.000000 0.400000,6.400000L13.000000,22.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l6.000000,-7.400000L19.000000,8.000000z"/>
+        android:pathData="M13.8,12.2l5.7,0.0L23.6,7.0C23.2,6.7 18.7,3.0 12.0,3.0C5.3,3.0 0.8,6.7 0.4,7.0L12.0,21.5l0.0,0.0l0.0,0.0l1.8,-2.2L13.8,12.2z"
+        android:fillColor="#FFFFFF"/>
     <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M21.000000,20.000000l2.000000,0.000000l0.000000,2.000000l-2.000000,0.000000z"/>
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M21.000000,10.000000l2.000000,0.000000l0.000000,8.100000l-2.000000,0.000000z"/>
+        android:pathData="M21.9,15.4l-1.1,-1.2 -1.9,1.900001 -1.9,-1.900001 -1.1,1.2 1.9,1.9 -1.9,1.800001 1.1,1.199999 1.9,-1.9 1.9,1.9 1.1,-1.199999 -1.9,-1.800001z"
+        android:fillColor="#FFFFFF"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_0.xml b/packages/SystemUI/res/drawable/stat_sys_signal_0.xml
index 643c4f9..8bc872a 100644
--- a/packages/SystemUI/res/drawable/stat_sys_signal_0.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_signal_0.xml
@@ -1,7 +1,7 @@
 <!--
-Copyright (C) 2014 The Android Open Source Project
+    Copyright (C) 2016 The Android Open Source Project
 
-   Licensed under the Apache License, Version 2.0 (the "License");
+    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
 
@@ -15,17 +15,14 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:autoMirrored="true"
-        android:width="17dp"
-        android:height="17dp"
+        android:width="17.0dp"
+        android:height="17.0dp"
         android:viewportWidth="24.0"
         android:viewportHeight="24.0">
     <path
-        android:fillColor="?attr/singleToneColor"
-        android:pathData="M19.700001,20.000000l2.000000,0.000000l0.000000,2.000000l-2.000000,0.000000z"/>
-    <path
-        android:fillColor="?attr/singleToneColor"
-        android:pathData="M19.700001,10.000000l2.000000,0.000000l0.000000,8.100000l-2.000000,0.000000z"/>
-    <path
-        android:pathData="M17.700001,8.000000l4.299999,0.000000 0.000000,-6.000000 -20.000000,20.000000 15.700001,0.000000z"
+        android:pathData="M14.1,14.1l7.9,0.0 0.0,-11.5 -20.0,20.0 12.1,0.0z"
         android:fillColor="?attr/backgroundColor"/>
+    <path
+        android:pathData="M21.9,17.0l-1.1,-1.1 -1.9,1.9 -1.9,-1.9 -1.1,1.1 1.9,1.9 -1.9,1.9 1.1,1.1 1.9,-1.9 1.9,1.9 1.1,-1.1 -1.9,-1.9z"
+        android:fillColor="?attr/fillColor"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_1.xml b/packages/SystemUI/res/drawable/stat_sys_signal_1.xml
index 64781c3..8fa7630 100644
--- a/packages/SystemUI/res/drawable/stat_sys_signal_1.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_signal_1.xml
@@ -1,7 +1,7 @@
 <!--
-Copyright (C) 2014 The Android Open Source Project
+    Copyright (C) 2016 The Android Open Source Project
 
-   Licensed under the Apache License, Version 2.0 (the "License");
+    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
 
@@ -15,20 +15,17 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:autoMirrored="true"
-        android:width="17dp"
-        android:height="17dp"
+        android:width="17.0dp"
+        android:height="17.0dp"
         android:viewportWidth="24.0"
         android:viewportHeight="24.0">
     <path
-        android:fillColor="?attr/singleToneColor"
-        android:pathData="M19.7,20.0l2.0,0.0l0.0,2.0l-2.0,0.0z"/>
+        android:pathData="M10.0,14.6l-8.0,8.0l8.0,0.0l0,-8z"
+        android:fillColor="?attr/fillColor"/>
     <path
-        android:fillColor="?attr/singleToneColor"
-        android:pathData="M19.7,10.0l2.0,0.0l0.0,8.1l-2.0,0.0z"/>
+        android:pathData="M14.1,14.1l7.9,0.0 0.0,-11.5 -20.0,20.0 12.1,0.0z"
+        android:fillColor="?attr/backgroundColor"/>
     <path
-        android:fillColor="?attr/backgroundColor"
-        android:pathData="M17.7,8.0l4.299999,0.0 0.0,-6.0 -20.0,20.0 15.700001,0.0z"/>
-    <path
-        android:fillColor="?attr/fillColor"
-        android:pathData="M10.1,13.9l-8.1,8.1 8.1,0.0z"/>
+        android:pathData="M21.9,17.0l-1.1,-1.1 -1.9,1.9 -1.9,-1.9 -1.1,1.1 1.9,1.9 -1.9,1.9 1.1,1.1 1.9,-1.9 1.9,1.9 1.1,-1.1 -1.9,-1.9z"
+        android:fillColor="?attr/fillColor"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_2.xml b/packages/SystemUI/res/drawable/stat_sys_signal_2.xml
index eb2be08..2a660a3 100644
--- a/packages/SystemUI/res/drawable/stat_sys_signal_2.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_signal_2.xml
@@ -1,7 +1,7 @@
 <!--
-Copyright (C) 2014 The Android Open Source Project
+    Copyright (C) 2016 The Android Open Source Project
 
-   Licensed under the Apache License, Version 2.0 (the "License");
+    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
 
@@ -15,20 +15,17 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:autoMirrored="true"
-        android:width="17dp"
-        android:height="17dp"
+        android:width="17.0dp"
+        android:height="17.0dp"
         android:viewportWidth="24.0"
         android:viewportHeight="24.0">
     <path
-        android:fillColor="?attr/singleToneColor"
-        android:pathData="M19.700001,20.000000l2.000000,0.000000l0.000000,2.000000l-2.000000,0.000000z"/>
+        android:pathData="M14.0,10.6l-12.0,12.0l12.0,0.0L14.0,10.6z"
+        android:fillColor="?attr/fillColor"/>
     <path
-        android:fillColor="?attr/singleToneColor"
-        android:pathData="M19.700001,10.000000l2.000000,0.000000l0.000000,8.100000l-2.000000,0.000000z"/>
-    <path
-        android:fillColor="?attr/fillColor"
-        android:pathData="M13.900000,10.000000l-11.900000,12.000000 11.900000,0.000000z"/>
-    <path
-        android:pathData="M17.700001,8.000000l4.299999,0.000000 0.000000,-6.000000 -20.000000,20.000000 15.700001,0.000000z"
+        android:pathData="M14.1,14.1l7.9,0.0 0.0,-11.5 -20.0,20.0 12.1,0.0z"
         android:fillColor="?attr/backgroundColor"/>
+    <path
+        android:pathData="M21.9,17.0l-1.1,-1.1 -1.9,1.9 -1.9,-1.9 -1.1,1.1 1.9,1.9 -1.9,1.9 1.1,1.1 1.9,-1.9 1.9,1.9 1.1,-1.1 -1.9,-1.9z"
+        android:fillColor="?attr/fillColor"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_3.xml b/packages/SystemUI/res/drawable/stat_sys_signal_3.xml
index 22afad0..9e0a433 100644
--- a/packages/SystemUI/res/drawable/stat_sys_signal_3.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_signal_3.xml
@@ -1,7 +1,7 @@
 <!--
-Copyright (C) 2014 The Android Open Source Project
+    Copyright (C) 2016 The Android Open Source Project
 
-   Licensed under the Apache License, Version 2.0 (the "License");
+    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
 
@@ -15,20 +15,17 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:autoMirrored="true"
-        android:width="17dp"
-        android:height="17dp"
+        android:width="17.0dp"
+        android:height="17.0dp"
         android:viewportWidth="24.0"
         android:viewportHeight="24.0">
     <path
-        android:fillColor="?attr/singleToneColor"
-        android:pathData="M19.700001,19.900000l2.000000,0.000000l0.000000,2.000000l-2.000000,0.000000z"/>
-    <path
-        android:fillColor="?attr/singleToneColor"
-        android:pathData="M19.700001,9.900000l2.000000,0.000000l0.000000,8.100000l-2.000000,0.000000z"/>
-    <path
-        android:fillColor="?attr/fillColor"
-        android:pathData="M16.700001,7.200000l-14.700001,14.700000 14.700001,0.000000z"/>
-    <path
-        android:pathData="M17.700001,7.900000l4.299999,0.000000 0.000000,-6.000000 -20.000000,20.000000 15.700001,0.000000z"
+        android:pathData="M14.1,14.1l7.9,0.0 0.0,-11.5 -20.0,20.0 12.1,0.0z"
         android:fillColor="?attr/backgroundColor"/>
+    <path
+        android:pathData="M21.9,17.0l-1.1,-1.1 -1.9,1.9 -1.9,-1.9 -1.1,1.1 1.9,1.9 -1.9,1.9 1.1,1.1 1.9,-1.9 1.9,1.9 1.1,-1.1 -1.9,-1.9z"
+        android:fillColor="?attr/fillColor"/>
+    <path
+        android:pathData="M14.1,14.1l2.9,0.0 0.0,-6.5 -15.0,15.0 12.1,0.0z"
+        android:fillColor="?attr/fillColor"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_signal_4.xml b/packages/SystemUI/res/drawable/stat_sys_signal_4.xml
index d1e866d..01f6703 100644
--- a/packages/SystemUI/res/drawable/stat_sys_signal_4.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_signal_4.xml
@@ -1,7 +1,7 @@
 <!--
-Copyright (C) 2014 The Android Open Source Project
+    Copyright (C) 2016 The Android Open Source Project
 
-   Licensed under the Apache License, Version 2.0 (the "License");
+    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
 
@@ -15,18 +15,14 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:autoMirrored="true"
-        android:width="17dp"
-        android:height="17dp"
+        android:width="17.0dp"
+        android:height="17.0dp"
         android:viewportWidth="24.0"
         android:viewportHeight="24.0">
-
     <path
-        android:fillColor="?attr/singleToneColor"
-        android:pathData="M19.700001,20.000000l2.000000,0.000000l0.000000,2.000000l-2.000000,0.000000z"/>
+        android:pathData="M14.1,14.1l7.9,0.0 0.0,-11.5 -20.0,20.0 12.1,0.0z"
+        android:fillColor="?attr/fillColor"/>
     <path
-        android:fillColor="?attr/singleToneColor"
-        android:pathData="M19.700001,10.000000l2.000000,0.000000l0.000000,8.100000l-2.000000,0.000000z"/>
-    <path
-        android:fillColor="?attr/singleToneColor"
-        android:pathData="M2.000000,22.000000l15.700001,0.000000 0.000000,-14.000000 4.299999,0.000000 0.000000,-6.000000z"/>
+        android:pathData="M21.9,17.0l-1.1,-1.1 -1.9,1.9 -1.9,-1.9 -1.1,1.1 1.9,1.9 -1.9,1.9 1.1,1.1 1.9,-1.9 1.9,1.9 1.1,-1.1 -1.9,-1.9z"
+        android:fillColor="?attr/fillColor"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_0.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_0.xml
index 7f1b715e..2de2e36 100644
--- a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_0.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_0.xml
@@ -1,7 +1,7 @@
 <!--
-Copyright (C) 2014 The Android Open Source Project
+    Copyright (C) 2016 The Android Open Source Project
 
-   Licensed under the Apache License, Version 2.0 (the "License");
+    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
 
@@ -15,16 +15,13 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="18.41dp"
-        android:height="17dp"
-        android:viewportWidth="26.0"
+        android:height="18.41dp"
+        android:viewportWidth="24.0"
         android:viewportHeight="24.0">
     <path
-        android:fillColor="?attr/backgroundColor"
-        android:pathData="M19.000000,8.000000l5.300000,0.000000l1.200000,-1.500000C25.100000,6.100000 20.299999,2.100000 13.000000,2.100000S0.900000,6.100000 0.400000,6.500000L13.000000,22.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l6.000000,-7.400000L19.000000,8.000000z"/>
+        android:pathData="M13.8,12.2l5.7,0.0L23.6,7.0C23.2,6.7 18.7,3.0 12.0,3.0C5.3,3.0 0.8,6.7 0.4,7.0L12.0,21.5l0.0,0.0l0.0,0.0l1.8,-2.2L13.8,12.2z"
+        android:fillColor="?attr/backgroundColor"/>
     <path
-        android:fillColor="?attr/fillColor"
-        android:pathData="M21.000000,20.000000l2.000000,0.000000l0.000000,2.000000l-2.000000,0.000000z"/>
-    <path
-        android:fillColor="?attr/fillColor"
-        android:pathData="M21.000000,10.000000l2.000000,0.000000l0.000000,8.100000l-2.000000,0.000000z"/>
+        android:pathData="M21.9,15.4l-1.1,-1.2 -1.9,1.900001 -1.9,-1.900001 -1.1,1.2 1.9,1.9 -1.9,1.800001 1.1,1.199999 1.9,-1.9 1.9,1.9 1.1,-1.199999 -1.799999,-1.800001z"
+        android:fillColor="?attr/fillColor"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_1.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_1.xml
index acd89be..144a7c1 100644
--- a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_1.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_1.xml
@@ -1,7 +1,7 @@
 <!--
-Copyright (C) 2014 The Android Open Source Project
+    Copyright (C) 2016 The Android Open Source Project
 
-   Licensed under the Apache License, Version 2.0 (the "License");
+    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
 
@@ -15,19 +15,16 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="18.41dp"
-        android:height="17dp"
-        android:viewportWidth="26.0"
+        android:height="18.41dp"
+        android:viewportWidth="24.0"
         android:viewportHeight="24.0">
     <path
-        android:fillColor="?attr/backgroundColor"
-        android:pathData="M19.000000,8.000000l5.300000,0.000000l1.300000,-1.600000C25.100000,6.000000 20.299999,2.000000 13.000000,2.000000S0.900000,6.000000 0.400000,6.400000L13.000000,22.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l6.000000,-7.400000L19.000000,8.000000z"/>
+        android:pathData="M13.8,13.2c-0.1,0.0 -0.3,-0.1 -0.4,-0.1c-0.1,0.0 -0.3,0.0 -0.4,-0.1c-0.3,0.0 -0.6,-0.1 -0.9,-0.1c0.0,0.0 0.0,0.0 -0.1,0.0c0.0,0.0 0.0,0.0 0.0,0.0s0.0,0.0 0.0,0.0c0.0,0.0 0.0,0.0 -0.1,0.0c-0.3,0.0 -0.6,0.0 -0.9,0.1c-0.1,0.0 -0.3,0.0 -0.4,0.1c-0.2,0.0 -0.3,0.1 -0.5,0.1c-0.2,0.0 -0.3,0.1 -0.5,0.1c-0.1,0.0 -0.1,0.0 -0.2,0.1c-1.6,0.5 -2.7,1.3 -2.8,1.5l5.3,6.6l0.0,0.0l0.0,0.0l0.0,0.0l0.0,0.0l1.8,-2.2L13.700002,13.2z"
+        android:fillColor="?attr/fillColor"/>
     <path
-        android:fillColor="?attr/fillColor"
-        android:pathData="M13.000000,22.000000l5.500000,-6.800000c-0.200000,-0.200000 -2.300000,-1.900000 -5.500000,-1.900000s-5.300000,1.800000 -5.500000,1.900000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000L13.000000,22.000000z"/>
+        android:pathData="M13.8,12.2l5.7,0.0L23.6,7.0C23.2,6.7 18.7,3.0 12.0,3.0C5.3,3.0 0.8,6.7 0.4,7.0L12.0,21.5l0.0,0.0l0.0,0.0l1.8,-2.2L13.8,12.2z"
+        android:fillColor="?attr/backgroundColor"/>
     <path
-        android:fillColor="?attr/fillColor"
-        android:pathData="M21.000000,20.000000l2.000000,0.000000l0.000000,2.000000l-2.000000,0.000000z"/>
-    <path
-        android:fillColor="?attr/fillColor"
-        android:pathData="M21.000000,10.000000l2.000000,0.000000l0.000000,8.100000l-2.000000,0.000000z"/>
+        android:pathData="M21.9,15.4l-1.1,-1.2 -1.9,1.900001 -1.9,-1.900001 -1.1,1.2 1.9,1.9 -1.9,1.800001 1.1,1.199999 1.9,-1.9 1.9,1.9 1.1,-1.199999 -1.799999,-1.800001z"
+        android:fillColor="?attr/fillColor"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_2.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_2.xml
index f33b25c..6b7f712 100644
--- a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_2.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_2.xml
@@ -1,7 +1,7 @@
 <!--
-Copyright (C) 2014 The Android Open Source Project
+    Copyright (C) 2016 The Android Open Source Project
 
-   Licensed under the Apache License, Version 2.0 (the "License");
+    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
 
@@ -15,19 +15,16 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="18.41dp"
-        android:height="17dp"
-        android:viewportWidth="26.0"
+        android:height="18.41dp"
+        android:viewportWidth="24.0"
         android:viewportHeight="24.0">
     <path
-        android:fillColor="?attr/backgroundColor"
-        android:pathData="M19.000000,8.000000l5.300000,0.000000l1.300000,-1.600000C25.100000,6.000000 20.299999,2.000000 13.000000,2.000000S0.900000,6.000000 0.400000,6.400000L13.000000,22.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l6.000000,-7.400000L19.000000,8.000000z"/>
+        android:pathData="M13.8,12.2l4.9,0.0c-1.0,-0.7 -3.4,-2.2 -6.7,-2.2c-4.1,0.0 -6.9,2.2 -7.2,2.5l7.2,9.0l0.0,0.0l0.0,0.0l1.8,-2.2L13.800001,12.2z"
+        android:fillColor="?attr/fillColor"/>
     <path
-        android:fillColor="?attr/fillColor"
-        android:pathData="M19.000000,11.600000c-1.300000,-0.700000 -3.400000,-1.600000 -6.000000,-1.600000c-4.400000,0.000000 -7.300000,2.400000 -7.600000,2.700000L13.000000,22.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l6.000000,-7.400000L19.000000,11.600000z"/>
+        android:pathData="M13.8,12.2l5.7,0.0L23.6,7.0C23.2,6.7 18.7,3.0 12.0,3.0C5.3,3.0 0.8,6.7 0.4,7.0L12.0,21.5l0.0,0.0l0.0,0.0l1.8,-2.2L13.8,12.2z"
+        android:fillColor="?attr/backgroundColor"/>
     <path
-        android:fillColor="?attr/fillColor"
-        android:pathData="M21.000000,20.000000l2.000000,0.000000l0.000000,2.000000l-2.000000,0.000000z"/>
-    <path
-        android:fillColor="?attr/fillColor"
-        android:pathData="M21.000000,10.000000l2.000000,0.000000l0.000000,8.100000l-2.000000,0.000000z"/>
+        android:pathData="M21.9,15.4l-1.1,-1.2 -1.9,1.900001 -1.9,-1.900001 -1.1,1.2 1.800001,1.9 -1.800001,1.800001 1.1,1.199999 1.9,-1.9 1.9,1.9 1.1,-1.199999 -1.9,-1.800001z"
+        android:fillColor="?attr/fillColor"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_3.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_3.xml
index 09d2e50..d34b4de 100644
--- a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_3.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_3.xml
@@ -1,7 +1,7 @@
 <!--
-Copyright (C) 2014 The Android Open Source Project
+    Copyright (C) 2016 The Android Open Source Project
 
-   Licensed under the Apache License, Version 2.0 (the "License");
+    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
 
@@ -15,19 +15,16 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="18.41dp"
-        android:height="17dp"
-        android:viewportWidth="26.0"
+        android:height="18.41dp"
+        android:viewportWidth="24.0"
         android:viewportHeight="24.0">
     <path
-        android:fillColor="?attr/backgroundColor"
-        android:pathData="M19.000000,8.000000l5.300000,0.000000l1.300000,-1.600000C25.100000,6.000000 20.299999,2.000000 13.000000,2.000000S0.900000,6.000000 0.400000,6.400000L13.000000,22.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l6.000000,-7.400000L19.000000,8.000000z"/>
+        android:pathData="M13.8,12.2l5.7,0.0l1.0,-1.2C20.0,10.6 16.8,8.0 12.0,8.0s-8.0,2.6 -8.5,3.0L12.0,21.5l0.0,0.0l0.0,0.0l1.8,-2.2L13.8,12.2z"
+        android:fillColor="?attr/fillColor"/>
     <path
-        android:fillColor="?attr/fillColor"
-        android:pathData="M19.000000,8.600000c-1.600000,-0.700000 -3.600000,-1.300000 -6.000000,-1.300000c-5.300000,0.000000 -8.900000,3.000000 -9.200000,3.200000L13.000000,22.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l6.000000,-7.400000L19.000000,8.600000z"/>
+        android:pathData="M13.8,12.2l5.7,0.0L23.6,7.0C23.2,6.7 18.7,3.0 12.0,3.0C5.3,3.0 0.8,6.7 0.4,7.0L12.0,21.5l0.0,0.0l0.0,0.0l1.8,-2.2L13.8,12.2z"
+        android:fillColor="?attr/backgroundColor"/>
     <path
-        android:fillColor="?attr/fillColor"
-        android:pathData="M21.000000,20.000000l2.000000,0.000000l0.000000,2.000000l-2.000000,0.000000z"/>
-    <path
-        android:fillColor="?attr/fillColor"
-        android:pathData="M21.000000,10.000000l2.000000,0.000000l0.000000,8.100000l-2.000000,0.000000z"/>
+        android:pathData="M21.9,15.4l-1.1,-1.2 -1.9,1.900001 -1.9,-1.900001 -1.1,1.2 1.9,1.9 -1.9,1.800001 1.1,1.199999 1.9,-1.9 1.9,1.9 1.1,-1.199999 -1.9,-1.800001z"
+        android:fillColor="?attr/fillColor"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_4.xml b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_4.xml
index fb1f584..5701356 100644
--- a/packages/SystemUI/res/drawable/stat_sys_wifi_signal_4.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_wifi_signal_4.xml
@@ -1,7 +1,7 @@
 <!--
-Copyright (C) 2014 The Android Open Source Project
+    Copyright (C) 2016 The Android Open Source Project
 
-   Licensed under the Apache License, Version 2.0 (the "License");
+    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
 
@@ -15,16 +15,13 @@
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
         android:width="18.41dp"
-        android:height="17dp"
-        android:viewportWidth="26.0"
+        android:height="18.41dp"
+        android:viewportWidth="24.0"
         android:viewportHeight="24.0">
     <path
-        android:fillColor="?attr/singleToneColor"
-        android:pathData="M19.000000,8.000000l5.300000,0.000000l1.300000,-1.600000C25.100000,6.000000 20.299999,2.000000 13.000000,2.000000S0.900000,6.000000 0.400000,6.400000L13.000000,22.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l0.000000,0.000000l6.000000,-7.400000L19.000000,8.000000z"/>
+        android:pathData="M13.8,12.2l5.7,0.0L23.6,7.0C23.2,6.7 18.7,3.0 12.0,3.0C5.3,3.0 0.8,6.7 0.4,7.0L12.0,21.5l0.0,0.0l0.0,0.0l1.8,-2.2L13.8,12.2z"
+        android:fillColor="?attr/fillColor"/>
     <path
-        android:fillColor="?attr/singleToneColor"
-        android:pathData="M21.000000,20.000000l2.000000,0.000000l0.000000,2.000000l-2.000000,0.000000z"/>
-    <path
-        android:fillColor="?attr/singleToneColor"
-        android:pathData="M21.000000,10.000000l2.000000,0.000000l0.000000,8.100000l-2.000000,0.000000z"/>
+        android:pathData="M21.9,15.4l-1.1,-1.2 -1.9,1.900001 -1.9,-1.900001 -1.1,1.2 1.9,1.9 -1.9,1.800001 1.1,1.199999 1.9,-1.9 1.9,1.9 1.1,-1.199999 -1.9,-1.800001z"
+        android:fillColor="?attr/fillColor"/>
 </vector>
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
index 261d241..56f6b8d 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
@@ -60,6 +60,11 @@
     private static final String ACTION_BASE = "com.android.systemui.doze";
     private static final String PULSE_ACTION = ACTION_BASE + ".pulse";
 
+    /**
+     * If true, reregisters all trigger sensors when the screen turns off.
+     */
+    private static final boolean REREGISTER_ALL_SENSORS_ON_SCREEN_OFF = true;
+
     private final String mTag = String.format(TAG + ".%08x", hashCode());
     private final Context mContext = this;
     private final DozeParameters mDozeParameters = new DozeParameters(mContext);
@@ -272,6 +277,9 @@
             public void onPulseFinished() {
                 if (mPulsing && mDreaming) {
                     mPulsing = false;
+                    if (REREGISTER_ALL_SENSORS_ON_SCREEN_OFF) {
+                        reregisterAllSensors();
+                    }
                     turnDisplayOff();
                 }
                 mWakeLock.release(); // needs to be unconditional to balance acquire
@@ -308,6 +316,15 @@
         listenForNotifications(listen);
     }
 
+    private void reregisterAllSensors() {
+        for (TriggerSensor s : mSensors) {
+            s.setListening(false);
+        }
+        for (TriggerSensor s : mSensors) {
+            s.setListening(true);
+        }
+    }
+
     private void listenForBroadcasts(boolean listen) {
         if (listen) {
             final IntentFilter filter = new IntentFilter(PULSE_ACTION);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index 7207463..5b25f052 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -18,12 +18,10 @@
 
 import android.app.ActivityManager;
 import android.app.UiModeManager;
-import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.ServiceConnection;
 import android.content.pm.ActivityInfo;
 import android.content.res.Configuration;
@@ -99,7 +97,7 @@
     // and does not reside in the home stack.
     private String mOverrideRecentsPackageName;
 
-    private Handler mHandler = new Handler();
+    private Handler mHandler;
     private RecentsImpl mImpl;
     private int mDraggingInRecentsCurrentUser;
 
@@ -165,20 +163,6 @@
         }
     };
 
-
-    private BroadcastReceiver mSystemUserUnlockedReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            if (Intent.ACTION_USER_UNLOCKED.equals(intent.getAction())) {
-                int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
-                if (userId != UserHandle.USER_NULL) {
-                    mImpl.onUserUnlocked(userId);
-                }
-            }
-        }
-    };
-
-
     /**
      * Returns the callbacks interface that non-system users can call.
      */
@@ -208,7 +192,7 @@
         sSystemServicesProxy = SystemServicesProxy.getInstance(mContext);
         sTaskLoader = new RecentsTaskLoader(mContext);
         sConfiguration = new RecentsConfiguration(mContext);
-
+        mHandler = new Handler();
         UiModeManager uiModeManager = (UiModeManager) mContext.
                 getSystemService(Context.UI_MODE_SERVICE);
         if (uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION) {
@@ -238,12 +222,6 @@
             // For the system user, initialize an instance of the interface that we can pass to the
             // secondary user
             mSystemToUserCallbacks = new RecentsSystemUser(mContext, mImpl);
-
-            // Listen for user-unlocked to kick off preloading recents
-            IntentFilter filter = new IntentFilter();
-            filter.addAction(Intent.ACTION_USER_UNLOCKED);
-            mContext.registerReceiverAsUser(mSystemUserUnlockedReceiver, UserHandle.SYSTEM, filter,
-                    null /* permission */, null /* scheduler */);
         } else {
             // For the secondary user, bind to the primary user's service to get a persistent
             // interface to register its implementation and to later update its state
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 390ef87..64ef997 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -188,7 +188,7 @@
         reloadResources();
     }
 
-    public void onUserUnlocked(int userId) {
+    public void onBootCompleted() {
         // When we start, preload the data associated with the previous recent tasks.
         // We can use a new plan since the caches will be the same.
         RecentsTaskLoader loader = Recents.getTaskLoader();
@@ -201,10 +201,6 @@
         loader.loadTasks(mContext, plan, launchOpts);
     }
 
-    public void onBootCompleted() {
-        // Do nothing
-    }
-
     public void onConfigurationChanged() {
         Resources res = mContext.getResources();
         reloadResources();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/animations/HomeRecentsEnterExitAnimationHolder.java b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/HomeRecentsEnterExitAnimationHolder.java
index 9faaa4b..a673c8c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/animations/HomeRecentsEnterExitAnimationHolder.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/HomeRecentsEnterExitAnimationHolder.java
@@ -47,12 +47,13 @@
     public void startEnterAnimation(boolean isPipShown) {
         for(int i = 0; i < mGridView.getChildCount(); i++) {
             TaskCardView view = (TaskCardView) mGridView.getChildAt(i);
+            long delay = Math.max(mDelay * i, 0);
             view.setTranslationX(-mTranslationX);
             view.animate()
                     .alpha(isPipShown ? mDimAlpha : 1.0f)
                     .translationX(0)
                     .setDuration(mDuration)
-                    .setStartDelay(mDelay * i)
+                    .setStartDelay(delay)
                     .setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
         }
     }
@@ -60,11 +61,12 @@
     public void startExitAnimation(DismissRecentsToHomeAnimationStarted dismissEvent) {
         for(int i = mGridView.getChildCount() - 1; i >= 0; i--) {
             TaskCardView view = (TaskCardView) mGridView.getChildAt(i);
+            long delay = Math.max(mDelay * (mGridView.getChildCount() - 1 - i), 0);
             view.animate()
                     .alpha(0.0f)
                     .translationXBy(-mTranslationX)
                     .setDuration(mDuration)
-                    .setStartDelay(mDelay * (mGridView.getChildCount() - 1 - i))
+                    .setStartDelay(delay)
                     .setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
             if(i == 0) {
                 view.animate().setListener(dismissEvent.getAnimationTrigger()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index cf962df..0ef97152 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -95,8 +95,6 @@
         KeyguardUpdateMonitor.getInstance(context).registerCallback(mUpdateMonitor);
         context.registerReceiverAsUser(mTickReceiver, UserHandle.SYSTEM,
                 new IntentFilter(Intent.ACTION_TIME_TICK), null, null);
-        context.registerReceiverAsUser(mUnlockReceiver, UserHandle.ALL,
-                new IntentFilter(Intent.ACTION_USER_UNLOCKED), null, null);
     }
 
     public void setVisible(boolean visible) {
@@ -322,6 +320,13 @@
             super.onFingerprintAuthFailed();
             mLastSuccessiveErrorMessage = -1;
         }
+
+        @Override
+        public void onUserUnlocked() {
+            if (mVisible) {
+                updateIndication();
+            }
+        }
     };
 
     BroadcastReceiver mTickReceiver = new BroadcastReceiver() {
@@ -333,14 +338,6 @@
         }
     };
 
-    BroadcastReceiver mUnlockReceiver = new BroadcastReceiver() {
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            if (mVisible) {
-                updateIndication();
-            }
-        }
-    };
 
     private final Handler mHandler = new Handler() {
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index 4270147..f9b7bb5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -122,6 +122,7 @@
     private KeyguardIndicationController mIndicationController;
     private AccessibilityController mAccessibilityController;
     private PhoneStatusBar mPhoneStatusBar;
+    private KeyguardAffordanceHelper mAffordanceHelper;
 
     private boolean mUserSetupComplete;
     private boolean mPrewarmBound;
@@ -308,6 +309,10 @@
         updateCameraVisibility(); // in case onFinishInflate() was called too early
     }
 
+    public void setAffordanceHelper(KeyguardAffordanceHelper affordanceHelper) {
+        mAffordanceHelper = affordanceHelper;
+    }
+
     public void setUserSetupComplete(boolean userSetupComplete) {
         mUserSetupComplete = userSetupComplete;
         updateCameraVisibility();
@@ -620,6 +625,9 @@
             mPreviewContainer.addView(mCameraPreview);
             mCameraPreview.setVisibility(visibleBefore ? View.VISIBLE : View.INVISIBLE);
         }
+        if (mAffordanceHelper != null) {
+            mAffordanceHelper.updatePreviews();
+        }
     }
 
     private void updateLeftPreview() {
@@ -637,6 +645,9 @@
             mPreviewContainer.addView(mLeftPreview);
             mLeftPreview.setVisibility(View.INVISIBLE);
         }
+        if (mAffordanceHelper != null) {
+            mAffordanceHelper.updatePreviews();
+        }
     }
 
     public void startFinishDozeAnimation() {
@@ -720,6 +731,13 @@
                 @Override
                 public void onStrongAuthStateChanged(int userId) {
                     mLockIcon.update();
+        }
+
+                @Override
+                public void onUserUnlocked() {
+                    inflateCameraPreview();
+                    updateCameraVisibility();
+                    updateLeftAffordance();
                 }
             };
 
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 fb2c335..9c1eaa6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -233,6 +233,7 @@
         mKeyguardBottomArea = (KeyguardBottomAreaView) findViewById(R.id.keyguard_bottom_area);
         mQsNavbarScrim = findViewById(R.id.qs_navbar_scrim);
         mAfforanceHelper = new KeyguardAffordanceHelper(this, getContext());
+        mKeyguardBottomArea.setAffordanceHelper(mAfforanceHelper);
         mLastOrientation = getResources().getConfiguration().orientation;
 
         mQsAutoReinflateContainer =
@@ -1016,7 +1017,6 @@
             mKeyguardStatusBar.setVisibility(keyguardShowing ? View.VISIBLE : View.INVISIBLE);
             if (keyguardShowing && oldState != mStatusBarState) {
                 mKeyguardBottomArea.onKeyguardShowingChanged();
-                mAfforanceHelper.updatePreviews();
             }
         }
         if (keyguardShowing) {
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 66ca11c..221cc91 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -2749,7 +2749,7 @@
     public void handleSystemNavigationKey(int key) {
         if (SPEW) Log.d(TAG, "handleSystemNavigationKey: " + key);
         if (!panelsEnabled() || !mKeyguardMonitor.isDeviceInteractive()
-                || mKeyguardMonitor.isShowing()) {
+                || mKeyguardMonitor.isShowing() && !mKeyguardMonitor.isOccluded()) {
             return;
         }
 
@@ -3435,6 +3435,9 @@
         if (KeyguardUpdateMonitor.getInstance(mContext) != null) {
             KeyguardUpdateMonitor.getInstance(mContext).dump(fd, pw, args);
         }
+        if (mFlashlightController != null) {
+            mFlashlightController.dump(fd, pw, args);
+        }
 
         FalsingManager.getInstance(mContext).dump(pw);
         FalsingLog.dump(pw);
@@ -4392,7 +4395,8 @@
         checkBarModes();
         updateMediaMetaData(false, mState != StatusBarState.KEYGUARD);
         mKeyguardMonitor.notifyKeyguardState(mStatusBarKeyguardViewManager.isShowing(),
-                mStatusBarKeyguardViewManager.isSecure());
+                mStatusBarKeyguardViewManager.isSecure(),
+                mStatusBarKeyguardViewManager.isOccluded());
         Trace.endSection();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java
index 91b21ed..4e9fc76 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightController.java
@@ -27,6 +27,8 @@
 import android.text.TextUtils;
 import android.util.Log;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 
@@ -80,6 +82,7 @@
     public void setFlashlight(boolean enabled) {
         boolean pendingError = false;
         synchronized (this) {
+            if (mCameraId == null) return;
             if (mFlashlightEnabled != enabled) {
                 mFlashlightEnabled = enabled;
                 try {
@@ -235,6 +238,17 @@
         }
     };
 
+    public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        pw.println("FlashlightController state:");
+
+        pw.print("  mCameraId=");
+        pw.println(mCameraId);
+        pw.print("  mFlashlightEnabled=");
+        pw.println(mFlashlightEnabled);
+        pw.print("  mTorchAvailable=");
+        pw.println(mTorchAvailable);
+    }
+
     public interface FlashlightListener {
 
         /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
index c175180..44816f9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
@@ -38,6 +38,7 @@
     private int mCurrentUser;
     private boolean mShowing;
     private boolean mSecure;
+    private boolean mOccluded;
     private boolean mCanSkipBouncer;
 
     private boolean mListening;
@@ -81,6 +82,10 @@
         return mSecure;
     }
 
+    public boolean isOccluded() {
+        return mOccluded;
+    }
+
     public boolean canSkipBouncer() {
         return mCanSkipBouncer;
     }
@@ -99,10 +104,11 @@
         }
     }
 
-    public void notifyKeyguardState(boolean showing, boolean secure) {
-        if (mShowing == showing && mSecure == secure) return;
+    public void notifyKeyguardState(boolean showing, boolean secure, boolean occluded) {
+        if (mShowing == showing && mSecure == secure && mOccluded == occluded) return;
         mShowing = showing;
         mSecure = secure;
+        mOccluded = occluded;
         notifyKeyguardChanged();
     }
 
diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp
index 06c4350..af370ff 100644
--- a/rs/jni/android_renderscript_RenderScript.cpp
+++ b/rs/jni/android_renderscript_RenderScript.cpp
@@ -644,7 +644,7 @@
     in_allocs[2] = (RsAllocation)C;
 
     rsScriptForEachMulti((RsContext)con, (RsScript)id, 0,
-                         in_allocs, sizeof(in_allocs), nullptr,
+                         in_allocs, NELEM(in_allocs), nullptr,
                          &call, sizeof(call), nullptr, 0);
 }
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 9f2d447..e85fa25 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -3101,7 +3101,7 @@
         synchronized (this) {
             ActivityRecord r = mStackSupervisor.isInAnyStackLocked(token);
             if (r != null) {
-                r.task.stack.notifyActivityDrawnLocked(r);
+                r.getStack().notifyActivityDrawnLocked(r);
             }
         }
     }
@@ -4749,7 +4749,7 @@
                 return;
             }
             TaskRecord task = r.task;
-            if (task != null && (!task.mFullscreen || !task.stack.mFullscreen)) {
+            if (task != null && (!task.mFullscreen || !task.getStack().mFullscreen)) {
                 // Fixed screen orientation isn't supported when activities aren't in full screen
                 // mode.
                 return;
@@ -4789,7 +4789,7 @@
             final long origId = Binder.clearCallingIdentity();
             try {
                 r.forceNewConfig = true;
-                r.task.stack.ensureActivityConfigurationLocked(r, 0, false);
+                r.getStack().ensureActivityConfigurationLocked(r, 0, false);
             } finally {
                 Binder.restoreCallingIdentity(origId);
             }
@@ -4835,7 +4835,7 @@
             }
             if (mController != null) {
                 // Find the first activity that is not finishing.
-                ActivityRecord next = r.task.stack.topRunningActivityLocked(token, 0);
+                ActivityRecord next = r.getStack().topRunningActivityLocked(token, 0);
                 if (next != null) {
                     // ask watcher if this is allowed
                     boolean resumeOK = true;
@@ -4869,7 +4869,7 @@
                         Slog.i(TAG, "Removing task failed to finish activity");
                     }
                 } else {
-                    res = tr.stack.requestFinishActivityLocked(token, resultCode,
+                    res = tr.getStack().requestFinishActivityLocked(token, resultCode,
                             resultData, "app-request", true);
                     if (!res) {
                         Slog.i(TAG, "Failed to finish by app-request");
@@ -4903,7 +4903,7 @@
             for (int i = 0; i < activities.size(); i++) {
                 ActivityRecord r = activities.get(i);
                 if (!r.finishing && r.isInStackLocked()) {
-                    r.task.stack.finishActivityLocked(r, Activity.RESULT_CANCELED,
+                    r.getStack().finishActivityLocked(r, Activity.RESULT_CANCELED,
                             null, "finish-heavy", true);
                 }
             }
@@ -4939,7 +4939,7 @@
             final long origId = Binder.clearCallingIdentity();
             ActivityRecord r = ActivityRecord.isInStackLocked(token);
             if (r != null) {
-                r.task.stack.finishSubActivityLocked(r, resultWho, requestCode);
+                r.getStack().finishSubActivityLocked(r, resultWho, requestCode);
             }
             Binder.restoreCallingIdentity(origId);
         }
@@ -4963,7 +4963,7 @@
                     mStackSupervisor.showLockTaskToast();
                     return false;
                 }
-                return task.stack.finishActivityAffinityLocked(r);
+                return task.getStack().finishActivityAffinityLocked(r);
             } finally {
                 Binder.restoreCallingIdentity(origId);
             }
@@ -4994,7 +4994,7 @@
                 if (r == null) {
                     return false;
                 }
-                return r.task.stack.safelyDestroyActivityLocked(r, "app-req");
+                return r.getStack().safelyDestroyActivityLocked(r, "app-req");
             } finally {
                 Binder.restoreCallingIdentity(origId);
             }
@@ -6930,9 +6930,9 @@
         final long origId = Binder.clearCallingIdentity();
 
         synchronized (this) {
-            ActivityRecord r = ActivityRecord.isInStackLocked(token);
+            final ActivityRecord r = ActivityRecord.isInStackLocked(token);
             if (r != null) {
-                r.task.stack.activityStoppedLocked(r, icicle, persistentState, description);
+                r.getStack().activityStoppedLocked(r, icicle, persistentState, description);
             }
         }
 
@@ -9076,7 +9076,7 @@
         rti.origActivity = tr.origActivity;
         rti.realActivity = tr.realActivity;
         rti.description = tr.lastDescription;
-        rti.stackId = tr.stack != null ? tr.stack.mStackId : -1;
+        rti.stackId = tr.getStackId();
         rti.userId = tr.userId;
         rti.taskDescription = new ActivityManager.TaskDescription(tr.lastTaskDescription);
         rti.firstActiveTime = tr.firstActiveTime;
@@ -9205,15 +9205,15 @@
                             continue;
                         }
                     }
+                    final ActivityStack stack = tr.getStack();
                     if ((flags & ActivityManager.RECENT_IGNORE_HOME_STACK_TASKS) != 0) {
-                        if (tr.stack != null && tr.stack.isHomeStack()) {
+                        if (stack != null && stack.isHomeStack()) {
                             if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
                                     "Skipping, home stack task: " + tr);
                             continue;
                         }
                     }
                     if ((flags & ActivityManager.RECENT_INGORE_DOCKED_STACK_TOP_TASK) != 0) {
-                        final ActivityStack stack = tr.stack;
                         if (stack != null && stack.isDockedStack() && stack.topTask() == tr) {
                             if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
                                     "Skipping, top task in docked stack: " + tr);
@@ -9221,7 +9221,7 @@
                         }
                     }
                     if ((flags & ActivityManager.RECENT_INGORE_PINNED_STACK_TASKS) != 0) {
-                        if (tr.stack != null && tr.stack.isPinnedStack()) {
+                        if (stack != null && stack.isPinnedStack()) {
                             if (DEBUG_RECENTS) Slog.d(TAG_RECENTS,
                                     "Skipping, pinned stack task: " + tr);
                             continue;
@@ -9328,7 +9328,7 @@
                 // Use the full screen as the context for the task thumbnail
                 final Point displaySize = new Point();
                 final TaskThumbnailInfo thumbnailInfo = new TaskThumbnailInfo();
-                r.task.stack.getDisplaySize(displaySize);
+                r.getStack().getDisplaySize(displaySize);
                 thumbnailInfo.taskWidth = displaySize.x;
                 thumbnailInfo.taskHeight = displaySize.y;
                 thumbnailInfo.screenOrientation = mGlobalConfiguration.orientation;
@@ -9352,7 +9352,7 @@
 
                 task.inRecents = true;
                 mRecentTasks.add(task);
-                r.task.stack.addTask(task, false, "addAppTask");
+                r.getStack().addTask(task, false, "addAppTask");
 
                 task.setLastThumbnailLocked(thumbnail);
                 task.freeLastThumbnail();
@@ -9418,7 +9418,7 @@
                 // - a non-null bounds on a non-freeform (fullscreen OR docked) task moves
                 //   that task to freeform
                 // - otherwise the task is not moved
-                int stackId = task.stack.mStackId;
+                int stackId = task.getStackId();
                 if (!StackId.isTaskResizeAllowed(stackId)) {
                     throw new IllegalArgumentException("resizeTask not allowed on task=" + task);
                 }
@@ -9428,7 +9428,7 @@
                     stackId = FREEFORM_WORKSPACE_STACK_ID;
                 }
                 boolean preserveWindow = (resizeMode & RESIZE_MODE_PRESERVE_WINDOW) != 0;
-                if (stackId != task.stack.mStackId) {
+                if (stackId != task.getStackId()) {
                     mStackSupervisor.moveTaskToStackUncheckedLocked(
                             task, stackId, ON_TOP, !FORCE_FOCUS, "resizeTask");
                     preserveWindow = false;
@@ -9455,7 +9455,7 @@
                     Slog.w(TAG, "getTaskBounds: taskId=" + taskId + " not found");
                     return rect;
                 }
-                if (task.stack != null) {
+                if (task.getStack() != null) {
                     // Return the bounds from window manager since it will be adjusted for various
                     // things like the presense of a docked stack for tasks that aren't resizeable.
                     mWindowManager.getTaskBounds(task.taskId, rect);
@@ -10113,7 +10113,8 @@
             synchronized (this) {
                 final TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(
                         taskId, !RESTORE_FROM_RECENTS, INVALID_STACK_ID);
-                return tr != null && tr.stack != null && tr.stack.isHomeStack();
+                final ActivityStack stack = tr != null ? tr.getStack() : null;
+                return stack != null && stack.isHomeStack();
             }
         } finally {
             Binder.restoreCallingIdentity(ident);
@@ -12460,7 +12461,7 @@
                 }
                 final boolean translucentChanged = r.changeWindowTranslucency(true);
                 if (translucentChanged) {
-                    r.task.stack.releaseBackgroundResources(r);
+                    r.getStack().releaseBackgroundResources(r);
                     mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
                 }
                 mWindowManager.setAppFullscreen(token, true);
@@ -12487,7 +12488,7 @@
                 }
                 final boolean translucentChanged = r.changeWindowTranslucency(false);
                 if (translucentChanged) {
-                    r.task.stack.convertActivityToTranslucent(r);
+                    r.getStack().convertActivityToTranslucent(r);
                 }
                 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
                 mWindowManager.setAppFullscreen(token, false);
@@ -19161,7 +19162,7 @@
         synchronized (this) {
             ActivityRecord srec = ActivityRecord.forTokenLocked(token);
             if (srec != null) {
-                return srec.task.stack.shouldUpRecreateTaskLocked(srec, destAffinity);
+                return srec.getStack().shouldUpRecreateTaskLocked(srec, destAffinity);
             }
         }
         return false;
@@ -19173,7 +19174,7 @@
         synchronized (this) {
             final ActivityRecord r = ActivityRecord.forTokenLocked(token);
             if (r != null) {
-                return r.task.stack.navigateUpToLocked(r, destIntent, resultCode, resultData);
+                return r.getStack().navigateUpToLocked(r, destIntent, resultCode, resultData);
             }
             return false;
         }
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index e52671f..40d6d14 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -464,7 +464,7 @@
     }
 
     void scheduleMultiWindowModeChanged() {
-        if (task == null || task.stack == null || app == null || app.thread == null) {
+        if (task == null || task.getStack() == null || app == null || app.thread == null) {
             return;
         }
         try {
@@ -476,20 +476,19 @@
     }
 
     void schedulePictureInPictureModeChanged() {
-        if (task == null || task.stack == null || app == null || app.thread == null) {
+        if (task == null || task.getStack() == null || app == null || app.thread == null) {
             return;
         }
         try {
             app.thread.schedulePictureInPictureModeChanged(
-                    appToken, task.stack.mStackId == PINNED_STACK_ID);
+                    appToken, task.getStackId() == PINNED_STACK_ID);
         } catch (Exception e) {
             // If process died, no one cares.
         }
     }
 
     boolean isFreeform() {
-        return task != null && task.stack != null
-                && task.stack.mStackId == FREEFORM_WORKSPACE_STACK_ID;
+        return task != null && task.getStackId() == FREEFORM_WORKSPACE_STACK_ID;
     }
 
     static class Token extends IApplicationToken.Stub {
@@ -566,7 +565,7 @@
                 return null;
             }
             ActivityRecord r = token.weakActivity.get();
-            if (r == null || r.task == null || r.task.stack == null) {
+            if (r == null || r.getStack() == null) {
                 return null;
             }
             return r;
@@ -777,8 +776,9 @@
     }
 
     void setTask(TaskRecord newTask, TaskRecord taskToAffiliateWith) {
-        if (task != null && task.removeActivity(this) && task != newTask && task.stack != null) {
-            task.stack.removeTask(task, "setTask");
+        if (task != null && task.removeActivity(this) && task != newTask
+                && task.getStack() != null) {
+            task.getStack().removeTask(task, "setTask");
         }
         task = newTask;
         setTaskToAffiliateWith(taskToAffiliateWith);
@@ -792,6 +792,13 @@
         }
     }
 
+    /**
+     * @return Stack value from current task, null if there is no task.
+     */
+    ActivityStack getStack() {
+        return task != null ? task.getStack() : null;
+    }
+
     boolean changeWindowTranslucency(boolean toOpaque) {
         if (fullscreen == toOpaque) {
             return false;
@@ -825,7 +832,8 @@
     }
 
     boolean isInStackLocked() {
-        return task != null && task.stack != null && task.stack.isInStackLocked(this) != null;
+        final ActivityStack stack = getStack();
+        return stack != null && stack.isInStackLocked(this) != null;
     }
 
     boolean isHomeActivity() {
@@ -848,7 +856,7 @@
     }
 
     boolean isFocusable() {
-        return StackId.canReceiveKeys(task.stack.mStackId) || isAlwaysFocusable();
+        return StackId.canReceiveKeys(task.getStackId()) || isAlwaysFocusable();
     }
 
     boolean isResizeable() {
@@ -883,8 +891,8 @@
 
     void makeFinishingLocked() {
         if (!finishing) {
-            if (task != null && task.stack != null
-                    && this == task.stack.getVisibleBehindActivity()) {
+            final ActivityStack stack = getStack();
+            if (stack != null && this == stack.getVisibleBehindActivity()) {
                 // A finishing activity should not remain as visible in the background
                 mStackSupervisor.requestVisibleBehindLocked(this, false);
             }
@@ -948,7 +956,7 @@
                 intent, getUriPermissionsLocked(), userId);
         final ReferrerIntent rintent = new ReferrerIntent(intent, referrer);
         boolean unsent = true;
-        final ActivityStack stack = task.stack;
+        final ActivityStack stack = getStack();
         final boolean isTopActivityInStack =
                 stack != null && stack.topRunningActivityLocked() == this;
         final boolean isTopActivityWhileSleeping =
@@ -1133,7 +1141,7 @@
             return false;
         }
 
-        final ActivityStack stack = task.stack;
+        final ActivityStack stack = getStack();
         if (stack == null) {
             return false;
         }
@@ -1146,7 +1154,7 @@
 
     void finishLaunchTickingLocked() {
         launchTickTime = 0;
-        final ActivityStack stack = task.stack;
+        final ActivityStack stack = getStack();
         if (stack != null) {
             stack.mHandler.removeMessages(ActivityStack.LAUNCH_TICK_MSG);
         }
@@ -1180,7 +1188,7 @@
         if (displayStartTime != 0) {
             reportLaunchTimeLocked(curTime);
         }
-        final ActivityStack stack = task.stack;
+        final ActivityStack stack = getStack();
         if (fullyDrawnStartTime != 0 && stack != null) {
             final long thisTime = curTime - fullyDrawnStartTime;
             final long totalTime = stack.mFullyDrawnStartTime != 0
@@ -1212,7 +1220,7 @@
     }
 
     private void reportLaunchTimeLocked(final long curTime) {
-        final ActivityStack stack = task.stack;
+        final ActivityStack stack = getStack();
         if (stack == null) {
             return;
         }
@@ -1356,13 +1364,13 @@
 
     static ActivityRecord isInStackLocked(IBinder token) {
         final ActivityRecord r = ActivityRecord.forTokenLocked(token);
-        return (r != null) ? r.task.stack.isInStackLocked(r) : null;
+        return (r != null) ? r.getStack().isInStackLocked(r) : null;
     }
 
     static ActivityStack getStackLocked(IBinder token) {
         final ActivityRecord r = ActivityRecord.isInStackLocked(token);
         if (r != null) {
-            return r.task.stack;
+            return r.getStack();
         }
         return null;
     }
@@ -1373,8 +1381,9 @@
             // This would be redundant.
             return false;
         }
-        if (task == null || task.stack == null || this == task.stack.mResumedActivity
-                || this == task.stack.mPausingActivity || !haveState || !stopped) {
+        final ActivityStack stack = getStack();
+        if (stack == null || this == stack.mResumedActivity || this == stack.mPausingActivity
+                || !haveState || !stopped) {
             // We're not ready for this kind of thing.
             return false;
         }
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index d820627..5dda02d 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -644,9 +644,9 @@
             return null;
         }
         final TaskRecord task = r.task;
-        if (task != null && task.stack != null
-                && task.mActivities.contains(r) && mTaskHistory.contains(task)) {
-            if (task.stack != this) Slog.w(TAG,
+        final ActivityStack stack = r.getStack();
+        if (stack != null && task.mActivities.contains(r) && mTaskHistory.contains(task)) {
+            if (stack != this) Slog.w(TAG,
                     "Illegal state! task does not point to stack it is in.");
             return r;
         }
@@ -1467,7 +1467,7 @@
     private void setVisible(ActivityRecord r, boolean visible) {
         r.visible = visible;
         if (!visible && r.mUpdateTaskThumbnailWhenHidden) {
-            r.updateThumbnailLocked(r.task.stack.screenshotActivitiesLocked(r), null);
+            r.updateThumbnailLocked(r.task.getStack().screenshotActivitiesLocked(r), null);
             r.mUpdateTaskThumbnailWhenHidden = false;
         }
         mWindowManager.setAppVisibility(r.appToken, visible);
@@ -1487,7 +1487,7 @@
             return null;
         }
 
-        ActivityStack stack = task.stack;
+        final ActivityStack stack = task.getStack();
         if (stack == null) {
             return null;
         }
@@ -1531,7 +1531,7 @@
         ArrayList<ActivityStack> stacks = mStacks;
         final ActivityRecord parent = mActivityContainer.mParentActivity;
         if (parent != null) {
-            stacks = parent.task.stack.mStacks;
+            stacks = parent.getStack().mStacks;
         }
         if (stacks != null) {
             for (int i = stacks.size() - 1; i >= 0; --i) {
@@ -2276,7 +2276,7 @@
         }
 
         final TaskRecord nextTask = next.task;
-        if (prevTask != null && prevTask.stack == this &&
+        if (prevTask != null && prevTask.getStack() == this &&
                 prevTask.isOverHomeStack() && prev.finishing && prev.frontOfTask) {
             if (DEBUG_STACK)  mStackSupervisor.validateTopActivitiesLocked();
             if (prevTask == nextTask) {
@@ -3630,7 +3630,7 @@
         if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to FINISHING: " + r);
         r.state = ActivityState.FINISHING;
         final boolean finishingActivityInNonFocusedStack
-                = r.task.stack != mStackSupervisor.getFocusedStack()
+                = r.getStack() != mStackSupervisor.getFocusedStack()
                 && prevState == ActivityState.PAUSED && mode == FINISH_AFTER_VISIBLE;
 
         if (mode == FINISH_IMMEDIATELY
@@ -5228,7 +5228,7 @@
             }
         }
 
-        task.stack = null;
+        task.setStack(null);
     }
 
     TaskRecord createTaskRecord(int taskId, ActivityInfo info, Intent intent,
@@ -5261,7 +5261,7 @@
     void addTask(final TaskRecord task, final boolean toTop, String reason) {
         final ActivityStack prevStack = preAddTask(task, reason, toTop);
 
-        task.stack = this;
+        task.setStack(this);
         if (toTop) {
             insertTaskAtTop(task, null);
         } else {
@@ -5273,9 +5273,9 @@
 
     void positionTask(final TaskRecord task, int position) {
         final ActivityRecord topRunningActivity = task.topRunningActivityLocked();
-        final boolean wasResumed = topRunningActivity == task.stack.mResumedActivity;
+        final boolean wasResumed = topRunningActivity == task.getStack().mResumedActivity;
         final ActivityStack prevStack = preAddTask(task, "positionTask", !ON_TOP);
-        task.stack = this;
+        task.setStack(this);
         insertTaskAtPosition(task, position);
         postAddTask(task, prevStack);
         if (wasResumed) {
@@ -5289,7 +5289,7 @@
     }
 
     private ActivityStack preAddTask(TaskRecord task, String reason, boolean toTop) {
-        final ActivityStack prevStack = task.stack;
+        final ActivityStack prevStack = task.getStack();
         if (prevStack != null && prevStack != this) {
             prevStack.removeTask(task, reason,
                     toTop ? REMOVE_TASK_MODE_MOVING_TO_TOP : REMOVE_TASK_MODE_MOVING);
@@ -5343,7 +5343,7 @@
      * created on this stack which the activity is added to.
      * */
     void moveActivityToStack(ActivityRecord r) {
-        final ActivityStack prevStack = r.task.stack;
+        final ActivityStack prevStack = r.getStack();
         if (prevStack.mStackId == mStackId) {
             // You are already in the right stack silly...
             return;
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 67604d3..e1fe0d2 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -571,7 +571,7 @@
 
         final ActivityRecord parent = stack.mActivityContainer.mParentActivity;
         if (parent != null) {
-            stack = parent.task.stack;
+            stack = parent.getStack();
         }
         return stack == mFocusedStack;
     }
@@ -584,7 +584,7 @@
 
         final ActivityRecord parent = stack.mActivityContainer.mParentActivity;
         if (parent != null) {
-            stack = parent.task.stack;
+            stack = parent.getStack();
         }
         return stack == mHomeStack.mStacks.get((mHomeStack.mStacks.size() - 1));
     }
@@ -1210,7 +1210,7 @@
             setLockTaskModeLocked(task, LOCK_TASK_MODE_LOCKED, "mLockTaskAuth==LAUNCHABLE", false);
         }
 
-        final ActivityStack stack = task.stack;
+        final ActivityStack stack = task.getStack();
         try {
             if (app.thread == null) {
                 throw new RemoteException();
@@ -1359,7 +1359,7 @@
         ProcessRecord app = mService.getProcessRecordLocked(r.processName,
                 r.info.applicationInfo.uid, true);
 
-        r.task.stack.setLaunchTime(r);
+        r.getStack().setLaunchTime(r);
 
         if (app != null && app.thread != null) {
             try {
@@ -1607,7 +1607,7 @@
             r.idle = true;
 
             //Slog.i(TAG, "IDLE: mBooted=" + mBooted + ", fromTimeout=" + fromTimeout);
-            if (isFocusedStack(r.task.stack) || fromTimeout) {
+            if (isFocusedStack(r.getStack()) || fromTimeout) {
                 booting = checkFinishBootingLocked();
             }
         }
@@ -1645,7 +1645,7 @@
         // waiting for the next one to start.
         for (int i = 0; i < NS; i++) {
             r = stops.get(i);
-            final ActivityStack stack = r.task.stack;
+            final ActivityStack stack = r.getStack();
             if (stack != null) {
                 if (r.finishing) {
                     stack.finishCurrentActivityLocked(r, ActivityStack.FINISH_IMMEDIATELY, false);
@@ -1659,7 +1659,7 @@
         // waiting for the next one to start.
         for (int i = 0; i < NF; i++) {
             r = finishes.get(i);
-            final ActivityStack stack = r.task.stack;
+            final ActivityStack stack = r.getStack();
             if (stack != null) {
                 activityRemoved |= stack.destroyActivityLocked(r, true, "finish-idle");
             }
@@ -1835,7 +1835,8 @@
             // we'll just indicate that this task returns to the home task.
             task.setTaskToReturnTo(HOME_ACTIVITY_TYPE);
         }
-        if (task.stack == null) {
+        ActivityStack currentStack = task.getStack();
+        if (currentStack == null) {
             Slog.e(TAG, "findTaskToMoveToFrontLocked: can't move task="
                     + task + " to front. Stack is null");
             return;
@@ -1849,10 +1850,10 @@
                 if (stackId == INVALID_STACK_ID) {
                     stackId = task.getLaunchStackId();
                 }
-                if (stackId != task.stack.mStackId) {
-                    final ActivityStack stack = moveTaskToStackUncheckedLocked(
-                            task, stackId, ON_TOP, !FORCE_FOCUS, reason);
-                    stackId = stack.mStackId;
+                if (stackId != currentStack.mStackId) {
+                    currentStack = moveTaskToStackUncheckedLocked(task, stackId, ON_TOP,
+                            !FORCE_FOCUS, reason);
+                    stackId = currentStack.mStackId;
                     // moveTaskToStackUncheckedLocked() should already placed the task on top,
                     // still need moveTaskToFrontLocked() below for any transition settings.
                 }
@@ -1871,13 +1872,13 @@
         }
 
         final ActivityRecord r = task.getTopActivity();
-        task.stack.moveTaskToFrontLocked(task, false /* noAnimation */, options,
+        currentStack.moveTaskToFrontLocked(task, false /* noAnimation */, options,
                 r == null ? null : r.appTimeTracker, reason);
 
         if (DEBUG_STACK) Slog.d(TAG_STACK,
-                "findTaskToMoveToFront: moved to front of stack=" + task.stack);
+                "findTaskToMoveToFront: moved to front of stack=" + currentStack);
 
-        handleNonResizableTaskIfNeeded(task, INVALID_STACK_ID, task.stack.mStackId,
+        handleNonResizableTaskIfNeeded(task, INVALID_STACK_ID, currentStack.mStackId,
                 forceNonResizeable);
     }
 
@@ -2212,7 +2213,7 @@
             // All we can do for now is update the bounds so it can be used when the task is
             // added to window manager.
             task.updateOverrideConfiguration(bounds);
-            if (task.stack != null && task.stack.mStackId != FREEFORM_WORKSPACE_STACK_ID) {
+            if (task.getStackId() != FREEFORM_WORKSPACE_STACK_ID) {
                 // re-restore the task so it can have the proper stack association.
                 restoreRecentTaskLocked(task, FREEFORM_WORKSPACE_STACK_ID);
             }
@@ -2233,7 +2234,7 @@
         if (updatedConfig) {
             final ActivityRecord r = task.topRunningActivityLocked();
             if (r != null) {
-                final ActivityStack stack = task.stack;
+                final ActivityStack stack = r.getStack();
                 kept = stack.ensureActivityConfigurationLocked(r, 0, preserveWindow);
 
                 if (!deferResume) {
@@ -2291,15 +2292,16 @@
             stackId = FULLSCREEN_WORKSPACE_STACK_ID;
         }
 
-        if (task.stack != null) {
+        final ActivityStack currentStack = task.getStack();
+        if (currentStack != null) {
             // Task has already been restored once. See if we need to do anything more
-            if (task.stack.mStackId == stackId) {
+            if (currentStack.mStackId == stackId) {
                 // Nothing else to do since it is already restored in the right stack.
                 return true;
             }
             // Remove current stack association, so we can re-associate the task with the
             // right stack below.
-            task.stack.removeTask(task, "restoreRecentTaskLocked", REMOVE_TASK_MODE_MOVING);
+            currentStack.removeTask(task, "restoreRecentTaskLocked", REMOVE_TASK_MODE_MOVING);
         }
 
         final ActivityStack stack =
@@ -2343,7 +2345,7 @@
         }
 
         final ActivityRecord r = task.topRunningActivityLocked();
-        final ActivityStack prevStack = task.stack;
+        final ActivityStack prevStack = task.getStack();
         final boolean wasFocused = isFocusedStack(prevStack) && (topRunningActivityLocked() == r);
         final boolean wasResumed = prevStack.mResumedActivity == r;
         // In some cases the focused stack isn't the front stack. E.g. pinned stack.
@@ -2393,7 +2395,8 @@
             return false;
         }
 
-        if (task.stack != null && task.stack.mStackId == stackId) {
+        final ActivityStack currentStack = task.getStack();
+        if (currentStack != null && currentStack.mStackId == stackId) {
             // You are already in the right stack silly...
             Slog.i(TAG, "moveTaskToStack: taskId=" + taskId + " already in stackId=" + stackId);
             return true;
@@ -2405,7 +2408,7 @@
         }
 
         final ActivityRecord topActivity = task.getTopActivity();
-        final int sourceStackId = task.stack != null ? task.stack.mStackId : INVALID_STACK_ID;
+        final int sourceStackId = task.getStackId();
         final boolean mightReplaceWindow =
                 StackId.replaceWindowsOnTaskMove(sourceStackId, stackId) && topActivity != null;
         if (mightReplaceWindow) {
@@ -2505,7 +2508,7 @@
         try {
             final TaskRecord task = r.task;
 
-            if (r == task.stack.getVisibleBehindActivity()) {
+            if (r == task.getStack().getVisibleBehindActivity()) {
                 // An activity can't be pinned and visible behind at the same time. Go ahead and
                 // release it from been visible behind before pinning.
                 requestVisibleBehindLocked(r, false);
@@ -2555,13 +2558,13 @@
         }
 
         final TaskRecord task = r.task;
-        if (task == null || task.stack == null) {
+        final ActivityStack stack = r.getStack();
+        if (stack == null) {
             Slog.w(TAG, "moveActivityStackToFront: invalid task or stack: r="
                     + r + " task=" + task);
             return false;
         }
 
-        final ActivityStack stack = task.stack;
         if (stack == mFocusedStack && stack.topRunningActivityLocked() == r) {
             if (DEBUG_FOCUS) Slog.d(TAG_FOCUS,
                     "moveActivityStackToFront: already on top, r=" + r);
@@ -2771,7 +2774,7 @@
     }
 
     boolean reportResumedActivityLocked(ActivityRecord r) {
-        final ActivityStack stack = r.task.stack;
+        final ActivityStack stack = r.getStack();
         if (isFocusedStack(stack)) {
             mService.updateUsageStats(r, true);
         }
@@ -2795,7 +2798,7 @@
     }
 
     boolean requestVisibleBehindLocked(ActivityRecord r, boolean visible) {
-        final ActivityStack stack = r.task.stack;
+        final ActivityStack stack = r.getStack();
         if (stack == null) {
             if (DEBUG_VISIBLE_BEHIND) Slog.d(TAG_VISIBLE_BEHIND,
                     "requestVisibleBehind: r=" + r + " visible=" + visible + " stack is null");
@@ -2861,7 +2864,7 @@
     // Called when WindowManager has finished animating the launchingBehind activity to the back.
     void handleLaunchTaskBehindCompleteLocked(ActivityRecord r) {
         final TaskRecord task = r.task;
-        final ActivityStack stack = task.stack;
+        final ActivityStack stack = task.getStack();
 
         r.mLaunchTaskBehind = false;
         task.setLastThumbnailLocked(stack.screenshotActivitiesLocked(r));
@@ -3606,7 +3609,7 @@
                     lockTaskModeState != LOCK_TASK_MODE_NONE);
             resumeFocusedStackTopActivityLocked();
         } else if (lockTaskModeState != LOCK_TASK_MODE_NONE) {
-            handleNonResizableTaskIfNeeded(task, INVALID_STACK_ID, task.stack.mStackId,
+            handleNonResizableTaskIfNeeded(task, INVALID_STACK_ID, task.getStackId(),
                     true /* forceNonResizable */);
         }
     }
@@ -3715,7 +3718,7 @@
     }
 
     void scheduleReportPictureInPictureModeChangedIfNeeded(TaskRecord task, ActivityStack prevStack) {
-        final ActivityStack stack = task.stack;
+        final ActivityStack stack = task.getStack();
         if (prevStack == null || prevStack == stack
                 || (prevStack.mStackId != PINNED_STACK_ID && stack.mStackId != PINNED_STACK_ID)) {
             return;
@@ -4392,7 +4395,7 @@
                 focusedStack != null ? focusedStack.topActivity() : null;
 
         if (launchStackId != INVALID_STACK_ID) {
-            if (task.stack.mStackId != launchStackId) {
+            if (task.getStackId() != launchStackId) {
                 moveTaskToStackLocked(
                         taskId, launchStackId, ON_TOP, FORCE_FOCUS, "startActivityFromRecents",
                         ANIMATE);
@@ -4418,8 +4421,8 @@
 
             mService.mActivityStarter.postStartActivityUncheckedProcessing(task.getTopActivity(),
                     ActivityManager.START_TASK_TO_FRONT,
-                    sourceRecord != null ? sourceRecord.task.stack.mStackId : INVALID_STACK_ID,
-                    sourceRecord, task.stack);
+                    sourceRecord != null ? sourceRecord.task.getStackId() : INVALID_STACK_ID,
+                    sourceRecord, task.getStack());
             return ActivityManager.START_TASK_TO_FRONT;
         }
         callingUid = task.mCallingUid;
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 028c6ac..8252775 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -360,7 +360,7 @@
             }
         }
 
-        final ActivityStack resultStack = resultRecord == null ? null : resultRecord.task.stack;
+        final ActivityStack resultStack = resultRecord == null ? null : resultRecord.getStack();
 
         if (err != START_SUCCESS) {
             if (resultRecord != null) {
@@ -591,8 +591,9 @@
         }
 
         int startedActivityStackId = INVALID_STACK_ID;
-        if (r.task != null && r.task.stack != null) {
-            startedActivityStackId = r.task.stack.mStackId;
+        final ActivityStack currentStack = r.getStack();
+        if (currentStack != null) {
+            startedActivityStackId = currentStack.mStackId;
         } else if (mTargetStack != null) {
             startedActivityStackId = targetStack.mStackId;
         }
@@ -1099,10 +1100,12 @@
         }
 
         if (mStartActivity.packageName == null) {
-            if (mStartActivity.resultTo != null && mStartActivity.resultTo.task.stack != null) {
-                mStartActivity.resultTo.task.stack.sendActivityResultLocked(
-                        -1, mStartActivity.resultTo, mStartActivity.resultWho,
-                        mStartActivity.requestCode, RESULT_CANCELED, null);
+            final ActivityStack sourceStack = mStartActivity.resultTo != null
+                    ? mStartActivity.resultTo.getStack() : null;
+            if (sourceStack != null) {
+                sourceStack.sendActivityResultLocked(-1 /* callingUid */, mStartActivity.resultTo,
+                        mStartActivity.resultWho, mStartActivity.requestCode, RESULT_CANCELED,
+                        null /* data */);
             }
             ActivityOptions.abort(mOptions);
             return START_CLASS_NOT_FOUND;
@@ -1312,15 +1315,17 @@
     }
 
     private void sendNewTaskResultRequestIfNeeded() {
-        if (mStartActivity.resultTo != null && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0
-                && mStartActivity.resultTo.task.stack != null) {
+        final ActivityStack sourceStack = mStartActivity.resultTo != null
+                ? mStartActivity.resultTo.getStack() : null;
+        if (sourceStack != null && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
             // For whatever reason this activity is being launched into a new task...
             // yet the caller has requested a result back.  Well, that is pretty messed up,
             // so instead immediately send back a cancel and let the new task continue launched
             // as normal without a dependency on its originator.
             Slog.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
-            mStartActivity.resultTo.task.stack.sendActivityResultLocked(-1, mStartActivity.resultTo,
-                    mStartActivity.resultWho, mStartActivity.requestCode, RESULT_CANCELED, null);
+            sourceStack.sendActivityResultLocked(-1 /* callingUid */, mStartActivity.resultTo,
+                    mStartActivity.resultWho, mStartActivity.requestCode, RESULT_CANCELED,
+                    null /* data */);
             mStartActivity.resultTo = null;
         }
     }
@@ -1328,7 +1333,7 @@
     private void computeLaunchingTaskFlags() {
         // If the caller is not coming from another activity, but has given us an explicit task into
         // which they would like us to launch the new activity, then let's see about doing that.
-        if (mSourceRecord == null && mInTask != null && mInTask.stack != null) {
+        if (mSourceRecord == null && mInTask != null && mInTask.getStack() != null) {
             final Intent baseIntent = mInTask.getBaseIntent();
             final ActivityRecord root = mInTask.getRootActivity();
             if (baseIntent == null) {
@@ -1415,7 +1420,7 @@
             return;
         }
         if (!mSourceRecord.finishing) {
-            mSourceStack = mSourceRecord.task.stack;
+            mSourceStack = mSourceRecord.getStack();
             return;
         }
 
@@ -1474,7 +1479,7 @@
     }
 
     private ActivityRecord setTargetStackAndMoveToFrontIfNeeded(ActivityRecord intentActivity) {
-        mTargetStack = intentActivity.task.stack;
+        mTargetStack = intentActivity.getStack();
         mTargetStack.mLastPausedActivity = null;
         // If the target task is not in the front, then we need to bring it to the front...
         // except...  well, with SINGLE_TASK_LAUNCH it's not entirely clear. We'd like to have
@@ -1606,7 +1611,7 @@
                 // is put in the right place.
                 mSourceRecord = intentActivity;
                 final TaskRecord task = mSourceRecord.task;
-                if (task != null && task.stack == null) {
+                if (task != null && task.getStack() == null) {
                     // Target stack got cleared when we all activities were removed above.
                     // Go ahead and reset it.
                     mTargetStack = computeStackFocus(mSourceRecord, false /* newTask */,
@@ -1722,18 +1727,19 @@
         }
 
         final TaskRecord sourceTask = mSourceRecord.task;
+        final ActivityStack sourceStack = mSourceRecord.getStack();
         // We only want to allow changing stack if the target task is not the top one,
         // otherwise we would move the launching task to the other side, rather than show
         // two side by side.
-        final boolean moveStackAllowed = sourceTask.stack.topTask() != sourceTask;
+        final boolean moveStackAllowed = sourceStack.topTask() != sourceTask;
         if (moveStackAllowed) {
             mTargetStack = getLaunchStack(mStartActivity, mLaunchFlags, mStartActivity.task,
                     mOptions);
         }
 
         if (mTargetStack == null) {
-            mTargetStack = sourceTask.stack;
-        } else if (mTargetStack != sourceTask.stack) {
+            mTargetStack = sourceStack;
+        } else if (mTargetStack != sourceStack) {
             mSupervisor.moveTaskToStackLocked(sourceTask.taskId, mTargetStack.mStackId,
                     ON_TOP, FORCE_FOCUS, "launchToSide", !ANIMATE);
         }
@@ -1800,7 +1806,7 @@
         if (mLaunchBounds != null) {
             mInTask.updateOverrideConfiguration(mLaunchBounds);
             int stackId = mInTask.getLaunchStackId();
-            if (stackId != mInTask.stack.mStackId) {
+            if (stackId != mInTask.getStackId()) {
                 final ActivityStack stack = mSupervisor.moveTaskToStackUncheckedLocked(
                         mInTask, stackId, ON_TOP, !FORCE_FOCUS, "inTaskToFront");
                 stackId = stack.mStackId;
@@ -1809,7 +1815,7 @@
                 mService.resizeStack(stackId, mLaunchBounds, true, !PRESERVE_WINDOWS, ANIMATE, -1);
             }
         }
-        mTargetStack = mInTask.stack;
+        mTargetStack = mInTask.getStack();
         mTargetStack.moveTaskToFrontLocked(
                 mInTask, mNoAnimation, mOptions, mStartActivity.appTimeTracker, "inTaskToFront");
 
@@ -1916,10 +1922,10 @@
             return stack;
         }
 
-        if (task != null && task.stack != null) {
-            stack = task.stack;
-            if (stack.isOnHomeDisplay()) {
-                if (mSupervisor.mFocusedStack != stack) {
+        final ActivityStack currentStack = task != null ? task.getStack() : null;
+        if (currentStack != null) {
+            if (currentStack.isOnHomeDisplay()) {
+                if (mSupervisor.mFocusedStack != currentStack) {
                     if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
                             "computeStackFocus: Setting " + "focused stack to r=" + r
                                     + " task=" + task);
@@ -1929,7 +1935,7 @@
                                     + mSupervisor.mFocusedStack);
                 }
             }
-            return stack;
+            return currentStack;
         }
 
         final ActivityStackSupervisor.ActivityContainer container = r.mInitialActivityContainer;
@@ -1980,7 +1986,7 @@
 
         // We are reusing a task, keep the stack!
         if (mReuseTask != null) {
-            return mReuseTask.stack;
+            return mReuseTask.getStack();
         }
 
         final int launchStackId =
@@ -2001,7 +2007,7 @@
 
         // The parent activity doesn't want to launch the activity on top of itself, but
         // instead tries to put it onto other side in side-by-side mode.
-        final ActivityStack parentStack = task != null ? task.stack
+        final ActivityStack parentStack = task != null ? task.getStack()
                 : r.mInitialActivityContainer != null ? r.mInitialActivityContainer.mStack
                 : mSupervisor.mFocusedStack;
 
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index 9c08453..c494171 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -296,9 +296,10 @@
                         }
                         break;
                     case ActivityManager.INTENT_SENDER_ACTIVITY_RESULT:
-                        if (key.activity.task.stack != null) {
-                            key.activity.task.stack.sendActivityResultLocked(-1, key.activity,
-                                    key.who, key.requestCode, code, finalIntent);
+                        final ActivityStack stack = key.activity.getStack();
+                        if (stack != null) {
+                            stack.sendActivityResultLocked(-1, key.activity, key.who,
+                                    key.requestCode, code, finalIntent);
                         }
                         break;
                     case ActivityManager.INTENT_SENDER_BROADCAST:
diff --git a/services/core/java/com/android/server/am/RecentTasks.java b/services/core/java/com/android/server/am/RecentTasks.java
index beb863b..bc9bda2f 100644
--- a/services/core/java/com/android/server/am/RecentTasks.java
+++ b/services/core/java/com/android/server/am/RecentTasks.java
@@ -129,7 +129,8 @@
     }
 
     void notifyTaskPersisterLocked(TaskRecord task, boolean flush) {
-        if (task != null && task.stack != null && task.stack.isHomeStack()) {
+        final ActivityStack stack = task != null ? task.getStack() : null;
+        if (stack != null && stack.isHomeStack()) {
             // Never persist the home stack.
             return;
         }
@@ -147,8 +148,9 @@
             }
         }
         for (int i = size() - 1; i >= 0; i--) {
-            TaskRecord task = get(i);
-            if (task.isPersistable && (task.stack == null || !task.stack.isHomeStack())) {
+            final TaskRecord task = get(i);
+            final ActivityStack stack = task.getStack();
+            if (task.isPersistable && (stack == null || !stack.isHomeStack())) {
                 // Set of persisted taskIds for task.userId should not be null here
                 // TODO Investigate why it can happen. For now initialize with an empty set
                 if (mPersistedTaskIds.get(task.userId) == null) {
@@ -618,10 +620,12 @@
         final Intent intent = task.intent;
         final boolean document = intent != null && intent.isDocument();
         int maxRecents = task.maxRecents - 1;
+        final ActivityStack stack = task.getStack();
         for (int i = 0; i < recentsCount; i++) {
             final TaskRecord tr = get(i);
+            final ActivityStack trStack = tr.getStack();
             if (task != tr) {
-                if (task.stack != null && tr.stack != null && task.stack != tr.stack) {
+                if (stack != null && trStack != null && stack != trStack) {
                     continue;
                 }
                 if (task.userId != tr.userId) {
diff --git a/services/core/java/com/android/server/am/TaskPersister.java b/services/core/java/com/android/server/am/TaskPersister.java
index 43eb251..0817f0d 100644
--- a/services/core/java/com/android/server/am/TaskPersister.java
+++ b/services/core/java/com/android/server/am/TaskPersister.java
@@ -639,8 +639,9 @@
                             final TaskRecord task = mRecentTasks.get(taskNdx);
                             if (DEBUG) Slog.d(TAG, "LazyTaskWriter: task=" + task +
                                     " persistable=" + task.isPersistable);
+                            final ActivityStack stack = task.getStack();
                             if ((task.isPersistable || task.inRecents)
-                                    && (task.stack == null || !task.stack.isHomeStack())) {
+                                    && (stack == null || !stack.isHomeStack())) {
                                 if (DEBUG) Slog.d(TAG, "adding to persistentTaskIds task=" + task);
                                 persistentTaskIds.add(task.taskId);
                             } else {
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 6cc4d73..4d7c4d3 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -202,8 +202,8 @@
     /** List of all activities in the task arranged in history order */
     final ArrayList<ActivityRecord> mActivities;
 
-    /** Current stack */
-    ActivityStack stack;
+    /** Current stack. Setter must always be used to update the value. */
+    private ActivityStack mStack;
 
     /** Takes on same set of values as ActivityRecord.mActivityType */
     int taskType;
@@ -527,6 +527,21 @@
         mNextAffiliateTaskId = nextAffiliate == null ? INVALID_TASK_ID : nextAffiliate.taskId;
     }
 
+    ActivityStack getStack() {
+        return mStack;
+    }
+
+    void setStack(ActivityStack stack) {
+        mStack = stack;
+    }
+
+    /**
+     * @return Id of current stack, {@link INVALID_STACK_ID} if no stack is set.
+     */
+    int getStackId() {
+        return mStack != null ? mStack.mStackId : INVALID_STACK_ID;
+    }
+
     // Close up recents linked list.
     void closeRecentsChain() {
         if (mPrevAffiliate != null) {
@@ -583,10 +598,10 @@
             // Non-fullscreen tasks
             taskWidth = mBounds.width();
             taskHeight = mBounds.height();
-        } else if (stack != null) {
+        } else if (mStack != null) {
             // Fullscreen tasks
             final Point displaySize = new Point();
-            stack.getDisplaySize(displaySize);
+            mStack.getDisplaySize(displaySize);
             taskWidth = displaySize.x;
             taskHeight = displaySize.y;
         } else {
@@ -681,7 +696,7 @@
     }
 
     ActivityRecord topRunningActivityLocked() {
-        if (stack != null) {
+        if (mStack != null) {
             for (int activityNdx = mActivities.size() - 1; activityNdx >= 0; --activityNdx) {
                 ActivityRecord r = mActivities.get(activityNdx);
                 if (!r.finishing && r.okToShowLocked()) {
@@ -693,7 +708,7 @@
     }
 
     ActivityRecord topRunningActivityWithStartingWindowLocked() {
-        if (stack != null) {
+        if (mStack != null) {
             for (int activityNdx = mActivities.size() - 1; activityNdx >= 0; --activityNdx) {
                 ActivityRecord r = mActivities.get(activityNdx);
                 if (r.mStartingWindowState != STARTING_WINDOW_SHOWN
@@ -817,7 +832,7 @@
             mService.notifyTaskPersisterLocked(this, false);
         }
 
-        if (stack != null && stack.mStackId == PINNED_STACK_ID) {
+        if (getStackId() == PINNED_STACK_ID) {
             // We normally notify listeners of task stack changes on pause, however pinned stack
             // activities are normally in the paused state so no notification will be sent there
             // before the activity is removed. We send it here so instead.
@@ -849,13 +864,13 @@
             if (r.finishing) {
                 continue;
             }
-            if (stack == null) {
+            if (mStack == null) {
                 // Task was restored from persistent storage.
                 r.takeFromHistory();
                 mActivities.remove(activityNdx);
                 --activityNdx;
                 --numActivities;
-            } else if (stack.finishActivityLocked(
+            } else if (mStack.finishActivityLocked(
                     r, Activity.RESULT_CANCELED, null, "clear-task-index", false)) {
                 --activityNdx;
                 --numActivities;
@@ -910,7 +925,7 @@
                     if (opts != null) {
                         ret.updateOptionsLocked(opts);
                     }
-                    if (stack != null && stack.finishActivityLocked(
+                    if (mStack != null && mStack.finishActivityLocked(
                             r, Activity.RESULT_CANCELED, null, "clear-task-stack", false)) {
                         --activityNdx;
                         --numActivities;
@@ -924,8 +939,8 @@
                         && (launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) == 0
                         && !ActivityStarter.isDocumentLaunchesIntoExisting(launchFlags)) {
                     if (!ret.finishing) {
-                        if (stack != null) {
-                            stack.finishActivityLocked(
+                        if (mStack != null) {
+                            mStack.finishActivityLocked(
                                     ret, Activity.RESULT_CANCELED, null, "clear-task-top", false);
                         }
                         return null;
@@ -940,10 +955,10 @@
     }
 
     public TaskThumbnail getTaskThumbnailLocked() {
-        if (stack != null) {
-            final ActivityRecord resumedActivity = stack.mResumedActivity;
+        if (mStack != null) {
+            final ActivityRecord resumedActivity = mStack.mResumedActivity;
             if (resumedActivity != null && resumedActivity.task == this) {
-                final Bitmap thumbnail = stack.screenshotActivitiesLocked(resumedActivity);
+                final Bitmap thumbnail = mStack.screenshotActivitiesLocked(resumedActivity);
                 setLastThumbnailLocked(thumbnail);
             }
         }
@@ -1417,7 +1432,7 @@
         // If the task has no requested minimal size, we'd like to enforce a minimal size
         // so that the user can not render the task too small to manipulate. We don't need
         // to do this for the pinned stack as the bounds are controlled by the system.
-        if (stack.mStackId != PINNED_STACK_ID) {
+        if (getStackId() != PINNED_STACK_ID) {
             if (minWidth == INVALID_MIN_SIZE) {
                 minWidth = mService.mStackSupervisor.mDefaultMinSizeOfResizeableTask;
             }
@@ -1477,7 +1492,7 @@
 
         mFullscreen = bounds == null;
         if (mFullscreen) {
-            if (mBounds != null && StackId.persistTaskBounds(stack.mStackId)) {
+            if (mBounds != null && StackId.persistTaskBounds(mStack.mStackId)) {
                 mLastNonFullscreenBounds = mBounds;
             }
             mBounds = null;
@@ -1490,7 +1505,7 @@
             } else {
                 mBounds.set(mTmpRect);
             }
-            if (stack == null || StackId.persistTaskBounds(stack.mStackId)) {
+            if (mStack == null || StackId.persistTaskBounds(mStack.mStackId)) {
                 mLastNonFullscreenBounds = mBounds;
             }
             mOverrideConfig = calculateOverrideConfig(mTmpRect, insetBounds,
@@ -1626,7 +1641,7 @@
     /** Updates the task's bounds and override configuration to match what is expected for the
      * input stack. */
     void updateOverrideConfigurationForStack(ActivityStack inStack) {
-        if (stack != null && stack == inStack) {
+        if (mStack != null && mStack == inStack) {
             return;
         }
 
@@ -1670,17 +1685,17 @@
             return null;
         }
 
-        if (stack == null) {
+        if (mStack == null) {
             return null;
         }
 
-        final int stackId = stack.mStackId;
+        final int stackId = mStack.mStackId;
         if (stackId == HOME_STACK_ID
                 || stackId == FULLSCREEN_WORKSPACE_STACK_ID
                 || (stackId == DOCKED_STACK_ID && !isResizeable())) {
-            return isResizeable() ? stack.mBounds : null;
+            return isResizeable() ? mStack.mBounds : null;
         } else if (!StackId.persistTaskBounds(stackId)) {
-            return stack.mBounds;
+            return mStack.mBounds;
         }
         return mLastNonFullscreenBounds;
     }
@@ -1688,7 +1703,7 @@
     boolean canMatchRootAffinity() {
         // We don't allow root affinity matching on the pinned stack as no other task should
         // be launching in it based on affinity.
-        return rootAffinity != null && (stack == null || stack.mStackId != PINNED_STACK_ID);
+        return rootAffinity != null && getStackId() != PINNED_STACK_ID;
     }
 
     void dump(PrintWriter pw, String prefix) {
@@ -1779,9 +1794,7 @@
         if (lastDescription != null) {
             pw.print(prefix); pw.print("lastDescription="); pw.println(lastDescription);
         }
-        if (stack != null) {
-            pw.print(prefix); pw.print("stackId="); pw.println(stack.mStackId);
-        }
+        pw.print(prefix); pw.print("stackId="); pw.println(getStackId());
         pw.print(prefix + "hasBeenVisible=" + hasBeenVisible);
                 pw.print(" mResizeMode=" + ActivityInfo.resizeModeToString(mResizeMode));
                 pw.print(" isResizeable=" + isResizeable());
@@ -1798,7 +1811,7 @@
             sb.append(" U=");
             sb.append(userId);
             sb.append(" StackId=");
-            sb.append(stack != null ? stack.mStackId : INVALID_STACK_ID);
+            sb.append(getStackId());
             sb.append(" sz=");
             sb.append(mActivities.size());
             sb.append('}');
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 50faf3b..da9c547 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -405,11 +405,13 @@
         // Check carrier config for entitlement checks
         final CarrierConfigManager configManager = (CarrierConfigManager) mContext
              .getSystemService(Context.CARRIER_CONFIG_SERVICE);
-        boolean isEntitlementCheckRequired = configManager.getConfig().getBoolean(
-             CarrierConfigManager.KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL);
-
-        if (!isEntitlementCheckRequired) {
-            return false;
+        if (configManager != null && configManager.getConfig() != null) {
+            // we do have a CarrierConfigManager and it has a config.
+            boolean isEntitlementCheckRequired = configManager.getConfig().getBoolean(
+                    CarrierConfigManager.KEY_REQUIRE_ENTITLEMENT_CHECKS_BOOL);
+            if (!isEntitlementCheckRequired) {
+                return false;
+            }
         }
         return (provisionApp.length == 2);
     }
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index fe3a02d..970da99 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -216,7 +216,7 @@
         private static final int DEFAULT_FG_JOB_COUNT = 4;
         private static final int DEFAULT_BG_NORMAL_JOB_COUNT = 6;
         private static final int DEFAULT_BG_MODERATE_JOB_COUNT = 4;
-        private static final int DEFAULT_BG_LOW_JOB_COUNT = 2;
+        private static final int DEFAULT_BG_LOW_JOB_COUNT = 1;
         private static final int DEFAULT_BG_CRITICAL_JOB_COUNT = 1;
 
         /**
@@ -428,7 +428,18 @@
                                         }
                                         cancelJobsForUid(pkgUid, true);
                                     }
-                                } catch (RemoteException e) { /* cannot happen */ }
+                                } catch (RemoteException|IllegalArgumentException e) {
+                                    /*
+                                     * IllegalArgumentException means that the package doesn't exist.
+                                     * This arises when PACKAGE_CHANGED broadcast delivery has lagged
+                                     * behind outright uninstall, so by the time we try to act it's gone.
+                                     * We don't need to act on this PACKAGE_CHANGED when this happens;
+                                     * we'll get a PACKAGE_REMOVED later and clean up then.
+                                     *
+                                     * RemoteException can't actually happen; the package manager is
+                                     * running in this same process.
+                                     */
+                                }
                                 break;
                             }
                         }
@@ -906,7 +917,11 @@
     private boolean isCurrentlyActiveLocked(JobStatus job) {
         for (int i=0; i<mActiveServices.size(); i++) {
             JobServiceContext serviceContext = mActiveServices.get(i);
-            final JobStatus running = serviceContext.getRunningJob();
+            // The 'unsafe' direct-internal-reference running-job inspector is okay to
+            // use here because we are already holding the necessary lock *and* we
+            // immediately discard the returned object reference, if any; we return
+            // only a boolean state indicator to the caller.
+            final JobStatus running = serviceContext.getRunningJobUnsafeLocked();
             if (running != null && running.matches(job.getUid(), job.getJobId())) {
                 return true;
             }
diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java
index 27f397d..b089ba7 100644
--- a/services/core/java/com/android/server/job/JobServiceContext.java
+++ b/services/core/java/com/android/server/job/JobServiceContext.java
@@ -231,6 +231,15 @@
         return job == null ? null : new JobStatus(job);
     }
 
+    /**
+     * Internal non-cloning inspection of the currently running job, if any.  The lock
+     * must be held when calling this *and* for the entire lifetime of using its returned
+     * JobStatus object!
+     */
+    JobStatus getRunningJobUnsafeLocked() {
+        return mRunningJob;
+    }
+
     /** Called externally when a job that was scheduled for execution should be cancelled. */
     void cancelExecutingJob(int reason) {
         mCallbackHandler.obtainMessage(MSG_CANCEL, reason, 0 /* unused */).sendToTarget();
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index b617bdb..c9ef0d7 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -20679,9 +20679,9 @@
     }
 
     /** Called by UserManagerService */
-    void createNewUser(int userId) {
+    void createNewUser(int userId, String[] disallowedPackages) {
         synchronized (mInstallLock) {
-            mSettings.createNewUserLI(this, mInstaller, userId);
+            mSettings.createNewUserLI(this, mInstaller, userId, disallowedPackages);
         }
         synchronized (mPackages) {
             scheduleWritePackageRestrictionsLocked(userId);
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 0799d23..4ba5d07 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -3949,7 +3949,7 @@
     }
 
     void createNewUserLI(@NonNull PackageManagerService service, @NonNull Installer installer,
-            int userHandle) {
+            int userHandle, String[] disallowedPackages) {
         String[] volumeUuids;
         String[] names;
         int[] appIds;
@@ -3970,8 +3970,10 @@
                 if (ps.pkg == null || ps.pkg.applicationInfo == null) {
                     continue;
                 }
+                final boolean shouldInstall = ps.isSystem() &&
+                        !ArrayUtils.contains(disallowedPackages, ps.name);
                 // Only system apps are initially installed.
-                ps.setInstalled(ps.isSystem(), userHandle);
+                ps.setInstalled(shouldInstall, userHandle);
                 // Need to create a data directory for all apps under this user. Accumulate all
                 // required args and call the installer after mPackages lock has been released
                 volumeUuids[i] = ps.volumeUuid;
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 533d9b5..9146bec2 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -2182,9 +2182,10 @@
     }
 
     @Override
-    public UserInfo createProfileForUser(String name, int flags, int userId) {
+    public UserInfo createProfileForUser(String name, int flags, int userId,
+            String[] disallowedPackages) {
         checkManageOrCreateUsersPermission(flags);
-        return createUserInternal(name, flags, userId);
+        return createUserInternal(name, flags, userId, disallowedPackages);
     }
 
     @Override
@@ -2194,6 +2195,11 @@
     }
 
     private UserInfo createUserInternal(String name, int flags, int parentId) {
+        return createUserInternal(name, flags, parentId, null);
+    }
+
+    private UserInfo createUserInternal(String name, int flags, int parentId,
+            String[] disallowedPackages) {
         if (hasUserRestriction(UserManager.DISALLOW_ADD_USER, UserHandle.getCallingUserId())) {
             Log.w(LOG_TAG, "Cannot add user. DISALLOW_ADD_USER is enabled.");
             return null;
@@ -2204,10 +2210,11 @@
             Log.w(LOG_TAG, "Cannot add user. Not enough space on disk.");
             return null;
         }
-        return createUserInternalUnchecked(name, flags, parentId);
+        return createUserInternalUnchecked(name, flags, parentId, disallowedPackages);
     }
 
-    private UserInfo createUserInternalUnchecked(String name, int flags, int parentId) {
+    private UserInfo createUserInternalUnchecked(String name, int flags, int parentId,
+            String[] disallowedPackages) {
         if (ActivityManager.isLowRamDeviceStatic()) {
             return null;
         }
@@ -2321,7 +2328,7 @@
             storage.createUserKey(userId, userInfo.serialNumber, userInfo.isEphemeral());
             mPm.prepareUserData(userId, userInfo.serialNumber,
                     StorageManager.FLAG_STORAGE_DE | StorageManager.FLAG_STORAGE_CE);
-            mPm.createNewUser(userId);
+            mPm.createNewUser(userId, disallowedPackages);
             userInfo.partial = false;
             synchronized (mPackagesLock) {
                 writeUserLP(userData);
@@ -2371,7 +2378,8 @@
     @Override
     public UserInfo createRestrictedProfile(String name, int parentUserId) {
         checkManageOrCreateUsersPermission("setupRestrictedProfile");
-        final UserInfo user = createProfileForUser(name, UserInfo.FLAG_RESTRICTED, parentUserId);
+        final UserInfo user = createProfileForUser(
+                name, UserInfo.FLAG_RESTRICTED, parentUserId, null);
         if (user == null) {
             return null;
         }
@@ -3533,7 +3541,7 @@
 
         @Override
         public UserInfo createUserEvenWhenDisallowed(String name, int flags) {
-            UserInfo user = createUserInternalUnchecked(name, flags, UserHandle.USER_NULL);
+            UserInfo user = createUserInternalUnchecked(name, flags, UserHandle.USER_NULL, null);
             // Keep this in sync with UserManager.createUser
             if (user != null && !user.isAdmin()) {
                 setUserRestriction(UserManager.DISALLOW_SMS, true, user.id);
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 33155ce..9f81105 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -632,6 +632,12 @@
     WindowManagerInternal.OnHardKeyboardStatusChangeListener mHardKeyboardStatusChangeListener;
     SettingsObserver mSettingsObserver;
 
+    // A count of the windows which are 'seamlessly rotated', e.g. a surface
+    // at an old orientation is being transformed. We freeze orientation updates
+    // while any windows are seamlessly rotated, so we need to track when this
+    // hits zero so we can apply deferred orientation updates.
+    int mSeamlessRotationCount = 0;
+
     private final class SettingsObserver extends ContentObserver {
         private final Uri mDisplayInversionEnabledUri =
                 Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED);
@@ -5489,6 +5495,13 @@
             if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Deferring rotation, animation in progress.");
             return false;
         }
+        if (mDisplayFrozen) {
+            // Even if the screen rotation animation has finished (e.g. isAnimating
+            // returns false), there is still some time where we haven't yet unfrozen
+            // the display. We also need to abort rotation here.
+            if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Deferring rotation, still finishing previous rotation");
+            return false;
+        }
 
         if (!mDisplayEnabled) {
             // No point choosing a rotation if the display is not enabled.
@@ -5496,6 +5509,38 @@
             return false;
         }
 
+        final DisplayContent displayContent = getDefaultDisplayContentLocked();
+        final WindowList windows = displayContent.getWindowList();
+
+        final int oldRotation = mRotation;
+        boolean rotateSeamlessly = mPolicy.shouldRotateSeamlessly(oldRotation, mRotation);
+
+        if (rotateSeamlessly) {
+            for (int i = windows.size() - 1; i >= 0; i--) {
+                WindowState w = windows.get(i);
+                // We can't rotate (seamlessly or not) while waiting for the last seamless rotation
+                // to complete (that is, waiting for windows to redraw). It's tempting to check
+                // w.mSeamlessRotationCount but that could be incorrect in the case of window-removal.
+                if (w.mSeamlesslyRotated) {
+                    return false;
+                }
+                // In what can only be called an unfortunate workaround we require
+                // seamlessly rotated child windows to have the TRANSFORM_TO_DISPLAY_INVERSE
+                // flag. Due to limitations in the client API, there is no way for
+                // the client to set this flag in a race free fashion. If we seamlessly rotate
+                // a window which does not have this flag, but then gains it, we will get
+                // an incorrect visual result (rotated viewfinder). This means if we want to
+                // support seamlessly rotating windows which could gain this flag, we can't
+                // rotate windows without it. This limits seamless rotation in N to camera framework
+                // users, windows without children, and native code. This is unfortunate but
+                // having the camera work is our primary goal.
+                if (w.isChildWindow() & w.isVisibleNow() &&
+                        !w.mWinAnimator.mSurfaceController.getTransformToDisplayInverse()) {
+                    rotateSeamlessly = false;
+                }
+            }
+        }
+
         // TODO: Implement forced rotation changes.
         //       Set mAltOrientation to indicate that the application is receiving
         //       an orientation that has different metrics than it expected.
@@ -5514,7 +5559,7 @@
 
         if (mRotation == rotation && mAltOrientation == altOrientation) {
             // No change.
-            return false;
+             return false;
         }
 
         if (DEBUG_ORIENTATION) {
@@ -5524,8 +5569,6 @@
                 + ", lastOrientation=" + mLastOrientation);
         }
 
-        int oldRotation = mRotation;
-
         mRotation = rotation;
         mAltOrientation = altOrientation;
         mPolicy.setRotationLw(mRotation);
@@ -5534,7 +5577,6 @@
         mH.removeMessages(H.WINDOW_FREEZE_TIMEOUT);
         mH.sendEmptyMessageDelayed(H.WINDOW_FREEZE_TIMEOUT, WINDOW_FREEZE_TIMEOUT_DURATION);
         mWaitingForConfig = true;
-        final DisplayContent displayContent = getDefaultDisplayContentLocked();
         displayContent.setLayoutNeeded();
         final int[] anim = new int[2];
         if (displayContent.isDimming()) {
@@ -5542,33 +5584,6 @@
         } else {
             mPolicy.selectRotationAnimationLw(anim);
         }
-        boolean rotateSeamlessly = mPolicy.shouldRotateSeamlessly(oldRotation, mRotation);
-        final WindowList windows = displayContent.getWindowList();
-        // We can't rotate seamlessly while an existing seamless rotation is still
-        // waiting on windows to finish drawing.
-        if (rotateSeamlessly) {
-            for (int i = windows.size() - 1; i >= 0; i--) {
-                WindowState w = windows.get(i);
-                if (w.mSeamlesslyRotated) {
-                    rotateSeamlessly = false;
-                    break;
-                }
-                // In what can only be called an unfortunate workaround we require
-                // seamlessly rotated child windows to have the TRANSFORM_TO_DISPLAY_INVERSE
-                // flag. Due to limitations in the client API, there is no way for
-                // the client to set this flag in a race free fashion. If we seamlessly rotate
-                // a window which does not have this flag, but then gains it, we will get
-                // an incorrect visual result (rotated viewfinder). This means if we want to
-                // support seamlessly rotating windows which could gain this flag, we can't
-                // rotate windows without it. This limits seamless rotation in N to camera framework
-                // users, windows without children, and native code. This is unfortunate but
-                // having the camera work is our primary goal.
-                if (w.isChildWindow() & w.isVisibleNow() &&
-                        !w.mWinAnimator.mSurfaceController.getTransformToDisplayInverse()) {
-                    rotateSeamlessly = false;
-                }
-            }
-        }
 
         if (!rotateSeamlessly) {
             startFreezingDisplayLocked(inTransaction, anim[0], anim[1]);
@@ -5581,6 +5596,10 @@
             // When we are rotating seamlessly, we allow the elements to transition
             // to their rotated state independently and without a freeze required.
             screenRotationAnimation = null;
+
+            // We have to reset this in case a window was removed before it
+            // finished seamless rotation.
+            mSeamlessRotationCount = 0;
         }
 
         // We need to update our screen size information to match the new rotation. If the rotation
@@ -7524,8 +7543,8 @@
                             if (w.mSeamlesslyRotated) {
                                 layoutNeeded = true;
                                 w.setDisplayLayoutNeeded();
+                                markForSeamlessRotation(w, false);
                             }
-                            w.mSeamlesslyRotated = false;
                         }
                         if (layoutNeeded) {
                             mWindowPlacerLocked.performSurfacePlacement();
@@ -9583,6 +9602,26 @@
         mPolicy.registerShortcutKey(shortcutCode, shortcutKeyReceiver);
     }
 
+    void markForSeamlessRotation(WindowState w, boolean seamlesslyRotated) {
+        if (seamlesslyRotated == w.mSeamlesslyRotated) {
+            return;
+        }
+        w.mSeamlesslyRotated = seamlesslyRotated;
+        if (seamlesslyRotated) {
+            mSeamlessRotationCount++;
+        } else {
+            mSeamlessRotationCount--;
+        }
+        if (mSeamlessRotationCount == 0) {
+            if (DEBUG_ORIENTATION) {
+                Slog.i(TAG, "Performing post-rotate rotation after seamless rotation");
+            }
+            if (updateRotationUncheckedLocked(false)) {
+                mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
+            }
+        }
+    }
+
     private final class LocalService extends WindowManagerInternal {
         @Override
         public void requestTraversalFromDisplayManager() {
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index dc83ac0..1fae77d 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -1350,7 +1350,7 @@
         // If we are undergoing seamless rotation, the surface has already
         // been set up to persist at it's old location. We need to freeze
         // updates until a resize occurs.
-        w.mSeamlesslyRotated = w.mSeamlesslyRotated && !mSurfaceResized;
+        mService.markForSeamlessRotation(w, w.mSeamlesslyRotated && !mSurfaceResized);
 
         calculateSurfaceWindowCrop(mTmpClipRect, mTmpFinalClipRect);
 
@@ -1991,7 +1991,7 @@
             cropRect.set(0, 0, w.mRequestedWidth, w.mRequestedWidth + w.mRequestedHeight);
             mSurfaceController.setCropInTransaction(cropRect, false);
         } else {
-            w.mSeamlesslyRotated = true;
+            mService.markForSeamlessRotation(w, true);
             transform.getValues(mService.mTmpFloats);
 
             float DsDx = mService.mTmpFloats[Matrix.MSCALE_X];
diff --git a/services/net/java/android/net/dhcp/DhcpPacket.java b/services/net/java/android/net/dhcp/DhcpPacket.java
index 9aa66fe..ef4bc02 100644
--- a/services/net/java/android/net/dhcp/DhcpPacket.java
+++ b/services/net/java/android/net/dhcp/DhcpPacket.java
@@ -7,6 +7,7 @@
 import android.os.Build;
 import android.os.SystemProperties;
 import android.system.OsConstants;
+import com.android.internal.annotations.VisibleForTesting;
 
 import java.io.UnsupportedEncodingException;
 import java.net.Inet4Address;
@@ -14,9 +15,8 @@
 import java.nio.BufferUnderflowException;
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
-import java.nio.charset.StandardCharsets;
 import java.nio.ShortBuffer;
-
+import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
@@ -725,7 +725,8 @@
      * A subset of the optional parameters are parsed and are stored
      * in object fields.
      */
-    public static DhcpPacket decodeFullPacket(ByteBuffer packet, int pktType) throws ParseException
+    @VisibleForTesting
+    static DhcpPacket decodeFullPacket(ByteBuffer packet, int pktType) throws ParseException
     {
         // bootp parameters
         int transactionId;
@@ -894,8 +895,12 @@
                         + 64    // skip server host name (64 chars)
                         + 128); // skip boot file name (128 chars)
 
-        int dhcpMagicCookie = packet.getInt();
+        // Ensure this is a DHCP packet with a magic cookie, and not BOOTP. http://b/31850211
+        if (packet.remaining() < 4) {
+            throw new ParseException(DhcpErrorEvent.DHCP_NO_COOKIE, "not a DHCP message");
+        }
 
+        int dhcpMagicCookie = packet.getInt();
         if (dhcpMagicCookie != DHCP_MAGIC_COOKIE) {
             throw new ParseException(DhcpErrorEvent.DHCP_BAD_MAGIC_COOKIE,
                     "Bad magic cookie 0x%08x, should be 0x%08x",
@@ -1090,7 +1095,13 @@
     public static DhcpPacket decodeFullPacket(byte[] packet, int length, int pktType)
             throws ParseException {
         ByteBuffer buffer = ByteBuffer.wrap(packet, 0, length).order(ByteOrder.BIG_ENDIAN);
-        return decodeFullPacket(buffer, pktType);
+        try {
+            return decodeFullPacket(buffer, pktType);
+        } catch (ParseException e) {
+            throw e;
+        } catch (Exception e) {
+            throw new ParseException(DhcpErrorEvent.PARSING_ERROR, e.getMessage());
+        }
     }
 
     /**
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 514f095..3548f28 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -44,6 +44,7 @@
     <uses-permission android:name="android.permission.PACKET_KEEPALIVE_OFFLOAD" />
     <uses-permission android:name="android.permission.GET_INTENT_SENDER_INTENT" />
     <uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS" />
+    <uses-permission android:name="android.permission.INSTALL_PACKAGES" />
 
     <application>
         <uses-library android:name="android.test.runner" />
diff --git a/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java b/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java
index f8eaf7d..bc8baa1 100644
--- a/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java
+++ b/services/tests/servicestests/src/android/net/dhcp/DhcpPacketTest.java
@@ -16,24 +16,22 @@
 
 package android.net.dhcp;
 
-import android.net.NetworkUtils;
 import android.net.DhcpResults;
 import android.net.LinkAddress;
+import android.net.NetworkUtils;
+import android.net.metrics.DhcpErrorEvent;
 import android.system.OsConstants;
 import android.test.suitebuilder.annotation.SmallTest;
 import com.android.internal.util.HexDump;
-
 import java.net.Inet4Address;
 import java.nio.ByteBuffer;
 import java.util.ArrayList;
-
-import junit.framework.TestCase;
-import libcore.util.HexEncoding;
 import java.util.Arrays;
+import java.util.Random;
+import junit.framework.TestCase;
 
 import static android.net.dhcp.DhcpPacket.*;
 
-
 public class DhcpPacketTest extends TestCase {
 
     private static Inet4Address SERVER_ADDR = v4Address("192.0.2.1");
@@ -285,7 +283,7 @@
         // TODO: Turn all of these into golden files. This will probably require modifying
         // Android.mk appropriately, making this into an AndroidTestCase, and adding code to read
         // the golden files from the test APK's assets via mContext.getAssets().
-        final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
+        final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
             // IP header.
             "451001480000000080118849c0a89003c0a89ff7" +
             // UDP header.
@@ -304,8 +302,7 @@
             "0000000000000000000000000000000000000000000000000000000000000000" +
             // Options
             "638253633501023604c0a89003330400001c200104fffff0000304c0a89ffe06080808080808080404" +
-            "3a0400000e103b040000189cff00000000000000000000"
-        ).toCharArray(), false));
+            "3a0400000e103b040000189cff00000000000000000000"));
 
         DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
         assertTrue(offerPacket instanceof DhcpOfferPacket);  // Implicitly checks it's non-null.
@@ -316,7 +313,7 @@
 
     @SmallTest
     public void testOffer2() throws Exception {
-        final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
+        final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
             // IP header.
             "450001518d0600004011144dc0a82b01c0a82bf7" +
             // UDP header.
@@ -335,8 +332,7 @@
             "0000000000000000000000000000000000000000000000000000000000000000" +
             // Options
             "638253633501023604c0a82b01330400000e103a04000007083b0400000c4e0104ffffff00" +
-            "1c04c0a82bff0304c0a82b010604c0a82b012b0f414e44524f49445f4d455445524544ff"
-        ).toCharArray(), false));
+            "1c04c0a82bff0304c0a82b010604c0a82b012b0f414e44524f49445f4d455445524544ff"));
 
         assertEquals(337, packet.limit());
         DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
@@ -347,6 +343,185 @@
         assertTrue(dhcpResults.hasMeteredHint());
     }
 
+    @SmallTest
+    public void testBadIpPacket() throws Exception {
+        final byte[] packet = HexDump.hexStringToByteArray(
+            // IP header.
+            "450001518d0600004011144dc0a82b01c0a82bf7");
+
+        try {
+            DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, packet.length, ENCAP_L3);
+        } catch (DhcpPacket.ParseException expected) {
+            assertDhcpErrorCodes(DhcpErrorEvent.L3_TOO_SHORT, expected.errorCode);
+            return;
+        }
+        fail("Dhcp packet parsing should have failed");
+    }
+
+    @SmallTest
+    public void testBadDhcpPacket() throws Exception {
+        final byte[] packet = HexDump.hexStringToByteArray(
+            // IP header.
+            "450001518d0600004011144dc0a82b01c0a82bf7" +
+            // UDP header.
+            "00430044013d9ac7" +
+            // BOOTP header.
+            "02010600dfc23d1f0002000000000000c0a82bf7c0a82b0100000000");
+
+        try {
+            DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, packet.length, ENCAP_L3);
+        } catch (DhcpPacket.ParseException expected) {
+            assertDhcpErrorCodes(DhcpErrorEvent.L3_TOO_SHORT, expected.errorCode);
+            return;
+        }
+        fail("Dhcp packet parsing should have failed");
+    }
+
+    @SmallTest
+    public void testBadTruncatedOffer() throws Exception {
+        final byte[] packet = HexDump.hexStringToByteArray(
+            // IP header.
+            "450001518d0600004011144dc0a82b01c0a82bf7" +
+            // UDP header.
+            "00430044013d9ac7" +
+            // BOOTP header.
+            "02010600dfc23d1f0002000000000000c0a82bf7c0a82b0100000000" +
+            // MAC address.
+            "30766ff2a90c00000000000000000000" +
+            // Server name.
+            "0000000000000000000000000000000000000000000000000000000000000000" +
+            "0000000000000000000000000000000000000000000000000000000000000000" +
+            // File, missing one byte
+            "0000000000000000000000000000000000000000000000000000000000000000" +
+            "0000000000000000000000000000000000000000000000000000000000000000" +
+            "0000000000000000000000000000000000000000000000000000000000000000" +
+            "00000000000000000000000000000000000000000000000000000000000000");
+
+        try {
+            DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, packet.length, ENCAP_L3);
+        } catch (DhcpPacket.ParseException expected) {
+            assertDhcpErrorCodes(DhcpErrorEvent.L3_TOO_SHORT, expected.errorCode);
+            return;
+        }
+        fail("Dhcp packet parsing should have failed");
+    }
+
+    @SmallTest
+    public void testBadOfferWithoutACookie() throws Exception {
+        final byte[] packet = HexDump.hexStringToByteArray(
+            // IP header.
+            "450001518d0600004011144dc0a82b01c0a82bf7" +
+            // UDP header.
+            "00430044013d9ac7" +
+            // BOOTP header.
+            "02010600dfc23d1f0002000000000000c0a82bf7c0a82b0100000000" +
+            // MAC address.
+            "30766ff2a90c00000000000000000000" +
+            // Server name.
+            "0000000000000000000000000000000000000000000000000000000000000000" +
+            "0000000000000000000000000000000000000000000000000000000000000000" +
+            // File.
+            "0000000000000000000000000000000000000000000000000000000000000000" +
+            "0000000000000000000000000000000000000000000000000000000000000000" +
+            "0000000000000000000000000000000000000000000000000000000000000000" +
+            "0000000000000000000000000000000000000000000000000000000000000000"
+            // No options
+            );
+
+        try {
+            DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, packet.length, ENCAP_L3);
+        } catch (DhcpPacket.ParseException expected) {
+            assertDhcpErrorCodes(DhcpErrorEvent.DHCP_NO_COOKIE, expected.errorCode);
+            return;
+        }
+        fail("Dhcp packet parsing should have failed");
+    }
+
+    @SmallTest
+    public void testOfferWithBadCookie() throws Exception {
+        final byte[] packet = HexDump.hexStringToByteArray(
+            // IP header.
+            "450001518d0600004011144dc0a82b01c0a82bf7" +
+            // UDP header.
+            "00430044013d9ac7" +
+            // BOOTP header.
+            "02010600dfc23d1f0002000000000000c0a82bf7c0a82b0100000000" +
+            // MAC address.
+            "30766ff2a90c00000000000000000000" +
+            // Server name.
+            "0000000000000000000000000000000000000000000000000000000000000000" +
+            "0000000000000000000000000000000000000000000000000000000000000000" +
+            // File.
+            "0000000000000000000000000000000000000000000000000000000000000000" +
+            "0000000000000000000000000000000000000000000000000000000000000000" +
+            "0000000000000000000000000000000000000000000000000000000000000000" +
+            "0000000000000000000000000000000000000000000000000000000000000000" +
+            // Bad cookie
+            "DEADBEEF3501023604c0a82b01330400000e103a04000007083b0400000c4e0104ffffff00" +
+            "1c04c0a82bff0304c0a82b010604c0a82b012b0f414e44524f49445f4d455445524544ff");
+
+        try {
+            DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, packet.length, ENCAP_L3);
+        } catch (DhcpPacket.ParseException expected) {
+            assertDhcpErrorCodes(DhcpErrorEvent.DHCP_BAD_MAGIC_COOKIE, expected.errorCode);
+            return;
+        }
+        fail("Dhcp packet parsing should have failed");
+    }
+
+    private void assertDhcpErrorCodes(int expected, int got) {
+        assertEquals(Integer.toHexString(expected), Integer.toHexString(got));
+    }
+
+    public void testTruncatedOfferPackets() throws Exception {
+        final byte[] packet = HexDump.hexStringToByteArray(
+            // IP header.
+            "450001518d0600004011144dc0a82b01c0a82bf7" +
+            // UDP header.
+            "00430044013d9ac7" +
+            // BOOTP header.
+            "02010600dfc23d1f0002000000000000c0a82bf7c0a82b0100000000" +
+            // MAC address.
+            "30766ff2a90c00000000000000000000" +
+            // Server name.
+            "0000000000000000000000000000000000000000000000000000000000000000" +
+            "0000000000000000000000000000000000000000000000000000000000000000" +
+            // File.
+            "0000000000000000000000000000000000000000000000000000000000000000" +
+            "0000000000000000000000000000000000000000000000000000000000000000" +
+            "0000000000000000000000000000000000000000000000000000000000000000" +
+            "0000000000000000000000000000000000000000000000000000000000000000" +
+            // Options
+            "638253633501023604c0a82b01330400000e103a04000007083b0400000c4e0104ffffff00" +
+            "1c04c0a82bff0304c0a82b010604c0a82b012b0f414e44524f49445f4d455445524544ff");
+
+        for (int len = 0; len < packet.length; len++) {
+            try {
+                DhcpPacket.decodeFullPacket(packet, len, ENCAP_L3);
+            } catch (ParseException e) {
+                if (e.errorCode == DhcpErrorEvent.PARSING_ERROR) {
+                    fail(String.format("bad truncated packet of length %d", len));
+                }
+            }
+        }
+    }
+
+    public void testRandomPackets() throws Exception {
+        final int maxRandomPacketSize = 512;
+        final Random r = new Random();
+        for (int i = 0; i < 10000; i++) {
+            byte[] packet = new byte[r.nextInt(maxRandomPacketSize + 1)];
+            r.nextBytes(packet);
+            try {
+                DhcpPacket.decodeFullPacket(packet, packet.length, ENCAP_L3);
+            } catch (ParseException e) {
+                if (e.errorCode == DhcpErrorEvent.PARSING_ERROR) {
+                    fail("bad packet: " + HexDump.toHexString(packet));
+                }
+            }
+        }
+    }
+
     private byte[] mtuBytes(int mtu) {
         // 0x1a02: option 26, length 2. 0xff: no more options.
         if (mtu > Short.MAX_VALUE - Short.MIN_VALUE) {
@@ -354,7 +529,7 @@
                 String.format("Invalid MTU %d, must be 16-bit unsigned", mtu));
         }
         String hexString = String.format("1a02%04xff", mtu);
-        return HexEncoding.decode(hexString.toCharArray(), false);
+        return HexDump.hexStringToByteArray(hexString);
     }
 
     private void checkMtu(ByteBuffer packet, int expectedMtu, byte[] mtuBytes) throws Exception {
@@ -372,7 +547,7 @@
 
     @SmallTest
     public void testMtu() throws Exception {
-        final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
+        final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
             // IP header.
             "451001480000000080118849c0a89003c0a89ff7" +
             // UDP header.
@@ -391,8 +566,7 @@
             "0000000000000000000000000000000000000000000000000000000000000000" +
             // Options
             "638253633501023604c0a89003330400001c200104fffff0000304c0a89ffe06080808080808080404" +
-            "3a0400000e103b040000189cff00000000"
-        ).toCharArray(), false));
+            "3a0400000e103b040000189cff00000000"));
 
         checkMtu(packet, 0, null);
         checkMtu(packet, 0, mtuBytes(1501));
@@ -409,7 +583,7 @@
 
     @SmallTest
     public void testBadHwaddrLength() throws Exception {
-        final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
+        final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
             // IP header.
             "450001518d0600004011144dc0a82b01c0a82bf7" +
             // UDP header.
@@ -428,8 +602,7 @@
             "0000000000000000000000000000000000000000000000000000000000000000" +
             // Options
             "638253633501023604c0a82b01330400000e103a04000007083b0400000c4e0104ffffff00" +
-            "1c04c0a82bff0304c0a82b010604c0a82b012b0f414e44524f49445f4d455445524544ff"
-        ).toCharArray(), false));
+            "1c04c0a82bff0304c0a82b010604c0a82b012b0f414e44524f49445f4d455445524544ff"));
         String expectedClientMac = "30766FF2A90C";
 
         final int hwAddrLenOffset = 20 + 8 + 2;
@@ -486,7 +659,7 @@
         //    store any information in the overloaded fields).
         //
         // For now, we just check that it parses correctly.
-        final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
+        final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
             // Ethernet header.
             "b4cef6000000e80462236e300800" +
             // IP header.
@@ -507,8 +680,7 @@
             "0000000000000000000000000000000000000000000000000000000000000000" +
             // Options
             "638253633501023604010101010104ffff000033040000a8c03401030304ac1101010604ac110101" +
-            "0000000000000000000000000000000000000000000000ff000000"
-        ).toCharArray(), false));
+            "0000000000000000000000000000000000000000000000ff000000"));
 
         DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L2);
         assertTrue(offerPacket instanceof DhcpOfferPacket);
@@ -519,7 +691,7 @@
 
     @SmallTest
     public void testBug2111() throws Exception {
-        final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
+        final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
             // IP header.
             "4500014c00000000ff119beac3eaf3880a3f5d04" +
             // UDP header. TODO: fix invalid checksum (due to MAC address obfuscation).
@@ -538,8 +710,7 @@
             "0000000000000000000000000000000000000000000000000000000000000000" +
             // Options.
             "638253633501023604c00002fe33040000bfc60104fffff00003040a3f50010608c0000201c0000202" +
-            "0f0f646f6d61696e3132332e636f2e756b0000000000ff00000000"
-        ).toCharArray(), false));
+            "0f0f646f6d61696e3132332e636f2e756b0000000000ff00000000"));
 
         DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L3);
         assertTrue(offerPacket instanceof DhcpOfferPacket);
@@ -550,7 +721,7 @@
 
     @SmallTest
     public void testBug2136() throws Exception {
-        final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
+        final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
             // Ethernet header.
             "bcf5ac000000d0c7890000000800" +
             // IP header.
@@ -571,8 +742,7 @@
             "0000000000000000000000000000000000000000000000000000000000000000" +
             // Options.
             "6382536335010236040a20ff80330400001c200104fffff00003040a20900106089458413494584135" +
-            "0f0b6c616e63732e61632e756b000000000000000000ff00000000"
-        ).toCharArray(), false));
+            "0f0b6c616e63732e61632e756b000000000000000000ff00000000"));
 
         DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L2);
         assertTrue(offerPacket instanceof DhcpOfferPacket);
@@ -584,7 +754,7 @@
 
     @SmallTest
     public void testUdpServerAnySourcePort() throws Exception {
-        final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
+        final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
             // Ethernet header.
             "9cd917000000001c2e0000000800" +
             // IP header.
@@ -606,8 +776,7 @@
             "0000000000000000000000000000000000000000000000000000000000000000" +
             // Options.
             "6382536335010236040a0169fc3304000151800104ffff000003040a0fc817060cd1818003d1819403" +
-            "d18180060f0777766d2e6564751c040a0fffffff000000"
-        ).toCharArray(), false));
+            "d18180060f0777766d2e6564751c040a0fffffff000000"));
 
         DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L2);
         assertTrue(offerPacket instanceof DhcpOfferPacket);
@@ -620,7 +789,7 @@
 
     @SmallTest
     public void testUdpInvalidDstPort() throws Exception {
-        final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
+        final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
             // Ethernet header.
             "9cd917000000001c2e0000000800" +
             // IP header.
@@ -642,8 +811,7 @@
             "0000000000000000000000000000000000000000000000000000000000000000" +
             // Options.
             "6382536335010236040a0169fc3304000151800104ffff000003040a0fc817060cd1818003d1819403" +
-            "d18180060f0777766d2e6564751c040a0fffffff000000"
-        ).toCharArray(), false));
+            "d18180060f0777766d2e6564751c040a0fffffff000000"));
 
         try {
             DhcpPacket.decodeFullPacket(packet, ENCAP_L2);
@@ -653,7 +821,7 @@
 
     @SmallTest
     public void testMultipleRouters() throws Exception {
-        final ByteBuffer packet = ByteBuffer.wrap(HexEncoding.decode((
+        final ByteBuffer packet = ByteBuffer.wrap(HexDump.hexStringToByteArray(
             // Ethernet header.
             "fc3d93000000" + "081735000000" + "0800" +
             // IP header.
@@ -674,8 +842,7 @@
             "0000000000000000000000000000000000000000000000000000000000000000" +
             // Options.
             "638253633501023604c0abbd023304000070803a04000038403b04000062700104ffffff00" +
-            "0308c0a8bd01ffffff0006080808080808080404ff000000000000"
-        ).toCharArray(), false));
+            "0308c0a8bd01ffffff0006080808080808080404ff000000000000"));
 
         DhcpPacket offerPacket = DhcpPacket.decodeFullPacket(packet, ENCAP_L2);
         assertTrue(offerPacket instanceof DhcpOfferPacket);
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 6a434ca..0fb2c9f 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
 import android.app.ActivityManager;
 import android.os.Bundle;
@@ -46,16 +47,24 @@
     private static final int REMOVE_TIMEOUT_MILLIS = 60 * 1000; // 60 seconds
     private static final int SWITCH_USER_TIMEOUT_MILLIS = 40 * 1000; // 40 seconds
 
+    // Packages which are used during tests.
+    private static final String[] PACKAGES = new String[] {
+            "com.android.egg",
+            "com.android.retaildemo"
+    };
+
     private final Object mUserRemoveLock = new Object();
     private final Object mUserSwitchLock = new Object();
 
     private UserManager mUserManager = null;
+    private PackageManager mPackageManager;
     private List<Integer> usersToRemove;
 
     @Override
     public void setUp() throws Exception {
         super.setUp();
         mUserManager = UserManager.get(getContext());
+        mPackageManager = getContext().getPackageManager();
 
         IntentFilter filter = new IntentFilter(Intent.ACTION_USER_REMOVED);
         filter.addAction(Intent.ACTION_USER_SWITCHED);
@@ -185,6 +194,49 @@
         assertFalse(mUserManager.isManagedProfile());
     }
 
+    // Verify that disallowed packages are not installed in the managed profile.
+    @MediumTest
+    public void testAddManagedProfile_withDisallowedPackages() throws Exception {
+        final int primaryUserId = mUserManager.getPrimaryUser().id;
+        UserInfo userInfo1 = createProfileForUser("Managed1",
+                UserInfo.FLAG_MANAGED_PROFILE, primaryUserId);
+        // Verify that the packagesToVerify are installed by default.
+        for (String pkg : PACKAGES) {
+            assertTrue("Package should be installed in managed profile: " + pkg,
+                    isPackageInstalledForUser(pkg, userInfo1.id));
+        }
+        removeUser(userInfo1.id);
+
+        UserInfo userInfo2 = createProfileForUser("Managed2",
+                UserInfo.FLAG_MANAGED_PROFILE, primaryUserId, PACKAGES);
+        // Verify that the packagesToVerify are not installed by default.
+        for (String pkg : PACKAGES) {
+            assertFalse("Package should not be installed in managed profile when disallowed: "
+                    + pkg, isPackageInstalledForUser(pkg, userInfo2.id));
+        }
+    }
+
+    // Verify that if any packages are disallowed to install during creation of managed profile can
+    // still be installed later.
+    @MediumTest
+    public void testAddManagedProfile_disallowedPackagesInstalledLater() throws Exception {
+        final int primaryUserId = mUserManager.getPrimaryUser().id;
+        UserInfo userInfo = createProfileForUser("Managed",
+                UserInfo.FLAG_MANAGED_PROFILE, primaryUserId, PACKAGES);
+        // Verify that the packagesToVerify are not installed by default.
+        for (String pkg : PACKAGES) {
+            assertFalse("Package should not be installed in managed profile when disallowed: "
+                    + pkg, isPackageInstalledForUser(pkg, userInfo.id));
+        }
+
+        // Verify that the disallowed packages during profile creation can be installed now.
+        for (String pkg : PACKAGES) {
+            assertEquals("Package could not be installed: " + pkg,
+                    PackageManager.INSTALL_SUCCEEDED,
+                    mPackageManager.installExistingPackageAsUser(pkg, userInfo.id));
+        }
+    }
+
     @MediumTest
     public void testAddRestrictedProfile() throws Exception {
         UserInfo userInfo = createRestrictedProfile("Profile");
@@ -357,6 +409,14 @@
         switchUser(startUser);
     }
 
+    private boolean isPackageInstalledForUser(String packageName, int userId) {
+        try {
+            return mPackageManager.getPackageInfoAsUser(packageName, 0, userId) != null;
+        } catch (PackageManager.NameNotFoundException e) {
+            return false;
+        }
+    }
+
     private void switchUser(int userId) {
         synchronized (mUserSwitchLock) {
             ActivityManager am = getContext().getSystemService(ActivityManager.class);
@@ -401,7 +461,13 @@
     }
 
     private UserInfo createProfileForUser(String name, int flags, int userHandle) {
-        UserInfo profile = mUserManager.createProfileForUser(name, flags, userHandle);
+        return createProfileForUser(name, flags, userHandle, null);
+    }
+
+    private UserInfo createProfileForUser(String name, int flags, int userHandle,
+            String[] disallowedPackages) {
+        UserInfo profile = mUserManager.createProfileForUser(
+                name, flags, userHandle, disallowedPackages);
         if (profile != null) {
             usersToRemove.add(profile.id);
         }
diff --git a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
index 05cb31e..d4104bd 100644
--- a/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
+++ b/telephony/java/com/android/internal/telephony/CallerInfoAsyncQuery.java
@@ -176,13 +176,13 @@
                     // However, if there is any code that this Handler calls (such as in
                     // super.handleMessage) that DOES place unexpected messages on the
                     // queue, then we need pass these messages on.
-                    if (DBG) Rlog.d(LOG_TAG, "Unexpected command (CookieWrapper is null): " + msg.what +
+                    Rlog.i(LOG_TAG, "Unexpected command (CookieWrapper is null): " + msg.what +
                             " ignored by CallerInfoWorkerHandler, passing onto parent.");
 
                     super.handleMessage(msg);
                 } else {
 
-                    if (DBG) Rlog.d(LOG_TAG, "Processing event: " + cw.event + " token (arg1): " + msg.arg1 +
+                    Rlog.d(LOG_TAG, "Processing event: " + cw.event + " token (arg1): " + msg.arg1 +
                         " command: " + msg.what + " query URI: " + sanitizeUriToString(args.uri));
 
                     switch (cw.event) {
@@ -239,7 +239,7 @@
          */
         @Override
         protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
-            if (DBG) Rlog.d(LOG_TAG, "##### onQueryComplete() #####   query complete for token: " + token);
+            Rlog.d(LOG_TAG, "##### onQueryComplete() #####   query complete for token: " + token);
 
             //get the cookie and notify the listener.
             CookieWrapper cw = (CookieWrapper) cookie;
@@ -248,7 +248,7 @@
                 // from within this code.
                 // However, if there is any code that calls this method, we should
                 // check the parameters to make sure they're viable.
-                if (DBG) Rlog.d(LOG_TAG, "Cookie is null, ignoring onQueryComplete() request.");
+                Rlog.i(LOG_TAG, "Cookie is null, ignoring onQueryComplete() request.");
                 if (cursor != null) {
                     cursor.close();
                 }
@@ -333,9 +333,11 @@
 
             //notify the listener that the query is complete.
             if (cw.listener != null) {
-                if (DBG) Rlog.d(LOG_TAG, "notifying listener: " + cw.listener.getClass().toString() +
+                Rlog.d(LOG_TAG, "notifying listener: " + cw.listener.getClass().toString() +
                              " for token: " + token + mCallerInfo);
                 cw.listener.onQueryComplete(token, cw.cookie, mCallerInfo);
+            } else {
+                Rlog.w(LOG_TAG, "There is no listener to notify for this query.");
             }
 
             if (cursor != null) {
diff --git a/tests/UiBench/Android.mk b/tests/UiBench/Android.mk
index f65d109..be9a541 100644
--- a/tests/UiBench/Android.mk
+++ b/tests/UiBench/Android.mk
@@ -2,6 +2,8 @@
 include $(CLEAR_VARS)
 
 LOCAL_MODULE_TAGS := tests
+LOCAL_SDK_VERSION := 24
+LOCAL_MIN_SDK_VERSION := 21
 
 # omit gradle 'build' dir
 LOCAL_SRC_FILES := $(call all-java-files-under,src)
diff --git a/tests/UiBench/AndroidManifest.xml b/tests/UiBench/AndroidManifest.xml
index cb5f6c7..b7b4894 100644
--- a/tests/UiBench/AndroidManifest.xml
+++ b/tests/UiBench/AndroidManifest.xml
@@ -141,6 +141,14 @@
                 <category android:name="com.android.test.uibench.TEST" />
             </intent-filter>
         </activity>
+        <activity
+            android:name=".RenderingJitter"
+            android:label="Rendering/Jitter" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="com.android.test.uibench.TEST" />
+            </intent-filter>
+        </activity>
 
         <!-- Inflation -->
         <activity
diff --git a/tests/UiBench/res/layout/rendering_jitter.xml b/tests/UiBench/res/layout/rendering_jitter.xml
new file mode 100644
index 0000000..aaa7551
--- /dev/null
+++ b/tests/UiBench/res/layout/rendering_jitter.xml
@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2016 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
+  -->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:orientation="vertical">
+
+    <TextView android:id="@+id/jitter_mma"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:singleLine="true" />
+
+    <TextView android:id="@+id/totalish_mma"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:singleLine="true" />
+
+    <TextView android:id="@+id/ui_frametime_mma"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:singleLine="true" />
+
+    <TextView android:id="@+id/rt_frametime_mma"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:singleLine="true" />
+
+    <TextView android:id="@+id/total_mma"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:singleLine="true" />
+
+    <View android:layout_width="match_parent"
+        android:layout_height="0px"
+        android:layout_weight="1" />
+
+    <view class="com.android.test.uibench.RenderingJitter$PointGraphView"
+        android:id="@+id/graph"
+        android:layout_height="200dp"
+        android:layout_width="match_parent" />
+
+</LinearLayout>
diff --git a/tests/UiBench/src/com/android/test/uibench/RenderingJitter.java b/tests/UiBench/src/com/android/test/uibench/RenderingJitter.java
new file mode 100644
index 0000000..e2a9bcb
--- /dev/null
+++ b/tests/UiBench/src/com/android/test/uibench/RenderingJitter.java
@@ -0,0 +1,366 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.test.uibench;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Message;
+import android.util.AttributeSet;
+import android.view.FrameMetrics;
+import android.view.View;
+import android.view.Window;
+import android.view.Window.OnFrameMetricsAvailableListener;
+import android.view.animation.AnimationUtils;
+import android.widget.TextView;
+
+public class RenderingJitter extends Activity {
+    private TextView mJitterReport;
+    private TextView mUiFrameTimeReport;
+    private TextView mRenderThreadTimeReport;
+    private TextView mTotalFrameTimeReport;
+    private TextView mMostlyTotalFrameTimeReport;
+    private PointGraphView mGraph;
+
+    private static Handler sMetricsHandler;
+    static {
+        HandlerThread thread = new HandlerThread("frameMetricsListener");
+        thread.start();
+        sMetricsHandler = new Handler(thread.getLooper());
+    }
+
+    private Handler mUpdateHandler = new Handler() {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case R.id.jitter_mma:
+                    mJitterReport.setText((CharSequence) msg.obj);
+                    break;
+                case R.id.totalish_mma:
+                    mMostlyTotalFrameTimeReport.setText((CharSequence) msg.obj);
+                    break;
+                case R.id.ui_frametime_mma:
+                    mUiFrameTimeReport.setText((CharSequence) msg.obj);
+                    break;
+                case R.id.rt_frametime_mma:
+                    mRenderThreadTimeReport.setText((CharSequence) msg.obj);
+                    break;
+                case R.id.total_mma:
+                    mTotalFrameTimeReport.setText((CharSequence) msg.obj);
+                    break;
+                case R.id.graph:
+                    mGraph.addJitterSample(msg.arg1, msg.arg2);
+                    break;
+            }
+        }
+    };
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.rendering_jitter);
+        View content = findViewById(android.R.id.content);
+        content.setBackground(new AnimatedBackgroundDrawable());
+        content.setKeepScreenOn(true);
+        mJitterReport = (TextView) findViewById(R.id.jitter_mma);
+        mMostlyTotalFrameTimeReport = (TextView) findViewById(R.id.totalish_mma);
+        mUiFrameTimeReport = (TextView) findViewById(R.id.ui_frametime_mma);
+        mRenderThreadTimeReport = (TextView) findViewById(R.id.rt_frametime_mma);
+        mTotalFrameTimeReport = (TextView) findViewById(R.id.total_mma);
+        mGraph = (PointGraphView) findViewById(R.id.graph);
+        mJitterReport.setText("abcdefghijklmnopqrstuvwxyz");
+        mMostlyTotalFrameTimeReport.setText("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
+        mUiFrameTimeReport.setText("0123456789");
+        mRenderThreadTimeReport.setText(",.!()[]{};");
+        getWindow().addOnFrameMetricsAvailableListener(mMetricsListener, sMetricsHandler);
+    }
+
+    public static final class PointGraphView extends View {
+        private static final float[] JITTER_LINES_MS = {
+                .5f, 1.0f, 1.5f, 2.0f, 3.0f, 4.0f, 5.0f
+        };
+        private static final String[] JITTER_LINES_LABELS = makeLabels(JITTER_LINES_MS);
+        private static final int[] JITTER_LINES_COLORS = new int[] {
+                0xFF00E676, 0xFFFFF176, 0xFFFDD835, 0xFFFBC02D, 0xFFF9A825,
+                0xFFF57F17, 0xFFDD2C00
+        };
+        private Paint mPaint = new Paint();
+        private float[] mJitterYs = new float[JITTER_LINES_MS.length];
+        private float mLabelWidth;
+        private float mLabelHeight;
+        private float mDensity;
+        private float mGraphScale;
+        private float mGraphMaxMs;
+
+        private float[] mJitterPoints;
+        private float[] mJitterAvgPoints;
+
+        public PointGraphView(Context context, AttributeSet attrs) {
+            super(context, attrs);
+            setWillNotDraw(false);
+            mDensity = context.getResources().getDisplayMetrics().density;
+            mPaint.setTextSize(dp(10));
+            Rect textBounds = new Rect();
+            mPaint.getTextBounds("8.8", 0, 3, textBounds);
+            mLabelWidth = textBounds.width() + dp(2);
+            mLabelHeight = textBounds.height();
+        }
+
+        public void addJitterSample(int jitterUs, int jitterUsAvg) {
+            for (int i = 1; i < mJitterPoints.length - 2; i += 2) {
+                mJitterPoints[i] = mJitterPoints[i + 2];
+                mJitterAvgPoints[i] = mJitterAvgPoints[i + 2];
+            }
+            mJitterPoints[mJitterPoints.length - 1] =
+                    getHeight() - mGraphScale * (jitterUs / 1000.0f);
+            mJitterAvgPoints[mJitterAvgPoints.length - 1] =
+                    getHeight() - mGraphScale * (jitterUsAvg / 1000.0f);
+            invalidate();
+        }
+
+        private float dp(float dp) {
+            return mDensity * dp;
+        }
+
+        @Override
+        protected void onDraw(Canvas canvas) {
+            canvas.drawColor(0x90000000);
+            int h = getHeight();
+            int w = getWidth();
+            mPaint.setColor(Color.WHITE);
+            mPaint.setStrokeWidth(dp(1));
+            canvas.drawLine(mLabelWidth, 0, mLabelWidth, h, mPaint);
+            for (int i = 0; i < JITTER_LINES_LABELS.length; i++) {
+                canvas.drawText(JITTER_LINES_LABELS[i],
+                        0, (float) Math.floor(mJitterYs[i] + mLabelHeight * .5f), mPaint);
+            }
+            for (int i = 0; i < JITTER_LINES_LABELS.length; i++) {
+                mPaint.setColor(JITTER_LINES_COLORS[i]);
+                canvas.drawLine(mLabelWidth, mJitterYs[i], w, mJitterYs[i], mPaint);
+            }
+            mPaint.setStrokeWidth(dp(2));
+            mPaint.setColor(Color.WHITE);
+            canvas.drawPoints(mJitterPoints, mPaint);
+            mPaint.setColor(0xFF2196F3);
+            canvas.drawPoints(mJitterAvgPoints, mPaint);
+        }
+
+        @Override
+        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
+            super.onSizeChanged(w, h, oldw, oldh);
+            int graphWidth = (int) ((w - mLabelWidth - dp(1)) / mDensity);
+            float[] oldJitterPoints = mJitterPoints;
+            float[] oldJitterAvgPoints = mJitterAvgPoints;
+            mJitterPoints = new float[graphWidth * 2];
+            mJitterAvgPoints = new float[graphWidth * 2];
+            for (int i = 0; i < mJitterPoints.length; i += 2) {
+                mJitterPoints[i] = mLabelWidth + (i / 2 + 1) * mDensity;
+                mJitterAvgPoints[i] = mJitterPoints[i];
+            }
+            if (oldJitterPoints != null) {
+                int newIndexShift = Math.max(mJitterPoints.length - oldJitterPoints.length, 0);
+                int oldIndexShift = oldJitterPoints.length - mJitterPoints.length;
+                for (int i = 1 + newIndexShift; i < mJitterPoints.length; i += 2) {
+                    mJitterPoints[i] = oldJitterPoints[i + oldIndexShift];
+                    mJitterAvgPoints[i] = oldJitterAvgPoints[i + oldIndexShift];
+                }
+            }
+            mGraphMaxMs = JITTER_LINES_MS[JITTER_LINES_MS.length - 1] + .5f;
+            mGraphScale = (h / mGraphMaxMs);
+            for (int i = 0; i < JITTER_LINES_MS.length; i++) {
+                mJitterYs[i] = (float) Math.floor(h - mGraphScale * JITTER_LINES_MS[i]);
+            }
+        }
+
+        private static String[] makeLabels(float[] divisions) {
+            String[] ret = new String[divisions.length];
+            for (int i = 0; i < divisions.length; i++) {
+                ret[i] = Float.toString(divisions[i]);
+            }
+            return ret;
+        }
+    }
+
+    private final OnFrameMetricsAvailableListener mMetricsListener = new OnFrameMetricsAvailableListener() {
+        private final static double WEIGHT = 40;
+        private long mPreviousFrameTotal;
+        private double mJitterMma;
+        private double mUiFrametimeMma;
+        private double mRtFrametimeMma;
+        private double mTotalFrametimeMma;
+        private double mMostlyTotalFrametimeMma;
+        private boolean mNeedsFirstValues = true;
+
+        @Override
+        public void onFrameMetricsAvailable(Window window, FrameMetrics frameMetrics,
+                int dropCountSinceLastInvocation) {
+            if (frameMetrics.getMetric(FrameMetrics.FIRST_DRAW_FRAME) == 1) {
+                return;
+            }
+
+            long uiDuration = frameMetrics.getMetric(FrameMetrics.INPUT_HANDLING_DURATION)
+                    + frameMetrics.getMetric(FrameMetrics.ANIMATION_DURATION)
+                    + frameMetrics.getMetric(FrameMetrics.LAYOUT_MEASURE_DURATION)
+                    + frameMetrics.getMetric(FrameMetrics.DRAW_DURATION);
+            long rtDuration = frameMetrics.getMetric(FrameMetrics.SYNC_DURATION)
+                    + frameMetrics.getMetric(FrameMetrics.COMMAND_ISSUE_DURATION);
+            long totalDuration = frameMetrics.getMetric(FrameMetrics.TOTAL_DURATION);
+            long jitter = Math.abs(totalDuration - mPreviousFrameTotal);
+            if (mNeedsFirstValues) {
+                mJitterMma = 0;
+                mUiFrametimeMma = uiDuration;
+                mRtFrametimeMma = rtDuration;
+                mTotalFrametimeMma = totalDuration;
+                mMostlyTotalFrametimeMma = uiDuration + rtDuration;
+                mNeedsFirstValues = false;
+            } else {
+                mJitterMma = add(mJitterMma, jitter);
+                mUiFrametimeMma = add(mUiFrametimeMma, uiDuration);
+                mRtFrametimeMma = add(mRtFrametimeMma, rtDuration);
+                mTotalFrametimeMma = add(mTotalFrametimeMma, totalDuration);
+                mMostlyTotalFrametimeMma = add(mMostlyTotalFrametimeMma, uiDuration + rtDuration);
+            }
+            mPreviousFrameTotal = totalDuration;
+            mUpdateHandler.obtainMessage(R.id.jitter_mma,
+                    String.format("Jitter: %.3fms", toMs(mJitterMma))).sendToTarget();
+            mUpdateHandler.obtainMessage(R.id.totalish_mma,
+                    String.format("CPU-total duration: %.3fms", toMs(mMostlyTotalFrametimeMma))).sendToTarget();
+            mUpdateHandler.obtainMessage(R.id.ui_frametime_mma,
+                    String.format("UI duration: %.3fms", toMs(mUiFrametimeMma))).sendToTarget();
+            mUpdateHandler.obtainMessage(R.id.rt_frametime_mma,
+                    String.format("RT duration: %.3fms", toMs(mRtFrametimeMma))).sendToTarget();
+            mUpdateHandler.obtainMessage(R.id.total_mma,
+                    String.format("Total duration: %.3fms", toMs(mTotalFrametimeMma))).sendToTarget();
+            mUpdateHandler.obtainMessage(R.id.graph, (int) (jitter / 1000),
+                    (int) (mJitterMma / 1000)).sendToTarget();
+        }
+
+        double add(double previous, double today) {
+            return (((WEIGHT - 1) * previous) + today) / WEIGHT;
+        }
+
+        double toMs(double val) {
+            return val / 1000000;
+        }
+    };
+
+    private static final class AnimatedBackgroundDrawable extends Drawable {
+        private static final int FROM_COLOR = 0xFF18FFFF;
+        private static final int TO_COLOR = 0xFF40C4FF;
+        private static final int DURATION = 1400;
+
+        private final Paint mPaint;
+        private boolean mReverse;
+        private long mStartTime;
+        private int mColor;
+
+        private boolean mReverseX;
+        private boolean mReverseY;
+        private float mX;
+        private float mY;
+        private float mRadius;
+        private float mMoveStep = 10.0f;
+
+        public AnimatedBackgroundDrawable() {
+            mPaint = new Paint();
+            mPaint.setColor(0xFFFFFF00);
+            mPaint.setAntiAlias(true);
+        }
+
+        @Override
+        public void draw(Canvas canvas) {
+            stepColor();
+            canvas.drawColor(mColor);
+
+            mX += (mReverseX ? -mMoveStep : mMoveStep);
+            mY += (mReverseY ? -mMoveStep : mMoveStep);
+            clampXY();
+            canvas.drawCircle(mX, mY, mRadius, mPaint);
+
+            invalidateSelf();
+        }
+
+        private void clampXY() {
+            if (mX <= mRadius) {
+                mReverseX = false;
+                mX = mRadius;
+            }
+            if (mY <= mRadius) {
+                mReverseY = false;
+                mY = mRadius;
+            }
+            float maxX = getBounds().width() - mRadius;
+            if (mX >= maxX) {
+                mReverseX = true;
+                mX = maxX;
+            }
+            float maxY = getBounds().height() - mRadius;
+            if (mY >= maxY) {
+                mReverseY = true;
+                mY = maxY;
+            }
+        }
+
+        @Override
+        protected void onBoundsChange(Rect bounds) {
+            super.onBoundsChange(bounds);
+            mMoveStep = Math.min(bounds.width(), bounds.height()) / 130.0f;
+            mRadius = Math.min(bounds.width(), bounds.height()) / 20.0f;
+        }
+
+        @Override
+        public void setAlpha(int alpha) {
+        }
+
+        @Override
+        public void setColorFilter(ColorFilter colorFilter) {
+        }
+
+        @Override
+        public int getOpacity() {
+            return PixelFormat.OPAQUE;
+        }
+
+        private void stepColor() {
+            if (mStartTime == 0) {
+                mStartTime = AnimationUtils.currentAnimationTimeMillis();
+            }
+            float frac = (AnimationUtils.currentAnimationTimeMillis() - mStartTime)
+                    / (float) DURATION;
+            if (frac > 1.0f) frac = 1.0f;
+            int dest = mReverse ? FROM_COLOR : TO_COLOR;
+            int src = mReverse ? TO_COLOR : FROM_COLOR;
+            int r = (int) (Color.red(src) + (Color.red(dest) - Color.red(src)) * frac);
+            int g = (int) (Color.green(src) + (Color.green(dest) - Color.green(src)) * frac);
+            int b = (int) (Color.blue(src) + (Color.blue(dest) - Color.blue(src)) * frac);
+            mColor = Color.rgb(r, g, b);
+            if (frac == 1.0f) {
+                mStartTime = 0;
+                mReverse = !mReverse;
+            }
+        }
+    }
+}