Merge "Fix LockscreenWallpaper panning" into nyc-dev
diff --git a/api/current.txt b/api/current.txt
index c1dbce7..f924b5b 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -891,6 +891,7 @@
     field public static final int notificationTimeout = 16843651; // 0x1010383
     field public static final int numColumns = 16843032; // 0x1010118
     field public static final int numStars = 16843076; // 0x1010144
+    field public static final int numberPickerStyle = 16844071; // 0x1010527
     field public static final int numbersBackgroundColor = 16843938; // 0x10104a2
     field public static final int numbersInnerTextColor = 16844001; // 0x10104e1
     field public static final int numbersSelectorColor = 16843939; // 0x10104a3
@@ -2534,6 +2535,7 @@
     field public static final int Widget_Material_Light_ListView = 16974513; // 0x10302b1
     field public static final int Widget_Material_Light_ListView_DropDown = 16974514; // 0x10302b2
     field public static final int Widget_Material_Light_MediaRouteButton = 16974515; // 0x10302b3
+    field public static final int Widget_Material_Light_NumberPicker = 16974557; // 0x10302dd
     field public static final int Widget_Material_Light_PopupMenu = 16974516; // 0x10302b4
     field public static final int Widget_Material_Light_PopupMenu_Overflow = 16974517; // 0x10302b5
     field public static final int Widget_Material_Light_PopupWindow = 16974518; // 0x10302b6
@@ -2566,6 +2568,7 @@
     field public static final int Widget_Material_ListView = 16974448; // 0x1030270
     field public static final int Widget_Material_ListView_DropDown = 16974449; // 0x1030271
     field public static final int Widget_Material_MediaRouteButton = 16974450; // 0x1030272
+    field public static final int Widget_Material_NumberPicker = 16974556; // 0x10302dc
     field public static final int Widget_Material_PopupMenu = 16974451; // 0x1030273
     field public static final int Widget_Material_PopupMenu_Overflow = 16974452; // 0x1030274
     field public static final int Widget_Material_PopupWindow = 16974453; // 0x1030275
@@ -22895,6 +22898,7 @@
     field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
     field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
     field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
+    field public static final java.lang.String COLUMN_RECORDING_PROHIBITED = "recording_prohibited";
     field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
     field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
     field public static final deprecated java.lang.String COLUMN_SEASON_NUMBER = "season_number";
@@ -34957,6 +34961,7 @@
     method public void onDestroy();
     method public boolean[] onGetSupportedCommands(java.lang.String[]);
     method public void onHandleAssist(android.os.Bundle, android.app.assist.AssistStructure, android.app.assist.AssistContent);
+    method public void onHandleAssistSecondary(android.os.Bundle, android.app.assist.AssistStructure, android.app.assist.AssistContent, int, int);
     method public void onHandleScreenshot(android.graphics.Bitmap);
     method public void onHide();
     method public boolean onKeyDown(int, android.view.KeyEvent);
diff --git a/api/system-current.txt b/api/system-current.txt
index 9a39b4c..915ceb2 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -988,6 +988,7 @@
     field public static final int notificationTimeout = 16843651; // 0x1010383
     field public static final int numColumns = 16843032; // 0x1010118
     field public static final int numStars = 16843076; // 0x1010144
+    field public static final int numberPickerStyle = 16844071; // 0x1010527
     field public static final int numbersBackgroundColor = 16843938; // 0x10104a2
     field public static final int numbersInnerTextColor = 16844001; // 0x10104e1
     field public static final int numbersSelectorColor = 16843939; // 0x10104a3
@@ -2638,6 +2639,7 @@
     field public static final int Widget_Material_Light_ListView = 16974513; // 0x10302b1
     field public static final int Widget_Material_Light_ListView_DropDown = 16974514; // 0x10302b2
     field public static final int Widget_Material_Light_MediaRouteButton = 16974515; // 0x10302b3
+    field public static final int Widget_Material_Light_NumberPicker = 16974557; // 0x10302dd
     field public static final int Widget_Material_Light_PopupMenu = 16974516; // 0x10302b4
     field public static final int Widget_Material_Light_PopupMenu_Overflow = 16974517; // 0x10302b5
     field public static final int Widget_Material_Light_PopupWindow = 16974518; // 0x10302b6
@@ -2670,6 +2672,7 @@
     field public static final int Widget_Material_ListView = 16974448; // 0x1030270
     field public static final int Widget_Material_ListView_DropDown = 16974449; // 0x1030271
     field public static final int Widget_Material_MediaRouteButton = 16974450; // 0x1030272
+    field public static final int Widget_Material_NumberPicker = 16974556; // 0x10302dc
     field public static final int Widget_Material_PopupMenu = 16974451; // 0x1030273
     field public static final int Widget_Material_PopupMenu_Overflow = 16974452; // 0x1030274
     field public static final int Widget_Material_PopupWindow = 16974453; // 0x1030275
@@ -24501,6 +24504,7 @@
     field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
     field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
     field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
+    field public static final java.lang.String COLUMN_RECORDING_PROHIBITED = "recording_prohibited";
     field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
     field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
     field public static final deprecated java.lang.String COLUMN_SEASON_NUMBER = "season_number";
@@ -37531,6 +37535,7 @@
     method public void onDestroy();
     method public boolean[] onGetSupportedCommands(java.lang.String[]);
     method public void onHandleAssist(android.os.Bundle, android.app.assist.AssistStructure, android.app.assist.AssistContent);
+    method public void onHandleAssistSecondary(android.os.Bundle, android.app.assist.AssistStructure, android.app.assist.AssistContent, int, int);
     method public void onHandleScreenshot(android.graphics.Bitmap);
     method public void onHide();
     method public boolean onKeyDown(int, android.view.KeyEvent);
diff --git a/api/test-current.txt b/api/test-current.txt
index 6895d48..0c86fd1 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -891,6 +891,7 @@
     field public static final int notificationTimeout = 16843651; // 0x1010383
     field public static final int numColumns = 16843032; // 0x1010118
     field public static final int numStars = 16843076; // 0x1010144
+    field public static final int numberPickerStyle = 16844071; // 0x1010527
     field public static final int numbersBackgroundColor = 16843938; // 0x10104a2
     field public static final int numbersInnerTextColor = 16844001; // 0x10104e1
     field public static final int numbersSelectorColor = 16843939; // 0x10104a3
@@ -2534,6 +2535,7 @@
     field public static final int Widget_Material_Light_ListView = 16974513; // 0x10302b1
     field public static final int Widget_Material_Light_ListView_DropDown = 16974514; // 0x10302b2
     field public static final int Widget_Material_Light_MediaRouteButton = 16974515; // 0x10302b3
+    field public static final int Widget_Material_Light_NumberPicker = 16974557; // 0x10302dd
     field public static final int Widget_Material_Light_PopupMenu = 16974516; // 0x10302b4
     field public static final int Widget_Material_Light_PopupMenu_Overflow = 16974517; // 0x10302b5
     field public static final int Widget_Material_Light_PopupWindow = 16974518; // 0x10302b6
@@ -2566,6 +2568,7 @@
     field public static final int Widget_Material_ListView = 16974448; // 0x1030270
     field public static final int Widget_Material_ListView_DropDown = 16974449; // 0x1030271
     field public static final int Widget_Material_MediaRouteButton = 16974450; // 0x1030272
+    field public static final int Widget_Material_NumberPicker = 16974556; // 0x10302dc
     field public static final int Widget_Material_PopupMenu = 16974451; // 0x1030273
     field public static final int Widget_Material_PopupMenu_Overflow = 16974452; // 0x1030274
     field public static final int Widget_Material_PopupWindow = 16974453; // 0x1030275
@@ -22963,6 +22966,7 @@
     field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
     field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
     field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
+    field public static final java.lang.String COLUMN_RECORDING_PROHIBITED = "recording_prohibited";
     field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
     field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
     field public static final deprecated java.lang.String COLUMN_SEASON_NUMBER = "season_number";
@@ -35032,6 +35036,7 @@
     method public void onDestroy();
     method public boolean[] onGetSupportedCommands(java.lang.String[]);
     method public void onHandleAssist(android.os.Bundle, android.app.assist.AssistStructure, android.app.assist.AssistContent);
+    method public void onHandleAssistSecondary(android.os.Bundle, android.app.assist.AssistStructure, android.app.assist.AssistContent, int, int);
     method public void onHandleScreenshot(android.graphics.Bitmap);
     method public void onHide();
     method public boolean onKeyDown(int, android.view.KeyEvent);
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 5116634..374c4f6 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -23,6 +23,8 @@
 
 import com.android.internal.app.IVoiceInteractor;
 
+import java.util.List;
+
 /**
  * Activity manager local system service interface.
  *
@@ -125,4 +127,10 @@
      * Callback for window manager to let activity manager know that the app transition is finished.
      */
     public abstract void notifyAppTransitionFinished();
+
+    /**
+     * Returns the top activity from each of the currently visible stacks. The first entry will be
+     * the focused activity.
+     */
+    public abstract List<IBinder> getTopVisibleActivities();
 }
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 65d48e6..7bf03de 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -2411,8 +2411,11 @@
             data.enforceInterface(IActivityManager.descriptor);
             int requestType = data.readInt();
             IResultReceiver receiver = IResultReceiver.Stub.asInterface(data.readStrongBinder());
+            Bundle receiverExtras = data.readBundle();
             IBinder activityToken = data.readStrongBinder();
-            boolean res = requestAssistContextExtras(requestType, receiver, activityToken);
+            boolean focused = data.readInt() == 1;
+            boolean res = requestAssistContextExtras(requestType, receiver, receiverExtras,
+                    activityToken, focused);
             reply.writeNoException();
             reply.writeInt(res ? 1 : 0);
             return true;
@@ -6080,13 +6083,16 @@
     }
 
     public boolean requestAssistContextExtras(int requestType, IResultReceiver receiver,
-            IBinder activityToken) throws RemoteException {
+            Bundle receiverExtras,
+            IBinder activityToken, boolean focused) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeInt(requestType);
         data.writeStrongBinder(receiver.asBinder());
+        data.writeBundle(receiverExtras);
         data.writeStrongBinder(activityToken);
+        data.writeInt(focused ? 1 : 0);
         mRemote.transact(REQUEST_ASSIST_CONTEXT_EXTRAS_TRANSACTION, data, reply, 0);
         reply.readException();
         boolean res = reply.readInt() != 0;
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 8ee6fd0..6975116 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -523,7 +523,8 @@
     public Bundle getAssistContextExtras(int requestType) throws RemoteException;
 
     public boolean requestAssistContextExtras(int requestType, IResultReceiver receiver,
-            IBinder activityToken) throws RemoteException;
+            Bundle receiverExtras,
+            IBinder activityToken, boolean focused) throws RemoteException;
 
     public void reportAssistContextExtras(IBinder token, Bundle extras,
             AssistStructure structure, AssistContent content, Uri referrer) throws RemoteException;
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index aef92cf..4c4f128 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -29,7 +29,6 @@
 import android.content.res.ResourcesKey;
 import android.hardware.display.DisplayManagerGlobal;
 import android.os.IBinder;
-import android.os.Trace;
 import android.util.ArrayMap;
 import android.util.DisplayMetrics;
 import android.util.LocaleList;
@@ -431,44 +430,37 @@
             @Nullable Configuration overrideConfig,
             @NonNull CompatibilityInfo compatInfo,
             @Nullable ClassLoader classLoader) {
-        try {
-            Trace.traceBegin(Trace.TRACE_TAG_RESOURCES,
-                    "ResourcesManager#createBaseActivityResources");
-            final ResourcesKey key = new ResourcesKey(
-                    resDir,
-                    splitResDirs,
-                    overlayDirs,
-                    libDirs,
-                    displayId,
-                    overrideConfig != null ? new Configuration(overrideConfig) : null, // Copy
-                    compatInfo);
-            classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader();
+        final ResourcesKey key = new ResourcesKey(
+                resDir,
+                splitResDirs,
+                overlayDirs,
+                libDirs,
+                displayId,
+                overrideConfig != null ? new Configuration(overrideConfig) : null, // Copy
+                compatInfo);
+        classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader();
 
-            if (DEBUG) {
-                Slog.d(TAG, "createBaseActivityResources activity=" + activityToken
-                        + " with key=" + key);
-            }
-
-            synchronized (this) {
-                final ActivityResources activityResources =
-                        getOrCreateActivityResourcesStructLocked(
-                                activityToken);
-
-                if (overrideConfig != null) {
-                    activityResources.overrideConfig.setTo(overrideConfig);
-                } else {
-                    activityResources.overrideConfig.setToDefaults();
-                }
-            }
-
-            // Update any existing Activity Resources references.
-            updateResourcesForActivity(activityToken, overrideConfig);
-
-            // Now request an actual Resources object.
-            return getOrCreateResources(activityToken, key, classLoader);
-        } finally {
-            Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
+        if (DEBUG) {
+            Slog.d(TAG, "createBaseActivityResources activity=" + activityToken
+                    + " with key=" + key);
         }
+
+        synchronized (this) {
+            final ActivityResources activityResources = getOrCreateActivityResourcesStructLocked(
+                    activityToken);
+
+            if (overrideConfig != null) {
+                activityResources.overrideConfig.setTo(overrideConfig);
+            } else {
+                activityResources.overrideConfig.setToDefaults();
+            }
+        }
+
+        // Update any existing Activity Resources references.
+        updateResourcesForActivity(activityToken, overrideConfig);
+
+        // Now request an actual Resources object.
+        return getOrCreateResources(activityToken, key, classLoader);
     }
 
     /**
@@ -498,8 +490,8 @@
             }
 
             if (activityToken != null) {
-                final ActivityResources activityResources =
-                        getOrCreateActivityResourcesStructLocked(activityToken);
+                final ActivityResources activityResources = getOrCreateActivityResourcesStructLocked(
+                        activityToken);
 
                 // Clean up any dead references so they don't pile up.
                 ArrayUtils.unstableRemoveIf(activityResources.activityResources,
@@ -547,7 +539,6 @@
         final String[] systemLocales = findSystemLocales
                 ? AssetManager.getSystem().getLocales() : null;
         final String[] nonSystemLocales = resourcesImpl.getAssets().getNonSystemLocales();
-
         // Avoid checking for non-pseudo-locales if we already know there were some from a previous
         // Resources. The default value (for when hasNonSystemLocales is true) doesn't matter,
         // since mHasNonSystemLocales will also be true, and thus isPseudoLocalesOnly would not be
@@ -622,21 +613,16 @@
             @Nullable Configuration overrideConfig,
             @NonNull CompatibilityInfo compatInfo,
             @Nullable ClassLoader classLoader) {
-        try {
-            Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "ResourcesManager#getResources");
-            final ResourcesKey key = new ResourcesKey(
-                    resDir,
-                    splitResDirs,
-                    overlayDirs,
-                    libDirs,
-                    displayId,
-                    overrideConfig != null ? new Configuration(overrideConfig) : null, // Copy
-                    compatInfo);
-            classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader();
-            return getOrCreateResources(activityToken, key, classLoader);
-        } finally {
-            Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
-        }
+        final ResourcesKey key = new ResourcesKey(
+                resDir,
+                splitResDirs,
+                overlayDirs,
+                libDirs,
+                displayId,
+                overrideConfig != null ? new Configuration(overrideConfig) : null, // Copy
+                compatInfo);
+        classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader();
+        return getOrCreateResources(activityToken, key, classLoader);
     }
 
     /**
@@ -650,104 +636,93 @@
      */
     public void updateResourcesForActivity(@NonNull IBinder activityToken,
             @Nullable Configuration overrideConfig) {
-        try {
-            Trace.traceBegin(Trace.TRACE_TAG_RESOURCES,
-                    "ResourcesManager#updateResourcesForActivity");
-            synchronized (this) {
-                final ActivityResources activityResources =
-                        getOrCreateActivityResourcesStructLocked(activityToken);
+        synchronized (this) {
+            final ActivityResources activityResources = getOrCreateActivityResourcesStructLocked(
+                    activityToken);
 
-                if (Objects.equals(activityResources.overrideConfig, overrideConfig)) {
-                    // They are the same, no work to do.
-                    return;
+            if (Objects.equals(activityResources.overrideConfig, overrideConfig)) {
+                // They are the same, no work to do.
+                return;
+            }
+
+            // Grab a copy of the old configuration so we can create the delta's of each
+            // Resources object associated with this Activity.
+            final Configuration oldConfig = new Configuration(activityResources.overrideConfig);
+
+            // Update the Activity's base override.
+            if (overrideConfig != null) {
+                activityResources.overrideConfig.setTo(overrideConfig);
+            } else {
+                activityResources.overrideConfig.setToDefaults();
+            }
+
+            if (DEBUG) {
+                Throwable here = new Throwable();
+                here.fillInStackTrace();
+                Slog.d(TAG, "updating resources override for activity=" + activityToken
+                        + " from oldConfig=" + Configuration.resourceQualifierString(oldConfig)
+                        + " to newConfig="
+                        + Configuration.resourceQualifierString(activityResources.overrideConfig),
+                        here);
+            }
+
+            final boolean activityHasOverrideConfig =
+                    !activityResources.overrideConfig.equals(Configuration.EMPTY);
+
+            // Rebase each Resources associated with this Activity.
+            final int refCount = activityResources.activityResources.size();
+            for (int i = 0; i < refCount; i++) {
+                WeakReference<Resources> weakResRef = activityResources.activityResources.get(i);
+                Resources resources = weakResRef.get();
+                if (resources == null) {
+                    continue;
                 }
 
-                // Grab a copy of the old configuration so we can create the delta's of each
-                // Resources object associated with this Activity.
-                final Configuration oldConfig = new Configuration(activityResources.overrideConfig);
+                // Extract the ResourcesKey that was last used to create the Resources for this
+                // activity.
+                final ResourcesKey oldKey = findKeyForResourceImplLocked(resources.getImpl());
+                if (oldKey == null) {
+                    Slog.e(TAG, "can't find ResourcesKey for resources impl="
+                            + resources.getImpl());
+                    continue;
+                }
 
-                // Update the Activity's base override.
+                // Build the new override configuration for this ResourcesKey.
+                final Configuration rebasedOverrideConfig = new Configuration();
                 if (overrideConfig != null) {
-                    activityResources.overrideConfig.setTo(overrideConfig);
-                } else {
-                    activityResources.overrideConfig.setToDefaults();
+                    rebasedOverrideConfig.setTo(overrideConfig);
                 }
 
+                if (activityHasOverrideConfig && oldKey.hasOverrideConfiguration()) {
+                    // Generate a delta between the old base Activity override configuration and
+                    // the actual final override configuration that was used to figure out the real
+                    // delta this Resources object wanted.
+                    Configuration overrideOverrideConfig = Configuration.generateDelta(
+                            oldConfig, oldKey.mOverrideConfiguration);
+                    rebasedOverrideConfig.updateFrom(overrideOverrideConfig);
+                }
+
+                // Create the new ResourcesKey with the rebased override config.
+                final ResourcesKey newKey = new ResourcesKey(oldKey.mResDir, oldKey.mSplitResDirs,
+                        oldKey.mOverlayDirs, oldKey.mLibDirs, oldKey.mDisplayId,
+                        rebasedOverrideConfig, oldKey.mCompatInfo);
+
                 if (DEBUG) {
-                    Throwable here = new Throwable();
-                    here.fillInStackTrace();
-                    Slog.d(TAG, "updating resources override for activity=" + activityToken
-                            + " from oldConfig="
-                            + Configuration.resourceQualifierString(oldConfig)
-                            + " to newConfig="
-                            + Configuration.resourceQualifierString(
-                            activityResources.overrideConfig),
-                            here);
+                    Slog.d(TAG, "rebasing ref=" + resources + " from oldKey=" + oldKey
+                            + " to newKey=" + newKey);
                 }
 
-                final boolean activityHasOverrideConfig =
-                        !activityResources.overrideConfig.equals(Configuration.EMPTY);
+                ResourcesImpl resourcesImpl = findResourcesImplForKeyLocked(newKey);
+                if (resourcesImpl == null) {
+                    resourcesImpl = createResourcesImpl(newKey);
+                    mResourceImpls.put(newKey, new WeakReference<>(resourcesImpl));
+                }
 
-                // Rebase each Resources associated with this Activity.
-                final int refCount = activityResources.activityResources.size();
-                for (int i = 0; i < refCount; i++) {
-                    WeakReference<Resources> weakResRef = activityResources.activityResources.get(
-                            i);
-                    Resources resources = weakResRef.get();
-                    if (resources == null) {
-                        continue;
-                    }
-
-                    // Extract the ResourcesKey that was last used to create the Resources for this
-                    // activity.
-                    final ResourcesKey oldKey = findKeyForResourceImplLocked(resources.getImpl());
-                    if (oldKey == null) {
-                        Slog.e(TAG, "can't find ResourcesKey for resources impl="
-                                + resources.getImpl());
-                        continue;
-                    }
-
-                    // Build the new override configuration for this ResourcesKey.
-                    final Configuration rebasedOverrideConfig = new Configuration();
-                    if (overrideConfig != null) {
-                        rebasedOverrideConfig.setTo(overrideConfig);
-                    }
-
-                    if (activityHasOverrideConfig && oldKey.hasOverrideConfiguration()) {
-                        // Generate a delta between the old base Activity override configuration and
-                        // the actual final override configuration that was used to figure out the
-                        // real delta this Resources object wanted.
-                        Configuration overrideOverrideConfig = Configuration.generateDelta(
-                                oldConfig, oldKey.mOverrideConfiguration);
-                        rebasedOverrideConfig.updateFrom(overrideOverrideConfig);
-                    }
-
-                    // Create the new ResourcesKey with the rebased override config.
-                    final ResourcesKey newKey = new ResourcesKey(oldKey.mResDir,
-                            oldKey.mSplitResDirs,
-                            oldKey.mOverlayDirs, oldKey.mLibDirs, oldKey.mDisplayId,
-                            rebasedOverrideConfig, oldKey.mCompatInfo);
-
-                    if (DEBUG) {
-                        Slog.d(TAG, "rebasing ref=" + resources + " from oldKey=" + oldKey
-                                + " to newKey=" + newKey);
-                    }
-
-                    ResourcesImpl resourcesImpl = findResourcesImplForKeyLocked(newKey);
-                    if (resourcesImpl == null) {
-                        resourcesImpl = createResourcesImpl(newKey);
-                        mResourceImpls.put(newKey, new WeakReference<>(resourcesImpl));
-                    }
-
-                    if (resourcesImpl != resources.getImpl()) {
-                        // Set the ResourcesImpl, updating it for all users of this Resources
-                        // object.
-                        resources.setImpl(resourcesImpl);
-                    }
+                if (resourcesImpl != resources.getImpl()) {
+                    // Set the ResourcesImpl, updating it for all users of this Resources object.
+                    resources.setImpl(resourcesImpl);
                 }
             }
-        } finally {
-            Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
         }
     }
 
@@ -770,95 +745,86 @@
 
     public final boolean applyConfigurationToResourcesLocked(@NonNull Configuration config,
                                                              @Nullable CompatibilityInfo compat) {
-        try {
-            Trace.traceBegin(Trace.TRACE_TAG_RESOURCES,
-                    "ResourcesManager#applyConfigurationToResourcesLocked");
-
-            if (!mResConfiguration.isOtherSeqNewer(config) && compat == null) {
-                if (DEBUG || DEBUG_CONFIGURATION) Slog.v(TAG, "Skipping new config: curSeq="
-                        + mResConfiguration.seq + ", newSeq=" + config.seq);
-                return false;
-            }
-            int changes = mResConfiguration.updateFrom(config);
-            // Things might have changed in display manager, so clear the cached displays.
-            mDisplays.clear();
-            DisplayMetrics defaultDisplayMetrics = getDisplayMetrics();
-
-            if (compat != null && (mResCompatibilityInfo == null ||
-                    !mResCompatibilityInfo.equals(compat))) {
-                mResCompatibilityInfo = compat;
-                changes |= ActivityInfo.CONFIG_SCREEN_LAYOUT
-                        | ActivityInfo.CONFIG_SCREEN_SIZE
-                        | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
-            }
-
-            Configuration localeAdjustedConfig = config;
-            final LocaleList configLocales = config.getLocales();
-            if (!configLocales.isEmpty()) {
-                setDefaultLocalesLocked(configLocales);
-                final LocaleList adjustedLocales = LocaleList.getAdjustedDefault();
-                if (adjustedLocales
-                        != configLocales) { // has the same result as .equals() in this case
-                    // The first locale in the list was not chosen. So we create a modified
-                    // configuration with the adjusted locales (which moves the chosen locale to the
-                    // front).
-                    localeAdjustedConfig = new Configuration();
-                    localeAdjustedConfig.setTo(config);
-                    localeAdjustedConfig.setLocales(adjustedLocales);
-                    // Also adjust the locale list in mResConfiguration, so that the Resources
-                    // created later would have the same locale list.
-                    if (!mResConfiguration.getLocales().equals(adjustedLocales)) {
-                        mResConfiguration.setLocales(adjustedLocales);
-                        changes |= ActivityInfo.CONFIG_LOCALE;
-                    }
-                }
-            }
-
-            Resources.updateSystemConfiguration(localeAdjustedConfig, defaultDisplayMetrics,
-                    compat);
-
-            ApplicationPackageManager.configurationChanged();
-            //Slog.i(TAG, "Configuration changed in " + currentPackageName());
-
-            Configuration tmpConfig = null;
-
-            for (int i = mResourceImpls.size() - 1; i >= 0; i--) {
-                ResourcesKey key = mResourceImpls.keyAt(i);
-                ResourcesImpl r = mResourceImpls.valueAt(i).get();
-                if (r != null) {
-                    if (DEBUG || DEBUG_CONFIGURATION) Slog.v(TAG, "Changing resources "
-                            + r + " config to: " + localeAdjustedConfig);
-                    int displayId = key.mDisplayId;
-                    boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
-                    DisplayMetrics dm = defaultDisplayMetrics;
-                    final boolean hasOverrideConfiguration = key.hasOverrideConfiguration();
-                    if (!isDefaultDisplay || hasOverrideConfiguration) {
-                        if (tmpConfig == null) {
-                            tmpConfig = new Configuration();
-                        }
-                        tmpConfig.setTo(localeAdjustedConfig);
-                        if (!isDefaultDisplay) {
-                            dm = getDisplayMetrics(displayId);
-                            applyNonDefaultDisplayMetricsToConfiguration(dm, tmpConfig);
-                        }
-                        if (hasOverrideConfiguration) {
-                            tmpConfig.updateFrom(key.mOverrideConfiguration);
-                        }
-                        r.updateConfiguration(tmpConfig, dm, compat);
-                    } else {
-                        r.updateConfiguration(localeAdjustedConfig, dm, compat);
-                    }
-                    //Slog.i(TAG, "Updated app resources " + v.getKey()
-                    //        + " " + r + ": " + r.getConfiguration());
-                } else {
-                    //Slog.i(TAG, "Removing old resources " + v.getKey());
-                    mResourceImpls.removeAt(i);
-                }
-            }
-
-            return changes != 0;
-        } finally {
-            Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
+        if (!mResConfiguration.isOtherSeqNewer(config) && compat == null) {
+            if (DEBUG || DEBUG_CONFIGURATION) Slog.v(TAG, "Skipping new config: curSeq="
+                    + mResConfiguration.seq + ", newSeq=" + config.seq);
+            return false;
         }
+        int changes = mResConfiguration.updateFrom(config);
+        // Things might have changed in display manager, so clear the cached displays.
+        mDisplays.clear();
+        DisplayMetrics defaultDisplayMetrics = getDisplayMetrics();
+
+        if (compat != null && (mResCompatibilityInfo == null ||
+                !mResCompatibilityInfo.equals(compat))) {
+            mResCompatibilityInfo = compat;
+            changes |= ActivityInfo.CONFIG_SCREEN_LAYOUT
+                    | ActivityInfo.CONFIG_SCREEN_SIZE
+                    | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
+        }
+
+        Configuration localeAdjustedConfig = config;
+        final LocaleList configLocales = config.getLocales();
+        if (!configLocales.isEmpty()) {
+            setDefaultLocalesLocked(configLocales);
+            final LocaleList adjustedLocales = LocaleList.getAdjustedDefault();
+            if (adjustedLocales != configLocales) { // has the same result as .equals() in this case
+                // The first locale in the list was not chosen. So we create a modified
+                // configuration with the adjusted locales (which moves the chosen locale to the
+                // front).
+                localeAdjustedConfig = new Configuration();
+                localeAdjustedConfig.setTo(config);
+                localeAdjustedConfig.setLocales(adjustedLocales);
+                // Also adjust the locale list in mResConfiguration, so that the Resources created
+                // later would have the same locale list.
+                if (!mResConfiguration.getLocales().equals(adjustedLocales)) {
+                    mResConfiguration.setLocales(adjustedLocales);
+                    changes |= ActivityInfo.CONFIG_LOCALE;
+                }
+            }
+        }
+
+        Resources.updateSystemConfiguration(localeAdjustedConfig, defaultDisplayMetrics, compat);
+
+        ApplicationPackageManager.configurationChanged();
+        //Slog.i(TAG, "Configuration changed in " + currentPackageName());
+
+        Configuration tmpConfig = null;
+
+        for (int i = mResourceImpls.size() - 1; i >= 0; i--) {
+            ResourcesKey key = mResourceImpls.keyAt(i);
+            ResourcesImpl r = mResourceImpls.valueAt(i).get();
+            if (r != null) {
+                if (DEBUG || DEBUG_CONFIGURATION) Slog.v(TAG, "Changing resources "
+                        + r + " config to: " + localeAdjustedConfig);
+                int displayId = key.mDisplayId;
+                boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
+                DisplayMetrics dm = defaultDisplayMetrics;
+                final boolean hasOverrideConfiguration = key.hasOverrideConfiguration();
+                if (!isDefaultDisplay || hasOverrideConfiguration) {
+                    if (tmpConfig == null) {
+                        tmpConfig = new Configuration();
+                    }
+                    tmpConfig.setTo(localeAdjustedConfig);
+                    if (!isDefaultDisplay) {
+                        dm = getDisplayMetrics(displayId);
+                        applyNonDefaultDisplayMetricsToConfiguration(dm, tmpConfig);
+                    }
+                    if (hasOverrideConfiguration) {
+                        tmpConfig.updateFrom(key.mOverrideConfiguration);
+                    }
+                    r.updateConfiguration(tmpConfig, dm, compat);
+                } else {
+                    r.updateConfiguration(localeAdjustedConfig, dm, compat);
+                }
+                //Slog.i(TAG, "Updated app resources " + v.getKey()
+                //        + " " + r + ": " + r.getConfiguration());
+            } else {
+                //Slog.i(TAG, "Removing old resources " + v.getKey());
+                mResourceImpls.removeAt(i);
+            }
+        }
+
+        return changes != 0;
     }
 }
diff --git a/core/java/android/net/http/X509TrustManagerExtensions.java b/core/java/android/net/http/X509TrustManagerExtensions.java
index 87a0b70..e0fa63a 100644
--- a/core/java/android/net/http/X509TrustManagerExtensions.java
+++ b/core/java/android/net/http/X509TrustManagerExtensions.java
@@ -17,6 +17,7 @@
 package android.net.http;
 
 import android.annotation.SystemApi;
+import android.security.net.config.UserCertificateSource;
 
 import com.android.org.conscrypt.TrustManagerImpl;
 
@@ -43,7 +44,6 @@
     // Methods to use when mDelegate is not a TrustManagerImpl and duck typing is being used.
     private final X509TrustManager mTrustManager;
     private final Method mCheckServerTrusted;
-    private final Method mIsUserAddedCertificate;
     private final Method mIsSameTrustConfiguration;
 
     /**
@@ -57,7 +57,6 @@
             mDelegate = (TrustManagerImpl) tm;
             mTrustManager = null;
             mCheckServerTrusted = null;
-            mIsUserAddedCertificate = null;
             mIsSameTrustConfiguration = null;
             return;
         }
@@ -74,14 +73,6 @@
             throw new IllegalArgumentException("Required method"
                     + " checkServerTrusted(X509Certificate[], String, String, String) missing");
         }
-        // Check that isUserAddedCertificate is present.
-        try {
-            mIsUserAddedCertificate = tm.getClass().getMethod("isUserAddedCertificate",
-                    X509Certificate.class);
-        } catch (NoSuchMethodException e) {
-            throw new IllegalArgumentException(
-                    "Required method isUserAddedCertificate(X509Certificate) missing");
-        }
         // Get the option isSameTrustConfiguration method.
         Method isSameTrustConfiguration = null;
         try {
@@ -128,29 +119,15 @@
     /**
      * Checks whether a CA certificate is added by an user.
      *
-     * <p>Since {@link X509TrustManager#checkServerTrusted} allows its parameter {@code chain} to
+     * <p>Since {@link X509TrustManager#checkServerTrusted} may allow its parameter {@code chain} to
      * chain up to user-added CA certificates, this method can be used to perform additional
      * policies for user-added CA certificates.
      *
-     * @return {@code true} to indicate that the certificate was added by the user, {@code false}
-     * otherwise.
+     * @return {@code true} to indicate that the certificate authority exists in the user added
+     * certificate store, {@code false} otherwise.
      */
     public boolean isUserAddedCertificate(X509Certificate cert) {
-        if (mDelegate != null) {
-            return mDelegate.isUserAddedCertificate(cert);
-        } else {
-            try {
-                return (Boolean) mIsUserAddedCertificate.invoke(mTrustManager, cert);
-            } catch (IllegalAccessException e) {
-                throw new RuntimeException("Failed to call isUserAddedCertificate", e);
-            } catch (InvocationTargetException e) {
-                if (e.getCause() instanceof RuntimeException) {
-                    throw (RuntimeException) e.getCause();
-                } else {
-                    throw new RuntimeException("isUserAddedCertificate failed", e.getCause());
-                }
-            }
-        }
+        return UserCertificateSource.getInstance().findBySubjectAndPublicKey(cert) != null;
     }
 
     /**
diff --git a/core/java/android/security/net/config/NetworkSecurityTrustManager.java b/core/java/android/security/net/config/NetworkSecurityTrustManager.java
index 3c292ca..d9cc82a 100644
--- a/core/java/android/security/net/config/NetworkSecurityTrustManager.java
+++ b/core/java/android/security/net/config/NetworkSecurityTrustManager.java
@@ -115,15 +115,6 @@
         return trustedChain;
     }
 
-    /**
-     * Check if the provided certificate is a user added certificate authority.
-     * This is required by android.net.http.X509TrustManagerExtensions.
-     */
-    public boolean isUserAddedCertificate(X509Certificate cert) {
-        // TODO: Figure out the right way to handle this, and if it is still even used.
-        return false;
-    }
-
     private void checkPins(List<X509Certificate> chain) throws CertificateException {
         PinSet pinSet = mNetworkSecurityConfig.getPins();
         if (pinSet.pins.isEmpty()
diff --git a/core/java/android/security/net/config/RootTrustManager.java b/core/java/android/security/net/config/RootTrustManager.java
index 859e022..2a30f11 100644
--- a/core/java/android/security/net/config/RootTrustManager.java
+++ b/core/java/android/security/net/config/RootTrustManager.java
@@ -131,15 +131,6 @@
         return config.getTrustManager().checkServerTrusted(certs, authType, hostname);
     }
 
-    /**
-     * Check if the provided certificate is a user added certificate authority.
-     * This is required by android.net.http.X509TrustManagerExtensions.
-     */
-    public boolean isUserAddedCertificate(X509Certificate cert) {
-        // TODO: Figure out the right way to handle this, and if it is still even used.
-        return false;
-    }
-
     @Override
     public X509Certificate[] getAcceptedIssuers() {
         // getAcceptedIssuers is meant to be used to determine which trust anchors the server will
diff --git a/core/java/android/service/voice/IVoiceInteractionSession.aidl b/core/java/android/service/voice/IVoiceInteractionSession.aidl
index dbc28f7..78e6bc3 100644
--- a/core/java/android/service/voice/IVoiceInteractionSession.aidl
+++ b/core/java/android/service/voice/IVoiceInteractionSession.aidl
@@ -30,7 +30,8 @@
 oneway interface IVoiceInteractionSession {
     void show(in Bundle sessionArgs, int flags, IVoiceInteractionSessionShowCallback showCallback);
     void hide();
-    void handleAssist(in Bundle assistData, in AssistStructure structure, in AssistContent content);
+    void handleAssist(in Bundle assistData, in AssistStructure structure, in AssistContent content,
+                      int index, int count);
     void handleScreenshot(in Bitmap screenshot);
     void taskStarted(in Intent intent, int taskId);
     void taskFinished(in Intent intent, int taskId);
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index 6ff9fe7..e354ab3 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -77,7 +77,7 @@
  */
 public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCallbacks2 {
     static final String TAG = "VoiceInteractionSession";
-    static final boolean DEBUG = true;
+    static final boolean DEBUG = false;
 
     /**
      * Flag received in {@link #onShow}: originator requested that the session be started with
@@ -110,6 +110,16 @@
      */
     public static final int SHOW_SOURCE_ACTIVITY = 1<<4;
 
+    // Keys for Bundle values
+    /** @hide */
+    public static final String KEY_DATA = "data";
+    /** @hide */
+    public static final String KEY_STRUCTURE = "structure";
+    /** @hide */
+    public static final String KEY_CONTENT = "content";
+    /** @hide */
+    public static final String KEY_RECEIVER_EXTRAS = "receiverExtras";
+
     final Context mContext;
     final HandlerCaller mHandlerCaller;
 
@@ -229,7 +239,7 @@
 
         @Override
         public void handleAssist(final Bundle data, final AssistStructure structure,
-                final AssistContent content) {
+                final AssistContent content, final int index, final int count) {
             // We want to pre-warm the AssistStructure before handing it off to the main
             // thread.  We also want to do this on a separate thread, so that if the app
             // is for some reason slow (due to slow filling in of async children in the
@@ -247,8 +257,9 @@
                             failure = e;
                         }
                     }
-                    mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageOOOO(MSG_HANDLE_ASSIST,
-                            data, failure == null ? structure : null, failure, content));
+                    mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageOOOOII(MSG_HANDLE_ASSIST,
+                            data, failure == null ? structure : null, failure, content,
+                            index, count));
                 }
             };
             retriever.start();
@@ -831,9 +842,16 @@
                 case MSG_HANDLE_ASSIST:
                     args = (SomeArgs)msg.obj;
                     if (DEBUG) Log.d(TAG, "onHandleAssist: data=" + args.arg1
-                            + " structure=" + args.arg2 + " content=" + args.arg3);
-                    doOnHandleAssist((Bundle) args.arg1, (AssistStructure) args.arg2,
-                            (Throwable) args.arg3, (AssistContent) args.arg4);
+                            + " structure=" + args.arg2 + " content=" + args.arg3
+                            + " activityIndex=" + args.argi5 + " activityCount=" + args.argi6);
+                    if (args.argi5 == 0) {
+                        doOnHandleAssist((Bundle) args.arg1, (AssistStructure) args.arg2,
+                                (Throwable) args.arg3, (AssistContent) args.arg4);
+                    } else {
+                        doOnHandleAssistSecondary((Bundle) args.arg1, (AssistStructure) args.arg2,
+                                (Throwable) args.arg3, (AssistContent) args.arg4,
+                                args.argi5, args.argi6);
+                    }
                     break;
                 case MSG_HANDLE_SCREENSHOT:
                     if (DEBUG) Log.d(TAG, "onHandleScreenshot: " + msg.obj);
@@ -1320,6 +1338,14 @@
         onHandleAssist(data, structure, content);
     }
 
+    void doOnHandleAssistSecondary(Bundle data, AssistStructure structure, Throwable failure,
+            AssistContent content, int index, int count) {
+        if (failure != null) {
+            onAssistStructureFailure(failure);
+        }
+        onHandleAssistSecondary(data, structure, content, index, count);
+    }
+
     /**
      * Called when there has been a failure transferring the {@link AssistStructure} to
      * the assistant.  This may happen, for example, if the data is too large and results
@@ -1356,6 +1382,45 @@
     }
 
     /**
+     * Called to receive data from other applications that the user was or is interacting with,
+     * that are currently on the screen in a multi-window display environment, not including the
+     * currently focused activity. This could be
+     * a free-form window, a picture-in-picture window, or another window in a split-screen display.
+     * <p>
+     * This method is very similar to
+     * {@link #onHandleAssist} except that it is called
+     * for additional non-focused activities along with an index and count that indicates
+     * which additional activity the data is for. {@code index} will be between 1 and
+     * {@code count}-1 and this method is called once for each additional window, in no particular
+     * order. The {@code count} indicates how many windows to expect assist data for, including the
+     * top focused activity, which continues to be returned via {@link #onHandleAssist}.
+     * <p>
+     * To be responsive to assist requests, process assist data as soon as it is received,
+     * without waiting for all queued activities to return assist data.
+     *
+     * @param data Arbitrary data supplied by the app through
+     * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData}.
+     * May be null if assist data has been disabled by the user or device policy.
+     * @param structure If available, the structure definition of all windows currently
+     * displayed by the app.  May be null if assist data has been disabled by the user
+     * or device policy; will be an empty stub if the application has disabled assist
+     * by marking its window as secure.
+     * @param content Additional content data supplied by the app through
+     * {@link android.app.Activity#onProvideAssistContent Activity.onProvideAssistContent}.
+     * May be null if assist data has been disabled by the user or device policy; will
+     * not be automatically filled in with data from the app if the app has marked its
+     * window as secure.
+     * @param index the index of the additional activity that this data
+     *        is for.
+     * @param count the total number of additional activities for which the assist data is being
+     *        returned, including the focused activity that is returned via
+     *        {@link #onHandleAssist}.
+     */
+    public void onHandleAssistSecondary(@Nullable Bundle data, @Nullable AssistStructure structure,
+            @Nullable AssistContent content, int index, int count) {
+    }
+
+    /**
      * Called to receive a screenshot of what the user was currently viewing when an assist
      * session is started.  May be null if screenshots are disabled by the user, policy,
      * or application.  If the original show request did not specify
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index af46756..bb883ea 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -1512,6 +1512,24 @@
         outParams.x = drawingLocation[0] + xOffset;
         outParams.y = drawingLocation[1] + anchorHeight + yOffset;
 
+        // Let the window manager know to align the top to y.
+        outParams.gravity = Gravity.LEFT | Gravity.TOP;
+        outParams.width = width;
+        outParams.height = height;
+
+        // If width or height is unspecified. We can leave it to the window manager to match
+        // to the parent size, but for our local purposes of calculating positioning, we need
+        // to fill in real width and height values.
+        final Rect displayFrame = new Rect();
+        anchor.getWindowVisibleDisplayFrame(displayFrame);
+        if (width < 0) {
+            width = displayFrame.right - displayFrame.left;
+        }
+        if (height < 0) {
+            height = displayFrame.bottom - displayFrame.top;
+        }
+
+
         // If we need to adjust for gravity RIGHT, align to the bottom-right
         // corner of the anchor (still accounting for offsets).
         final int hgrav = Gravity.getAbsoluteGravity(gravity, anchor.getLayoutDirection())
@@ -1520,17 +1538,9 @@
             outParams.x -= width - anchorWidth;
         }
 
-        // Let the window manager know to align the top to y.
-        outParams.gravity = Gravity.LEFT | Gravity.TOP;
-        outParams.width = width;
-        outParams.height = height;
-
         final int[] screenLocation = mTmpScreenLocation;
         anchor.getLocationOnScreen(screenLocation);
 
-        final Rect displayFrame = new Rect();
-        anchor.getWindowVisibleDisplayFrame(displayFrame);
-
         // First, attempt to fit the popup vertically without resizing.
         final boolean fitsVertical = tryFitVertical(outParams, yOffset, height,
                 anchorHeight, drawingLocation[1], screenLocation[1], displayFrame.top,
@@ -2114,10 +2124,10 @@
 
         // If an explicit width/height has not specified, use the most recent
         // explicitly specified value (either from setWidth/Height or update).
-        if (width == -1) {
+        if (width < 0) {
             width = mWidth;
         }
-        if (height == -1) {
+        if (height < 0) {
             height = mHeight;
         }
 
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index bbefcb5..10afdb8 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -1745,6 +1745,9 @@
         }
 
         public void add(String name, T obj) {
+            if (name == null) {
+                name = "";
+            }
             mMap.put(name, obj);
             if (OVERFLOW_NAME.equals(name)) {
                 mCurOverflow = obj;
@@ -1776,6 +1779,9 @@
         }
 
         public T startObject(String name) {
+            if (name == null) {
+                name = "";
+            }
             T obj = mMap.get(name);
             if (obj != null) {
                 return obj;
@@ -1825,6 +1831,9 @@
         }
 
         public T stopObject(String name) {
+            if (name == null) {
+                name = "";
+            }
             T obj = mMap.get(name);
             if (obj != null) {
                 return obj;
diff --git a/core/java/com/android/internal/os/HandlerCaller.java b/core/java/com/android/internal/os/HandlerCaller.java
index 113768e..c26fc3a 100644
--- a/core/java/com/android/internal/os/HandlerCaller.java
+++ b/core/java/com/android/internal/os/HandlerCaller.java
@@ -209,6 +209,18 @@
         return mH.obtainMessage(what, 0, 0, args);
     }
 
+    public Message obtainMessageOOOOII(int what, Object arg1, Object arg2,
+            Object arg3, Object arg4, int arg5, int arg6) {
+        SomeArgs args = SomeArgs.obtain();
+        args.arg1 = arg1;
+        args.arg2 = arg2;
+        args.arg3 = arg3;
+        args.arg4 = arg4;
+        args.argi5 = arg5;
+        args.argi6 = arg6;
+        return mH.obtainMessage(what, 0, 0, args);
+    }
+
     public Message obtainMessageIIII(int what, int arg1, int arg2,
             int arg3, int arg4) {
         SomeArgs args = SomeArgs.obtain();
@@ -218,7 +230,7 @@
         args.argi4 = arg4;
         return mH.obtainMessage(what, 0, 0, args);
     }
-    
+
     public Message obtainMessageIIIIII(int what, int arg1, int arg2,
             int arg3, int arg4, int arg5, int arg6) {
         SomeArgs args = SomeArgs.obtain();
@@ -230,7 +242,7 @@
         args.argi6 = arg6;
         return mH.obtainMessage(what, 0, 0, args);
     }
-    
+
     public Message obtainMessageIIIIO(int what, int arg1, int arg2,
             int arg3, int arg4, Object arg5) {
         SomeArgs args = SomeArgs.obtain();
diff --git a/core/java/com/android/internal/view/menu/CascadingMenuPopup.java b/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
index ddca51f..5cb307f 100644
--- a/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
+++ b/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
@@ -347,14 +347,21 @@
         final LayoutInflater inflater = LayoutInflater.from(mContext);
         final MenuAdapter adapter = new MenuAdapter(menu, inflater, mOverflowOnly);
 
-        // Apply "force show icon" setting; if the menu being shown is the top level menu, apply the
-        // setting set on this CascadingMenuPopup by its creating code. If it's a submenu, or if no
-        // "force" setting was explicitly set, determine the setting by examining the items.
+        // Apply "force show icon" setting. There are 4 cases:
+        // (1) This is the top level menu. Only add spacing for icons if forced.
+        // (2) This is a submenu. Add spacing if any of the visible menu items has an icon.
+        // (3) This is a top level menu that is not an overflow menu. Add spacing if any of the
+        //     visible menu items has an icon.
+        // (4) This is an overflow menu or a top level menu that doesn't have "force" set.
+        //     Don't allow spacing.
         if (!isShowing() && mForceShowIcon) {
-            adapter.setForceShowIcon(mForceShowIcon);
-        } else {
-            adapter.setForceShowIcon(MenuPopup.shouldPreserveIconSpacing(menu));
+          // Case 1
+          adapter.setForceShowIcon(true);
+        } else if (isShowing() || !isShowing() && !mForceShowIcon && !mOverflowOnly) {
+          // Case 2 or 3
+          adapter.setForceShowIcon(MenuPopup.shouldPreserveIconSpacing(menu));
         }
+        // Case 4: Else, don't allow spacing for icons.
 
         final int menuWidth = measureIndividualMenuWidth(adapter, null, mContext, mMenuMaxWidth);
         final MenuPopupWindow popupWindow = createPopupWindow();
@@ -734,4 +741,4 @@
             return window.getListView();
         }
     }
-}
\ No newline at end of file
+}
diff --git a/core/java/com/android/internal/view/menu/MenuPopup.java b/core/java/com/android/internal/view/menu/MenuPopup.java
index 16e4156..10bd66f 100644
--- a/core/java/com/android/internal/view/menu/MenuPopup.java
+++ b/core/java/com/android/internal/view/menu/MenuPopup.java
@@ -187,6 +187,11 @@
     /**
      * Returns whether icon spacing needs to be preserved for the given menu, based on whether any
      * of its items contains an icon.
+     *
+     * NOTE: This should only be used for non-overflow-only menus, because this method does not
+     * take into account whether the menu items are being shown as part of the popup or or being
+     * shown as actions in the action bar.
+     *
      * @param menu
      * @return Whether to preserve icon spacing.
      */
diff --git a/core/res/res/layout/notification_template_right_icon.xml b/core/res/res/layout/notification_template_right_icon.xml
index b652127..65a5015 100644
--- a/core/res/res/layout/notification_template_right_icon.xml
+++ b/core/res/res/layout/notification_template_right_icon.xml
@@ -16,8 +16,8 @@
   -->
 
 <ImageView android:id="@+id/right_icon" xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="@dimen/notification_large_icon_width"
-    android:layout_height="@dimen/notification_large_icon_width"
+    android:layout_width="40dp"
+    android:layout_height="40dp"
     android:layout_marginEnd="@dimen/notification_content_margin_end"
     android:layout_marginTop="36dp"
     android:layout_gravity="top|end"
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 9178305..8200df8 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -162,9 +162,9 @@
     <dimen name="notification_min_height">92dp</dimen>
 
     <!-- The width of the big icons in notifications. -->
-    <dimen name="notification_large_icon_width">40dp</dimen>
+    <dimen name="notification_large_icon_width">64dp</dimen>
     <!-- The width of the big icons in notifications. -->
-    <dimen name="notification_large_icon_height">40dp</dimen>
+    <dimen name="notification_large_icon_height">64dp</dimen>
 
     <!-- The minimum width of the app name in the header if it shrinks -->
     <dimen name="notification_header_shrink_min_width">72dp</dimen>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 6ff7139..80b3a64 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2713,11 +2713,14 @@
     <public type="attr" name="forceHasOverlappingRendering" />
     <public type="attr" name="contentInsetStartWithNavigation" />
     <public type="attr" name="contentInsetEndWithActions" />
+    <public type="attr" name="numberPickerStyle" />
 
     <public type="style" name="Theme.Material.Light.DialogWhenLarge.DarkActionBar" />
     <public type="style" name="Widget.Material.SeekBar.Discrete" />
     <public type="style" name="Widget.Material.CompoundButton.Switch" />
     <public type="style" name="Widget.Material.Light.CompoundButton.Switch" />
+    <public type="style" name="Widget.Material.NumberPicker" />
+    <public type="style" name="Widget.Material.Light.NumberPicker" />
 
     <public type="id" name="accessibilityActionSetProgress" />
     <public type="id" name="icon_frame" />
diff --git a/docs/html/training/articles/keystore.jd b/docs/html/training/articles/keystore.jd
index aa1ed0a..026f7a0 100644
--- a/docs/html/training/articles/keystore.jd
+++ b/docs/html/training/articles/keystore.jd
@@ -152,8 +152,10 @@
 
 <p>Generating a new {@link java.security.PrivateKey} requires that
   you also specify the initial X.509 attributes that the self-signed
-  certificate will have. You can replace the certificate at a later
-  time with a certificate signed by a Certificate Authority.</p>
+  certificate will have. You can use
+  {@link java.security.KeyStore#setKeyEntry(String, java.security.Key, char[], java.security.cert.Certificate[]) KeyStore.setKeyEntry}
+  to replace the certificate at a later time with a certificate signed
+  by a Certificate Authority (CA).</p>
 
 <p>To generate the key, use a {@link java.security.KeyPairGenerator}
   with {@link android.security.KeyPairGeneratorSpec}:</p>
diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
index 715c875..6913f43 100644
--- a/libs/androidfw/AssetManager.cpp
+++ b/libs/androidfw/AssetManager.cpp
@@ -34,7 +34,9 @@
 #include <utils/String8.h>
 #include <utils/threads.h>
 #include <utils/Timers.h>
-#include <utils/Trace.h>
+#ifdef __ANDROID__
+#include <cutils/trace.h>
+#endif
 
 #include <assert.h>
 #include <dirent.h>
@@ -52,6 +54,14 @@
     _rc; })
 #endif
 
+#ifdef __ANDROID__
+#define MY_TRACE_BEGIN(x) ATRACE_BEGIN(x)
+#define MY_TRACE_END() ATRACE_END()
+#else
+#define MY_TRACE_BEGIN(x)
+#define MY_TRACE_END()
+#endif
+
 using namespace android;
 
 static const bool kIsDebug = false;
@@ -613,7 +623,7 @@
     ResTable* sharedRes = NULL;
     bool shared = true;
     bool onlyEmptyResources = true;
-    ATRACE_NAME(ap.path.string());
+    MY_TRACE_BEGIN(ap.path.string());
     Asset* idmap = openIdmapLocked(ap);
     size_t nextEntryIdx = mResources->getTableCount();
     ALOGV("Looking for resource asset in '%s'\n", ap.path.string());
@@ -693,6 +703,8 @@
     if (idmap != NULL) {
         delete idmap;
     }
+    MY_TRACE_END();
+
     return onlyEmptyResources;
 }
 
@@ -740,7 +752,6 @@
 
 void AssetManager::updateResourceParamsLocked() const
 {
-    ATRACE_CALL();
     ResTable* res = mResources;
     if (!res) {
         return;
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 15cb684..1ccc59a 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -24,7 +24,6 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include <algorithm>
 #include <limits>
 #include <memory>
 #include <type_traits>
@@ -5811,10 +5810,6 @@
     return NULL;
 }
 
-static bool compareResTableConfig(const ResTable_config& a, const ResTable_config& b) {
-    return a.compare(b) < 0;
-}
-
 void ResTable::getConfigurations(Vector<ResTable_config>* configs, bool ignoreMipmap,
         bool ignoreAndroidPackage, bool includeSystemConfigs) const {
     const size_t packageCount = mPackageGroups.size();
@@ -5845,11 +5840,17 @@
                     ResTable_config cfg;
                     memset(&cfg, 0, sizeof(ResTable_config));
                     cfg.copyFromDtoH(config->config);
-
-                    auto iter = std::lower_bound(configs->begin(), configs->end(), cfg,
-                                                 compareResTableConfig);
-                    if (iter == configs->end() || iter->compare(cfg) != 0) {
-                        configs->insertAt(cfg, std::distance(configs->begin(), iter));
+                    // only insert unique
+                    const size_t N = configs->size();
+                    size_t n;
+                    for (n = 0; n < N; n++) {
+                        if (0 == (*configs)[n].compare(cfg)) {
+                            break;
+                        }
+                    }
+                    // if we didn't find it
+                    if (n == N) {
+                        configs->add(cfg);
                     }
                 }
             }
@@ -5857,10 +5858,6 @@
     }
 }
 
-static bool compareString8AndCString(const String8& str, const char* cStr) {
-    return strcmp(str.string(), cStr) < 0;
-}
-
 void ResTable::getLocales(Vector<String8>* locales, bool includeSystemLocales) const
 {
     Vector<ResTable_config> configs;
@@ -5875,11 +5872,15 @@
     char locale[RESTABLE_MAX_LOCALE_LEN];
     for (size_t i=0; i<I; i++) {
         configs[i].getBcp47Locale(locale);
-
-        auto iter = std::lower_bound(locales->begin(), locales->end(), locale,
-                                     compareString8AndCString);
-        if (iter == locales->end() || strcmp(iter->string(), locale) != 0) {
-            locales->insertAt(String8(locale), std::distance(locales->begin(), iter));
+        const size_t J = locales->size();
+        size_t j;
+        for (j=0; j<J; j++) {
+            if (0 == strcmp(locale, (*locales)[j].string())) {
+                break;
+            }
+        }
+        if (j == J) {
+            locales->add(String8(locale));
         }
     }
 }
diff --git a/libs/androidfw/tests/ResTable_test.cpp b/libs/androidfw/tests/ResTable_test.cpp
index b8b4625..7cd7fb5 100644
--- a/libs/androidfw/tests/ResTable_test.cpp
+++ b/libs/androidfw/tests/ResTable_test.cpp
@@ -39,20 +39,8 @@
  */
 #include "data/basic/basic_arsc.h"
 
-/**
- * Include a binary library resource table.
- *
- * Package: com.android.test.basic
- */
 #include "data/lib/lib_arsc.h"
 
-/**
- * Include a system resource table.
- *
- * Package: android
- */
-#include "data/system/system_arsc.h"
-
 TEST(ResTableTest, shouldLoadSuccessfully) {
     ResTable table;
     ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
@@ -336,25 +324,4 @@
     ASSERT_EQ(uint32_t(600), val.data);
 }
 
-TEST(ResTableTest, GetConfigurationsReturnsUniqueList) {
-    ResTable table;
-    ASSERT_EQ(NO_ERROR, table.add(system_arsc, system_arsc_len));
-    ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
-
-    ResTable_config configSv;
-    memset(&configSv, 0, sizeof(configSv));
-    configSv.language[0] = 's';
-    configSv.language[1] = 'v';
-
-    Vector<ResTable_config> configs;
-    table.getConfigurations(&configs);
-
-    EXPECT_EQ(1, std::count(configs.begin(), configs.end(), configSv));
-
-    Vector<String8> locales;
-    table.getLocales(&locales);
-
-    EXPECT_EQ(1, std::count(locales.begin(), locales.end(), String8("sv")));
-}
-
 } // namespace
diff --git a/libs/androidfw/tests/TestHelpers.h b/libs/androidfw/tests/TestHelpers.h
index ff9be16..ac80d88 100644
--- a/libs/androidfw/tests/TestHelpers.h
+++ b/libs/androidfw/tests/TestHelpers.h
@@ -21,7 +21,7 @@
 enum { MAY_NOT_BE_BAG = false };
 
 static inline bool operator==(const android::ResTable_config& a, const android::ResTable_config& b) {
-    return a.compare(b) == 0;
+    return memcmp(&a, &b, sizeof(a)) == 0;
 }
 
 static inline ::std::ostream& operator<<(::std::ostream& out, const android::ResTable_config& c) {
diff --git a/libs/androidfw/tests/data/system/R.h b/libs/androidfw/tests/data/system/R.h
index 6a31fb8..27f25fe 100644
--- a/libs/androidfw/tests/data/system/R.h
+++ b/libs/androidfw/tests/data/system/R.h
@@ -33,12 +33,6 @@
     };
 }
 
-namespace integer {
-    enum {
-        number = 0x01030000, // sv
-    };
-}
-
 } // namespace R
 } // namespace android
 
diff --git a/libs/androidfw/tests/data/system/res/values-sv/values.xml b/libs/androidfw/tests/data/system/res/values-sv/values.xml
deleted file mode 100644
index b97bdb6..0000000
--- a/libs/androidfw/tests/data/system/res/values-sv/values.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.
--->
-
-<resources>
-    <public type="integer" name="number" id="0x01030000" />
-    <integer name="number">1</integer>
-</resources>
diff --git a/libs/androidfw/tests/data/system/system_arsc.h b/libs/androidfw/tests/data/system/system_arsc.h
index b0dab6b..215ecae 100644
--- a/libs/androidfw/tests/data/system/system_arsc.h
+++ b/libs/androidfw/tests/data/system/system_arsc.h
@@ -1,8 +1,8 @@
 unsigned char system_arsc[] = {
-  0x02, 0x00, 0x0c, 0x00, 0xf8, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x0c, 0x00, 0x18, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
   0x01, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0xd0, 0x03, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0xf0, 0x02, 0x00, 0x00,
   0x01, 0x00, 0x00, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x72, 0x00,
   0x6f, 0x00, 0x69, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -25,33 +25,26 @@
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00,
-  0x04, 0x00, 0x00, 0x00, 0x98, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x78, 0x00, 0x00, 0x00,
-  0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x0c, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00,
-  0x04, 0x00, 0x61, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x00, 0x00,
-  0x05, 0x00, 0x73, 0x00, 0x74, 0x00, 0x79, 0x00, 0x6c, 0x00, 0x65, 0x00,
-  0x00, 0x00, 0x07, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x65, 0x00,
-  0x67, 0x00, 0x65, 0x00, 0x72, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x5e, 0x00,
-  0x61, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x2d, 0x00, 0x70, 0x00,
-  0x72, 0x00, 0x69, 0x00, 0x76, 0x00, 0x61, 0x00, 0x74, 0x00, 0x65, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x84, 0x00, 0x00, 0x00,
-  0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x18, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x00, 0x00, 0x60, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x40, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x61, 0x00, 0x74, 0x00, 0x74, 0x00,
+  0x72, 0x00, 0x00, 0x00, 0x05, 0x00, 0x73, 0x00, 0x74, 0x00, 0x79, 0x00,
+  0x6c, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00,
+  0x70, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
   0x0a, 0x00, 0x62, 0x00, 0x61, 0x00, 0x63, 0x00, 0x6b, 0x00, 0x67, 0x00,
   0x72, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x00, 0x00,
   0x0a, 0x00, 0x66, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x65, 0x00, 0x67, 0x00,
   0x72, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x00, 0x00,
   0x09, 0x00, 0x54, 0x00, 0x68, 0x00, 0x65, 0x00, 0x6d, 0x00, 0x65, 0x00,
-  0x2e, 0x00, 0x4f, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x00, 0x00, 0x06, 0x00,
-  0x6e, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x62, 0x00, 0x65, 0x00, 0x72, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,
-  0x00, 0x00, 0x00, 0x40, 0x01, 0x02, 0x4c, 0x00, 0x8c, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00,
-  0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x2e, 0x00, 0x4f, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40,
+  0x01, 0x02, 0x44, 0x00, 0x84, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -62,27 +55,15 @@
   0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x11, 0x00, 0x00, 0x00,
   0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x02, 0x4c, 0x00,
-  0x78, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-  0x50, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x02, 0x44, 0x00,
+  0x70, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
-  0x08, 0x00, 0x00, 0x1d, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0x01, 0x01,
-  0x08, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0xff, 0x02, 0x02, 0x10, 0x00,
-  0x14, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x40, 0x01, 0x02, 0x4c, 0x00, 0x60, 0x00, 0x00, 0x00,
-  0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00,
-  0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x76, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x08, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x10,
-  0x01, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00,
-  0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00,
+  0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x01, 0x01, 0x08, 0x00, 0x00, 0x1d, 0x00, 0x00, 0xff, 0xff,
+  0x01, 0x00, 0x01, 0x01, 0x08, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0xff
 };
-unsigned int system_arsc_len = 1016;
+unsigned int system_arsc_len = 792;
diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java
index e8c50e3..db7b43a 100644
--- a/media/java/android/media/tv/TvContract.java
+++ b/media/java/android/media/tv/TvContract.java
@@ -1217,6 +1217,18 @@
         public static final String COLUMN_SEARCHABLE = "searchable";
 
         /**
+         * The flag indicating whether recording of this program is prohibited.
+         *
+         * <p>A value of 1 indicates that recording of this program is prohibited and application
+         * will not schedule any recording for this program. A value of 0 indicates that the
+         * recording is not prohibited. If not specified, this value is set to 0 (not prohibited) by
+         * default.
+         *
+         * <p>Type: INTEGER (boolean)
+         */
+        public static final String COLUMN_RECORDING_PROHIBITED = "recording_prohibited";
+
+        /**
          * Internal data used by individual TV input services.
          *
          * <p>This is internal to the provider that inserted it, and should not be decoded by other
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index d74dda6..bfd938e 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -483,26 +483,19 @@
         }
 
         /**
-         * This is called when the start playback position is changed.
-         *
-         * <p>The start playback position of the time shifted program should be adjusted when the TV
-         * input cannot retain the whole recorded program due to some reason (e.g. limitation on
-         * storage space). This is necessary to prevent the application from allowing the user to
-         * seek to a time position that is not reachable.
+         * This is called when the start position for time shifting has changed.
          *
          * @param session A {@link TvInputManager.Session} associated with this callback.
-         * @param timeMs The start playback position of the time shifted program, in milliseconds
-         *            since the epoch.
+         * @param timeMs The start position for time shifting, in milliseconds since the epoch.
          */
         public void onTimeShiftStartPositionChanged(Session session, long timeMs) {
         }
 
         /**
-         * This is called when the current playback position is changed.
+         * This is called when the current position for time shifting is changed.
          *
          * @param session A {@link TvInputManager.Session} associated with this callback.
-         * @param timeMs The current playback position of the time shifted program, in milliseconds
-         *            since the epoch.
+         * @param timeMs The current position for time shifting, in milliseconds since the epoch.
          */
         public void onTimeShiftCurrentPositionChanged(Session session, long timeMs) {
         }
diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java
index 3780f6f..e134635 100644
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -996,15 +996,18 @@
         }
 
         /**
-         * Returns the start playback position for time shifting, in milliseconds since the epoch.
+         * Returns the start position for time shifting, in milliseconds since the epoch.
          * Returns {@link TvInputManager#TIME_SHIFT_INVALID_TIME} if the position is unknown at the
          * moment.
          *
-         * <p>The start playback position of the time shifted program should be adjusted when the
-         * implementation cannot retain the whole recorded program due to some reason (e.g.
-         * limitation on storage space). It is the earliest possible time position that the user can
-         * seek to, thus failure to notifying its change immediately might result in bad experience
-         * where the application allows the user to seek to an invalid time position.
+         * <p>The start position for time shifting indicates the earliest possible time the user can
+         * seek to. Initially this is equivalent to the time when the implementation starts
+         * recording. Later it may be adjusted because there is insufficient space or the duration
+         * of recording is limited by the implementation. The application does not allow the user to
+         * seek to a position earlier than the start position.
+         *
+         * <p>For playback of a recorded program initiated by {@link #onTimeShiftPlay(Uri)}, the
+         * start position is the time when playback starts. It does not change.
          *
          * @see #onTimeShiftPlay(Uri)
          * @see #onTimeShiftResume()
@@ -1018,13 +1021,13 @@
         }
 
         /**
-         * Returns the current playback position for time shifting, in milliseconds since the epoch.
+         * Returns the current position for time shifting, in milliseconds since the epoch.
          * Returns {@link TvInputManager#TIME_SHIFT_INVALID_TIME} if the position is unknown at the
          * moment.
          *
-         * <p>Note that the current playback position should be equal to or greater than the start
-         * playback position reported by {@link #onTimeShiftGetStartPosition}. Failure to notifying
-         * the correct current position might lead to bad user experience.
+         * <p>The current position for time shifting is the same as the current position of
+         * playback. It should be equal to or greater than the start position reported by
+         * {@link #onTimeShiftGetStartPosition()}.
          *
          * @see #onTimeShiftPlay(Uri)
          * @see #onTimeShiftResume()
diff --git a/media/java/android/media/tv/TvView.java b/media/java/android/media/tv/TvView.java
index 71b0193..10cec1f 100644
--- a/media/java/android/media/tv/TvView.java
+++ b/media/java/android/media/tv/TvView.java
@@ -848,32 +848,34 @@
     public abstract static class TimeShiftPositionCallback {
 
         /**
-         * This is called when the start playback position is changed.
+         * This is called when the start position for time shifting has changed.
          *
-         * <p>The start playback position of the time shifted program can be adjusted by the TV
-         * input when it cannot retain the whole recorded program due to some reason (e.g.
-         * limitation on storage space). The application should not allow the user to seek to a
-         * position earlier than the start position.
+         * <p>The start position for time shifting indicates the earliest possible time the user can
+         * seek to. Initially this is equivalent to the time when the underlying TV input starts
+         * recording. Later it may be adjusted because there is insufficient space or the duration
+         * of recording is limited. The application must not allow the user to seek to a position
+         * earlier than the start position.
          *
-         * <p>Note that {@code timeMs} is not relative time in the program but wall-clock time,
-         * which is intended to avoid calling this method unnecessarily around program boundaries.
+         * <p>For playback of a recorded program initiated by {@link #timeShiftPlay(String, Uri)},
+         * the start position is the time when playback starts. It does not change.
          *
          * @param inputId The ID of the TV input bound to this view.
-         * @param timeMs The start playback position of the time shifted program, in milliseconds
-         *            since the epoch.
+         * @param timeMs The start position for time shifting, in milliseconds since the epoch.
          */
         public void onTimeShiftStartPositionChanged(String inputId, long timeMs) {
         }
 
         /**
-         * This is called when the current playback position is changed.
+         * This is called when the current position for time shifting has changed.
          *
-         * <p>Note that {@code timeMs} is not relative time in the program but wall-clock time,
-         * which is intended to avoid calling this method unnecessarily around program boundaries.
+         * <p>The current position for time shifting is the same as the current position of
+         * playback. During playback, the current position changes continuously. When paused, it
+         * does not change.
+         *
+         * <p>Note that {@code timeMs} is wall-clock time.
          *
          * @param inputId The ID of the TV input bound to this view.
-         * @param timeMs The current playback position of the time shifted program, in milliseconds
-         *            since the epoch.
+         * @param timeMs The current position for time shifting, in milliseconds since the epoch.
          */
         public void onTimeShiftCurrentPositionChanged(String inputId, long timeMs) {
         }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentClipper.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentClipper.java
index 15bfc3b..059b5e0 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentClipper.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentClipper.java
@@ -32,6 +32,7 @@
 import libcore.io.IoUtils;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 
 /**
@@ -76,7 +77,8 @@
      * This should be run from inside an AsyncTask.
      */
     public List<DocumentInfo> getClippedDocuments() {
-        return getDocumentsFromClipData(mClipboard.getPrimaryClip());
+        ClipData data = mClipboard.getPrimaryClip();
+        return data == null ? Collections.EMPTY_LIST : getDocumentsFromClipData(data);
     }
 
     /**
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
index 0e27622..2be93b8 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
@@ -17,6 +17,7 @@
 package com.android.documentsui;
 
 import static com.android.documentsui.Shared.TAG;
+import static com.android.documentsui.State.ACTION_CREATE;
 
 import android.app.Fragment;
 import android.app.FragmentManager;
@@ -107,8 +108,9 @@
                 mAdapter.update(data);
 
                 // When launched into empty recents, show drawer
-                if (mAdapter.isEmpty() && !state.hasLocationChanged() &&
-                        context instanceof DocumentsActivity) {
+                if (mAdapter.isEmpty() && !state.hasLocationChanged()
+                        && state.action != ACTION_CREATE
+                        && context instanceof DocumentsActivity) {
                     ((DocumentsActivity) context).setRootsDrawerOpen(true);
                 }
             }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
index 22454ad..ccb2886 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
@@ -1179,14 +1179,23 @@
                 case DragEvent.ACTION_DROP:
                     // After a drop event, always stop highlighting the target.
                     setDropTargetHighlight(v, false);
+
+                    ClipData clipData = event.getClipData();
+                    if (clipData == null) {
+                        Log.w(TAG, "Received invalid drop event with null clipdata. Ignoring.");
+                        return false;
+                    }
+
                     // Don't copy from the cwd into the cwd. Note: this currently doesn't work for
                     // multi-window drag, because localState isn't carried over from one process to
                     // another.
                     Object src = event.getLocalState();
                     DocumentInfo dst = getDestination(v);
                     if (Objects.equals(src, dst)) {
+                        if (DEBUG) Log.d(TAG, "Drop target same as source. Ignoring.");
                         return false;
                     }
+
                     // Recognize multi-window drag and drop based on the fact that localState is not
                     // carried between processes. It will stop working when the localsState behavior
                     // is changed. The info about window should be passed in the localState then.
@@ -1195,7 +1204,8 @@
                     Metrics.logUserAction(getContext(),
                             src == null ? Metrics.USER_ACTION_DRAG_N_DROP_MULTI_WINDOW
                                     : Metrics.USER_ACTION_DRAG_N_DROP);
-                    copyFromClipData(event.getClipData(), dst);
+
+                    copyFromClipData(clipData, dst);
                     return true;
             }
             return false;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
index e6217b2..e3eae33 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
@@ -90,6 +90,10 @@
      */
     private static final class DocumentsTuner extends FragmentTuner {
 
+        // We use this to keep track of whether a model has been previously loaded or not so we can
+        // open the drawer on empty directories on first launch
+        private boolean mModelPreviousLoaded;
+
         public DocumentsTuner(Context context, State state) {
             super(context, state);
         }
@@ -178,10 +182,12 @@
                 showDrawer = true;
             }
 
-            if (showDrawer && !mState.hasInitialLocationChanged() && !isSearch) {
+            if (showDrawer && !mState.hasInitialLocationChanged() && !isSearch
+                    && !mModelPreviousLoaded) {
                 // This noops on layouts without drawer, so no need to guard.
                 ((BaseActivity) mContext).setRootsDrawerOpen(true);
             }
+            mModelPreviousLoaded = true;
         }
 
         @Override
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/FileOperationService.java b/packages/DocumentsUI/src/com/android/documentsui/services/FileOperationService.java
index 580fa38..871e135 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/services/FileOperationService.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/FileOperationService.java
@@ -229,31 +229,32 @@
             @OpType int operationType, String id, List<DocumentInfo> srcs, DocumentInfo srcParent,
             DocumentStack stack) {
 
+        if (srcs.isEmpty()) {
+            Log.w(TAG, "Ignoring job request with empty srcs list. Id: " + id);
+            return null;
+        }
+
         if (mRunning.containsKey(id)) {
             Log.w(TAG, "Duplicate job id: " + id
                     + ". Ignoring job request for srcs: " + srcs + ", stack: " + stack + ".");
             return null;
         }
 
-        Job job = null;
         switch (operationType) {
             case OPERATION_COPY:
-                job = jobFactory.createCopy(this, getApplicationContext(), this, id, stack, srcs);
-                break;
+                return jobFactory.createCopy(
+                        this, getApplicationContext(), this, id, stack, srcs);
             case OPERATION_MOVE:
-                job = jobFactory.createMove(this, getApplicationContext(), this, id, stack, srcs,
+                return jobFactory.createMove(
+                        this, getApplicationContext(), this, id, stack, srcs,
                         srcParent);
-                break;
             case OPERATION_DELETE:
-                job = jobFactory.createDelete(this, getApplicationContext(), this, id, stack, srcs,
+                return jobFactory.createDelete(
+                        this, getApplicationContext(), this, id, stack, srcs,
                         srcParent);
-                break;
             default:
                 throw new UnsupportedOperationException();
         }
-
-        assert(job != null);
-        return job;
     }
 
     @GuardedBy("mRunning")
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/Job.java b/packages/DocumentsUI/src/com/android/documentsui/services/Job.java
index c723ac6..b4f1299 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/services/Job.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/Job.java
@@ -291,18 +291,24 @@
 
         Job createCopy(Context service, Context appContext, Listener listener,
                 String id, DocumentStack stack, List<DocumentInfo> srcs) {
+            assert(!srcs.isEmpty());
+            assert(stack.peek().isCreateSupported());
             return new CopyJob(service, appContext, listener, id, stack, srcs);
         }
 
         Job createMove(Context service, Context appContext, Listener listener,
                 String id, DocumentStack stack, List<DocumentInfo> srcs,
                 DocumentInfo srcParent) {
+            assert(!srcs.isEmpty());
+            assert(stack.peek().isCreateSupported());
             return new MoveJob(service, appContext, listener, id, stack, srcs, srcParent);
         }
 
         Job createDelete(Context service, Context appContext, Listener listener,
                 String id, DocumentStack stack, List<DocumentInfo> srcs,
                 DocumentInfo srcParent) {
+            assert(!srcs.isEmpty());
+            assert(stack.peek().isDirectory());  // we can't currently delete from archives.
             return new DeleteJob(service, appContext, listener, id, stack, srcs, srcParent);
         }
     }
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/services/FileOperationServiceTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/services/FileOperationServiceTest.java
index 4d5392e..96d963f 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/services/FileOperationServiceTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/services/FileOperationServiceTest.java
@@ -79,6 +79,16 @@
         mJobFactory.assertAllJobsStarted();
     }
 
+    public void testRunsJobs_AfterExceptionInJobCreation() throws Exception {
+        startService(createCopyIntent(new ArrayList<DocumentInfo>(), BETA_DOC));
+        startService(createCopyIntent(newArrayList(GAMMA_DOC), DELTA_DOC));
+
+        mJobFactory.assertJobsCreated(1);
+
+        mExecutor.runAll();
+        mJobFactory.assertAllJobsStarted();
+    }
+
     public void testRunsJobs_AfterFailure() throws Exception {
         startService(createCopyIntent(newArrayList(ALPHA_DOC), BETA_DOC));
         startService(createCopyIntent(newArrayList(GAMMA_DOC), DELTA_DOC));
@@ -182,9 +192,18 @@
             }
         }
 
+        void assertJobsCreated(int expected) {
+            assertEquals(expected, jobs.size());
+        }
+
         @Override
         Job createCopy(Context service, Context appContext, Listener listener, String id,
                 DocumentStack stack, List<DocumentInfo> srcs) {
+
+            if (srcs.isEmpty()) {
+                throw new RuntimeException("Empty srcs not supported!");
+            }
+
             TestJob job = new TestJob(service, appContext, listener, OPERATION_COPY, id, stack);
             jobs.add(job);
             return job;
diff --git a/packages/SettingsLib/res/layout/restricted_switch_preference.xml b/packages/SettingsLib/res/layout/restricted_switch_preference.xml
new file mode 100644
index 0000000..89dc10b
--- /dev/null
+++ b/packages/SettingsLib/res/layout/restricted_switch_preference.xml
@@ -0,0 +1,86 @@
+<?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="wrap_content"
+    android:minHeight="?android:attr/listPreferredItemHeightSmall"
+    android:gravity="center_vertical"
+    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+    android:background="?android:attr/activatedBackgroundIndicator"
+    android:clipToPadding="false">
+
+    <LinearLayout
+        android:id="@+id/icon_frame"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:minWidth="60dp"
+        android:gravity="start|center_vertical"
+        android:orientation="horizontal"
+        android:paddingEnd="12dp"
+        android:paddingTop="4dp"
+        android:paddingBottom="4dp">
+        <com.android.internal.widget.PreferenceImageView
+            android:id="@android:id/icon"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:maxWidth="48dp"
+            android:maxHeight="48dp" />
+    </LinearLayout>
+
+    <RelativeLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:paddingTop="16dp"
+        android:paddingBottom="16dp">
+
+        <TextView android:id="@android:id/title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:singleLine="true"
+            android:textAppearance="?android:attr/textAppearanceListItem"
+            android:ellipsize="marquee" />
+
+        <TextView android:id="@android:id/summary"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@android:id/title"
+            android:layout_alignStart="@android:id/title"
+            android:textAppearance="?android:attr/textAppearanceListItemSecondary"
+            android:textColor="?android:attr/textColorSecondary"
+            android:maxLines="10" />
+
+        <TextView android:id="@+id/additional_summary"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@android:id/summary"
+            android:layout_alignStart="@android:id/summary"
+            android:textAppearance="?android:attr/textAppearanceListItemSecondary"
+            android:textColor="?android:attr/textColorSecondary"
+            android:maxLines="10"
+            android:visibility="gone" />
+    </RelativeLayout>
+
+    <!-- Preference should place its actual preference widget here. -->
+    <LinearLayout android:id="@android:id/widget_frame"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:gravity="end|center_vertical"
+        android:paddingStart="16dp"
+        android:orientation="vertical" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SettingsLib/res/values/attrs.xml b/packages/SettingsLib/res/values/attrs.xml
index 4484613..4cdc177 100644
--- a/packages/SettingsLib/res/values/attrs.xml
+++ b/packages/SettingsLib/res/values/attrs.xml
@@ -15,10 +15,18 @@
 -->
 
 <resources>
+
     <declare-styleable name="RestrictedPreference">
+        <!-- The user restriction on which the preference disabled by admin state will be based on. -->
         <attr name="userRestriction" format="string" />
+        <!-- If true then we can use enabled/disabled by admin strings for summary (android.R.id.summary). -->
         <attr name="useAdminDisabledSummary" format="boolean" />
+        <!-- If true, an additional summary will be added in addition to the existing summary and
+        this will be used for enabled/disabled by admin strings leaving android.R.id.summary untouched.
+        As such when this is true, useAdminDisabledSummary will be overwritten to false. -->
+        <attr name="useAdditionalSummary" format="boolean" />
     </declare-styleable>
+
     <declare-styleable name="WifiEncryptionState">
         <attr name="state_encrypted" format="boolean" />
     </declare-styleable>
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
index f381286..dabbc61 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
@@ -17,12 +17,14 @@
 package com.android.settingslib;
 
 import android.content.Context;
+import android.content.res.TypedArray;
 import android.os.UserHandle;
 import android.support.v4.content.res.TypedArrayUtils;
 import android.support.v7.preference.PreferenceManager;
 import android.support.v7.preference.PreferenceViewHolder;
 import android.support.v14.preference.SwitchPreference;
 import android.util.AttributeSet;
+import android.util.TypedValue;
 import android.view.View;
 import android.widget.TextView;
 
@@ -34,12 +36,28 @@
  */
 public class RestrictedSwitchPreference extends SwitchPreference {
     RestrictedPreferenceHelper mHelper;
+    boolean mUseAdditionalSummary = false;
 
     public RestrictedSwitchPreference(Context context, AttributeSet attrs,
             int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
         setWidgetLayoutResource(R.layout.restricted_switch_widget);
         mHelper = new RestrictedPreferenceHelper(context, this, attrs);
+        if (attrs != null) {
+            final TypedArray attributes = context.obtainStyledAttributes(attrs,
+                    R.styleable.RestrictedPreference);
+            final TypedValue useAdditionalSummary =
+                    attributes.peekValue(R.styleable.RestrictedPreference_useAdditionalSummary);
+            if (useAdditionalSummary != null) {
+                mUseAdditionalSummary =
+                        (useAdditionalSummary.type == TypedValue.TYPE_INT_BOOLEAN
+                                && useAdditionalSummary.data != 0);
+            }
+        }
+        if (mUseAdditionalSummary) {
+            setLayoutResource(R.layout.restricted_switch_preference);
+            useAdminDisabledSummary(false);
+        }
     }
 
     public RestrictedSwitchPreference(Context context, AttributeSet attrs, int defStyleAttr) {
@@ -67,11 +85,29 @@
         if (switchWidget != null) {
             switchWidget.setVisibility(isDisabledByAdmin() ? View.GONE : View.VISIBLE);
         }
-        final TextView summaryView = (TextView) holder.findViewById(android.R.id.summary);
-        if (summaryView != null && isDisabledByAdmin()) {
-            summaryView.setText(
-                    isChecked() ? R.string.enabled_by_admin : R.string.disabled_by_admin);
-            summaryView.setVisibility(View.VISIBLE);
+        if (mUseAdditionalSummary) {
+            final TextView additionalSummaryView = (TextView) holder.findViewById(
+                    R.id.additional_summary);
+            if (additionalSummaryView != null) {
+                if (isDisabledByAdmin()) {
+                    additionalSummaryView.setText(
+                            isChecked() ? R.string.enabled_by_admin : R.string.disabled_by_admin);
+                    additionalSummaryView.setVisibility(View.VISIBLE);
+                }
+            } else {
+                additionalSummaryView.setVisibility(View.GONE);
+            }
+        } else {
+            final TextView summaryView = (TextView) holder.findViewById(android.R.id.summary);
+            if (summaryView != null) {
+                if (isDisabledByAdmin()) {
+                    summaryView.setText(
+                            isChecked() ? R.string.enabled_by_admin : R.string.disabled_by_admin);
+                    summaryView.setVisibility(View.VISIBLE);
+                }
+            }
+            // No need to change the visibility to GONE in the else case here since Preference class
+            // would have already changed it if there is no summary to display.
         }
     }
 
diff --git a/packages/SystemUI/res/layout-television/recents_on_tv.xml b/packages/SystemUI/res/layout-television/recents_on_tv.xml
index 280fd20..1dbd1b3 100644
--- a/packages/SystemUI/res/layout-television/recents_on_tv.xml
+++ b/packages/SystemUI/res/layout-television/recents_on_tv.xml
@@ -35,9 +35,9 @@
     <!-- Placeholder view to give focus to the PIP menus. -->
     <View
         android:id="@+id/pip"
-        android:layout_width="0dp"
-        android:layout_height="0dp"
+        android:layout_width="1dp"
+        android:layout_height="1dp"
         android:focusable="true"
-        android:visibility="gone" />
+        android:visibility="visible" />
 
 </com.android.systemui.recents.tv.views.RecentsTvView>
diff --git a/packages/SystemUI/res/layout/recents_task_view.xml b/packages/SystemUI/res/layout/recents_task_view.xml
index b1b2f1e..1978a93 100644
--- a/packages/SystemUI/res/layout/recents_task_view.xml
+++ b/packages/SystemUI/res/layout/recents_task_view.xml
@@ -18,47 +18,43 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:focusable="true">
-    <FrameLayout
-        android:id="@+id/task_view_content"
+    <com.android.systemui.recents.views.TaskViewThumbnail
+        android:id="@+id/task_view_thumbnail"
         android:layout_width="match_parent"
-        android:layout_height="match_parent">
-        <com.android.systemui.recents.views.TaskViewThumbnail
-            android:id="@+id/task_view_thumbnail"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent" />
+        android:layout_height="match_parent" />
 
-        <include layout="@layout/recents_task_view_header" />
+    <include layout="@layout/recents_task_view_header" />
 
-        <com.android.systemui.statusbar.AlphaOptimizedFrameLayout
-            android:id="@+id/lock_to_app_fab"
-            android:layout_width="@dimen/recents_lock_to_app_size"
-            android:layout_height="@dimen/recents_lock_to_app_size"
-            android:layout_gravity="bottom|right"
-            android:layout_marginRight="15dp"
-            android:layout_marginBottom="15dp"
-            android:translationZ="4dp"
-            android:contentDescription="@string/recents_lock_to_app_button_label"
-            android:background="@drawable/recents_lock_to_task_button_bg"
-            android:visibility="invisible"
-            android:alpha="0">
-            <ImageView
-                android:layout_width="@dimen/recents_lock_to_app_icon_size"
-                android:layout_height="@dimen/recents_lock_to_app_icon_size"
-                android:layout_gravity="center"
-                android:src="@drawable/recents_lock_to_app_pin" />
-        </com.android.systemui.statusbar.AlphaOptimizedFrameLayout>
+    <!-- TODO: Move this into a view stub -->
+    <com.android.systemui.statusbar.AlphaOptimizedFrameLayout
+        android:id="@+id/lock_to_app_fab"
+        android:layout_width="@dimen/recents_lock_to_app_size"
+        android:layout_height="@dimen/recents_lock_to_app_size"
+        android:layout_gravity="bottom|right"
+        android:layout_marginRight="15dp"
+        android:layout_marginBottom="15dp"
+        android:translationZ="4dp"
+        android:contentDescription="@string/recents_lock_to_app_button_label"
+        android:background="@drawable/recents_lock_to_task_button_bg"
+        android:visibility="invisible"
+        android:alpha="0">
+        <ImageView
+            android:layout_width="@dimen/recents_lock_to_app_icon_size"
+            android:layout_height="@dimen/recents_lock_to_app_icon_size"
+            android:layout_gravity="center"
+            android:src="@drawable/recents_lock_to_app_pin" />
+    </com.android.systemui.statusbar.AlphaOptimizedFrameLayout>
 
-        <!-- The incompatible app toast -->
-        <ViewStub android:id="@+id/incompatible_app_toast_stub"
-                    android:inflatedId="@+id/incompatible_app_toast"
-                    android:layout="@*android:layout/transient_notification"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_gravity="top|center_horizontal"
-                    android:layout_marginTop="48dp"
-                    android:layout_marginLeft="16dp"
-                    android:layout_marginRight="16dp" />
-    </FrameLayout>
+    <!-- The incompatible app toast -->
+    <ViewStub android:id="@+id/incompatible_app_toast_stub"
+                android:inflatedId="@+id/incompatible_app_toast"
+                android:layout="@*android:layout/transient_notification"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="top|center_horizontal"
+                android:layout_marginTop="48dp"
+                android:layout_marginLeft="16dp"
+                android:layout_marginRight="16dp" />
 </com.android.systemui.recents.views.TaskView>
 
 
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index cf2e338..03b9837 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -606,8 +606,8 @@
     <dimen name="recents_layout_z_min">3dp</dimen>
     <dimen name="recents_layout_z_max">24dp</dimen>
 
-    <!-- The margin between the freeform and stack.  We also don't want this to change across 
-         configurations that Recents can be opened in, so we define them statically for all 
+    <!-- The margin between the freeform and stack.  We also don't want this to change across
+         configurations that Recents can be opened in, so we define them statically for all
          display sizes. -->
     <dimen name="recents_freeform_layout_bottom_margin">16dp</dimen>
 
@@ -651,4 +651,7 @@
 
     <!-- The amount to translate when animating the removal of a task. -->
     <dimen name="recents_task_view_remove_anim_translation_x">100dp</dimen>
+
+    <!-- The alpha to apply to the recents row when it doesn't have focus -->
+    <item name="recents_recents_row_dim_alpha" format="float" type="dimen">0.5</item>
 </resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 0730083..aeb484f 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -33,6 +33,7 @@
         <item name="android:windowBackground">@color/transparent</item>
         <item name="android:colorBackgroundCacheHint">@null</item>
         <item name="android:windowShowWallpaper">true</item>
+        <item name="android:windowDisablePreview">true</item>
     </style>
 
     <!-- Performance optimized Recents theme (no wallpaper) -->
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index df79669..4d69280 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -98,7 +98,7 @@
 
     private RecentsPackageMonitor mPackageMonitor;
     private long mLastTabKeyEventTime;
-    private int mLastOrientation = Configuration.ORIENTATION_UNDEFINED;
+    private int mLastDeviceOrientation = Configuration.ORIENTATION_UNDEFINED;
     private boolean mFinishedOnStartup;
     private boolean mIgnoreAltTabRelease;
     private boolean mIsVisible;
@@ -276,7 +276,7 @@
         getWindow().getAttributes().privateFlags |=
                 WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY;
 
-        mLastOrientation = getResources().getConfiguration().orientation;
+        mLastDeviceOrientation = Utilities.getAppConfiguration(this).orientation;
         mFocusTimerDuration = getResources().getInteger(R.integer.recents_auto_advance_duration);
         mIterateTrigger = new DozeTrigger(mFocusTimerDuration, new Runnable() {
             @Override
@@ -426,13 +426,12 @@
     public void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
 
-
         // Notify of the config change
-        int newOrientation = getResources().getConfiguration().orientation;
+        int newDeviceOrientation = Utilities.getAppConfiguration(this).orientation;
         int numStackTasks = mRecentsView.getStack().getStackTaskCount();
         EventBus.getDefault().send(new ConfigurationChangedEvent(false /* fromMultiWindow */,
-                (mLastOrientation != newOrientation), numStackTasks > 0));
-        mLastOrientation = newOrientation;
+                (mLastDeviceOrientation != newDeviceOrientation), numStackTasks > 0));
+        mLastDeviceOrientation = newDeviceOrientation;
     }
 
     @Override
@@ -455,7 +454,7 @@
         int numStackTasks = stack.getStackTaskCount();
 
         EventBus.getDefault().send(new ConfigurationChangedEvent(true /* fromMultiWindow */,
-                false /* fromOrientationChange */, numStackTasks > 0));
+                false /* fromDeviceOrientationChange */, numStackTasks > 0));
 
         if (mRecentsView != null) {
             mRecentsView.updateStack(stack);
@@ -777,6 +776,8 @@
     @Override
     public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
         super.dump(prefix, fd, writer, args);
+        EventBus.getDefault().dump(prefix, writer);
+
         String id = Integer.toHexString(System.identityHashCode(this));
 
         writer.print(prefix); writer.print(TAG);
@@ -787,6 +788,5 @@
         if (mRecentsView != null) {
             mRecentsView.dump(prefix, writer);
         }
-        EventBus.getDefault().dump(prefix, writer);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 6d32293..c230cd8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -689,7 +689,7 @@
             TaskStackViewScroller stackScroller = stackView.getScroller();
 
             stackView.updateLayoutAlgorithm(true /* boundScroll */);
-            stackView.updateToInitialState(true /* scrollToInitialState */);
+            stackView.updateToInitialState();
 
             for (int i = tasks.size() - 1; i >= 0; i--) {
                 Task task = tasks.get(i);
@@ -742,7 +742,7 @@
 
         // Get the transform for the running task
         stackView.updateLayoutAlgorithm(true /* boundScroll */);
-        stackView.updateToInitialState(true /* scrollToInitialState */);
+        stackView.updateToInitialState();
         stackView.getStackAlgorithm().getStackTransformScreenCoordinates(launchTask,
                 stackView.getScroller().getStackScroll(), mTmpTransform, null);
         return mTmpTransform;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/ConfigurationChangedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ConfigurationChangedEvent.java
index e3bc2a7..53b67cf 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/ConfigurationChangedEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ConfigurationChangedEvent.java
@@ -24,13 +24,13 @@
 public class ConfigurationChangedEvent extends EventBus.AnimatedEvent {
 
     public final boolean fromMultiWindow;
-    public final boolean fromOrientationChange;
+    public final boolean fromDeviceOrientationChange;
     public final boolean hasStackTasks;
 
-    public ConfigurationChangedEvent(boolean fromMultiWindow, boolean fromOrientationChange,
+    public ConfigurationChangedEvent(boolean fromMultiWindow, boolean fromDeviceOrientationChange,
             boolean hasStackTasks) {
         this.fromMultiWindow = fromMultiWindow;
-        this.fromOrientationChange = fromOrientationChange;
+        this.fromDeviceOrientationChange = fromDeviceOrientationChange;
         this.hasStackTasks = hasStackTasks;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
index 4ecda54..f6cc12b 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
@@ -18,8 +18,11 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorSet;
+import android.animation.RectEvaluator;
 import android.annotation.FloatRange;
 import android.app.Activity;
+import android.content.Context;
+import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.Color;
 import android.graphics.Rect;
@@ -71,7 +74,7 @@
             };
 
     public static final RectFEvaluator RECTF_EVALUATOR = new RectFEvaluator();
-
+    public static final RectEvaluator RECT_EVALUATOR = new RectEvaluator(new Rect());
     public static final Rect EMPTY_RECT = new Rect();
 
     /**
@@ -270,6 +273,14 @@
     }
 
     /**
+     * Returns the application configuration, which is independent of the activity's current
+     * configuration in multiwindow.
+     */
+    public static Configuration getAppConfiguration(Context context) {
+        return context.getApplicationContext().getResources().getConfiguration();
+    }
+
+    /**
      * Returns a lightweight dump of a rect.
      */
     public static String dumpRect(Rect r) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
index fbb5987..95e276f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
@@ -299,7 +299,7 @@
                 if (bounds != null && !dockAreaOverlay.getBounds().equals(bounds)) {
                     if (animateBounds) {
                         PropertyValuesHolder prop = PropertyValuesHolder.ofObject(
-                                Utilities.DRAWABLE_RECT, new RectEvaluator(new Rect()),
+                                Utilities.DRAWABLE_RECT, Utilities.RECT_EVALUATOR,
                                 dockAreaOverlay.getBounds(), bounds);
                         animators.add(ObjectAnimator.ofPropertyValuesHolder(dockAreaOverlay, prop));
                     } else {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
index 60a85df..7378102 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
@@ -107,7 +107,9 @@
         public void onMoveToFullscreen() {
             // Recents should be dismissed when PIP moves to fullscreen. If not, Recents will
             // be unnecessarily shown in the scenario: PIP->Fullscreen->PIP.
-            dismissRecentsToLaunchTargetTaskOrHome();
+            // Do not show Recents close animation because PIP->Fullscreen animation will be shown
+            // instead.
+            dismissRecentsToLaunchTargetTaskOrHome(false);
         }
 
         @Override
@@ -118,7 +120,7 @@
             new PipRecentsOverlayManager.Callback() {
                 @Override
                 public void onClosed() {
-                    dismissRecentsToLaunchTargetTaskOrHome();
+                    dismissRecentsToLaunchTargetTaskOrHome(true);
                 }
 
                 @Override
@@ -211,13 +213,15 @@
         }
     }
 
-    boolean dismissRecentsToLaunchTargetTaskOrHome() {
+    boolean dismissRecentsToLaunchTargetTaskOrHome(boolean animate) {
         SystemServicesProxy ssp = Recents.getSystemServices();
         if (ssp.isRecentsTopMost(ssp.getTopMostTask(), null)) {
             // If we have a focused Task, launch that Task now
-            if (mRecentsView.launchPreviousTask()) return true;
+            if (mRecentsView.launchPreviousTask(animate)) {
+              return true;
+            }
             // If none of the other cases apply, then just go Home
-            dismissRecentsToHome(true /* animateTaskViews */);
+            dismissRecentsToHome(animate /* animateTaskViews */);
         }
         return false;
     }
@@ -247,7 +251,7 @@
         dismissEvent.addPostAnimationCallback(mFinishLaunchHomeRunnable);
         dismissEvent.addPostAnimationCallback(closeSystemWindows);
 
-        if(mTaskStackHorizontalGridView.getChildCount() > 0 && animateTaskViews) {
+        if (mTaskStackHorizontalGridView.getChildCount() > 0 && animateTaskViews) {
             mHomeRecentsEnterExitAnimationHolder.startExitAnimation(dismissEvent);
         } else {
             closeSystemWindows.run();
@@ -374,7 +378,7 @@
     public void onEnterAnimationComplete() {
         super.onEnterAnimationComplete();
         if(mLaunchedFromHome) {
-            mHomeRecentsEnterExitAnimationHolder.startEnterAnimation();
+            mHomeRecentsEnterExitAnimationHolder.startEnterAnimation(mPipManager.isPipShown());
         }
         EventBus.getDefault().send(new EnterRecentsWindowAnimationCompletedEvent());
     }
@@ -463,7 +467,7 @@
         if (launchState.launchedFromHome) {
             dismissRecentsToHome(true /* animateTaskViews */);
         } else {
-            dismissRecentsToLaunchTargetTaskOrHome();
+            dismissRecentsToLaunchTargetTaskOrHome(true);
         }
     }
 
@@ -561,6 +565,8 @@
             // as if it's the part of the Recents UI.
             mPipRecentsOverlayManager.requestFocus(
                     mTaskStackViewAdapter.getItemCount() > 0);
+        } else {
+            mPipRecentsOverlayManager.clearFocus();
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/animations/DismissAnimationsHolder.java b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/DismissAnimationsHolder.java
index ae8d800..66d8576 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/animations/DismissAnimationsHolder.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/DismissAnimationsHolder.java
@@ -29,7 +29,8 @@
     private LinearLayout mDismissArea;
     private LinearLayout mInfoField;
     private View mThumbnailView;
-    private int mCardYDelta;
+    private int mDismissEnterYDelta;
+    private int mDismissStartYDelta;
     private long mShortDuration;
     private long mLongDuration;
 
@@ -38,7 +39,8 @@
         mDismissArea = (LinearLayout) taskCardView.findViewById(R.id.card_dismiss);
         mThumbnailView = taskCardView.findViewById(R.id.card_view_thumbnail);
         Resources res = taskCardView.getResources();
-        mCardYDelta = res.getDimensionPixelOffset(R.dimen.recents_tv_dismiss_shift_down);
+        mDismissEnterYDelta = res.getDimensionPixelOffset(R.dimen.recents_tv_dismiss_shift_down);
+        mDismissStartYDelta = mDismissEnterYDelta * 2;
         mShortDuration =  res.getInteger(R.integer.dismiss_short_duration);
         mLongDuration =  res.getInteger(R.integer.dismiss_long_duration);
     }
@@ -52,13 +54,13 @@
         mInfoField.animate()
                 .setDuration(mShortDuration)
                 .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
-                .translationYBy(mCardYDelta)
+                .translationY(mDismissEnterYDelta)
                 .alpha(0.5f);
 
         mThumbnailView.animate()
                 .setDuration(mShortDuration)
                 .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
-                .translationYBy(mCardYDelta)
+                .translationY(mDismissEnterYDelta)
                 .alpha(0.5f);
     }
 
@@ -71,13 +73,13 @@
         mInfoField.animate()
                 .setDuration(mShortDuration)
                 .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
-                .translationYBy(-mCardYDelta)
+                .translationY(0)
                 .alpha(1.0f);
 
         mThumbnailView.animate()
                 .setDuration(mShortDuration)
                 .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
-                .translationYBy(-mCardYDelta)
+                .translationY(0)
                 .alpha(1.0f);
     }
 
@@ -90,14 +92,14 @@
         mInfoField.animate()
                 .setDuration(mLongDuration)
                 .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
-                .translationYBy(mCardYDelta)
+                .translationY(mDismissStartYDelta)
                 .alpha(0.0f)
                 .setListener(listener);
 
         mThumbnailView.animate()
                 .setDuration(mLongDuration)
                 .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
-                .translationYBy(mCardYDelta)
+                .translationY(mDismissStartYDelta)
                 .alpha(0.0f);
     }
 
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 497a0a3..92718a3 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
@@ -28,6 +28,7 @@
 
     private Context mContext;
     private TaskStackHorizontalGridView mGridView;
+    private float mDimAlpha;
     private long mDelay;
     private int mDuration;
     private int mTranslationX;
@@ -36,18 +37,19 @@
             TaskStackHorizontalGridView gridView) {
         mContext = context;
         mGridView = gridView;
+        mDimAlpha = mContext.getResources().getFloat(R.dimen.recents_recents_row_dim_alpha);
         mTranslationX = mContext.getResources()
                 .getDimensionPixelSize(R.dimen.recents_tv_home_recents_shift);
         mDelay = mContext.getResources().getInteger(R.integer.recents_home_delay);
         mDuration =  mContext.getResources().getInteger(R.integer.recents_home_duration);
     }
 
-    public void startEnterAnimation() {
+    public void startEnterAnimation(boolean isPipShown) {
         for(int i = 0; i < mGridView.getChildCount(); i++) {
             TaskCardView view = (TaskCardView) mGridView.getChildAt(i);
             view.setTranslationX(-mTranslationX);
             view.animate()
-                    .alpha(1.0f)
+                    .alpha(isPipShown ? mDimAlpha : 1.0f)
                     .translationX(0)
                     .setDuration(mDuration)
                     .setStartDelay(mDelay * i)
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/animations/RecentsRowFocusAnimationHolder.java b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/RecentsRowFocusAnimationHolder.java
index 28abc34..160835f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/animations/RecentsRowFocusAnimationHolder.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/RecentsRowFocusAnimationHolder.java
@@ -29,8 +29,6 @@
  * Recents row's focus animation with PIP controls.
  */
 public class RecentsRowFocusAnimationHolder {
-    private static final float DIM_ALPHA = 0.5f;
-
     private View mView;
     private View mTitleView;
 
@@ -43,6 +41,7 @@
 
         Resources res = view.getResources();
         int duration = res.getInteger(R.integer.recents_tv_pip_focus_anim_duration);
+        float dimAlpha = res.getFloat(R.dimen.recents_recents_row_dim_alpha);
 
         mFocusGainAnimatorSet = new AnimatorSet();
         mFocusGainAnimatorSet.playTogether(
@@ -53,7 +52,7 @@
 
         mFocusLoseAnimatorSet = new AnimatorSet();
         mFocusLoseAnimatorSet.playTogether(
-                ObjectAnimator.ofFloat(mView, "alpha", DIM_ALPHA),
+                ObjectAnimator.ofFloat(mView, "alpha", dimAlpha),
                 ObjectAnimator.ofFloat(mTitleView, "alpha", 0f));
         mFocusLoseAnimatorSet.setDuration(duration);
         mFocusLoseAnimatorSet.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvTransitionHelper.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvTransitionHelper.java
index 5b94ebe..812bff1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvTransitionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvTransitionHelper.java
@@ -121,11 +121,13 @@
         }
         try {
             Rect taskRect = taskView.getFocusedThumbnailRect();
-            Bitmap thumbnail = Bitmap.createScaledBitmap(task.thumbnail, taskRect.width(),
-                    taskRect.height(), false);
-            WindowManagerGlobal.getWindowManagerService()
-                    .overridePendingAppTransitionAspectScaledThumb(thumbnail, taskRect.left,
-                            taskRect.top, taskRect.width(), taskRect.height(), callback, true);
+            if (taskRect != null) {
+                Bitmap thumbnail = Bitmap.createScaledBitmap(task.thumbnail, taskRect.width(),
+                        taskRect.height(), false);
+                WindowManagerGlobal.getWindowManagerService()
+                        .overridePendingAppTransitionAspectScaledThumb(thumbnail, taskRect.left,
+                                taskRect.top, taskRect.width(), taskRect.height(), callback, true);
+            }
         } catch (RemoteException e) {
             Log.w(TAG, "Failed to override transition: " + e);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvView.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvView.java
index 594f6bc..4058c62 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvView.java
@@ -112,7 +112,7 @@
         if (mTaskStackHorizontalView != null) {
             Task task = mTaskStackHorizontalView.getFocusedTask();
             if (task != null) {
-                launchTaskFomRecents(task);
+                launchTaskFomRecents(task, true);
                 return true;
             }
         }
@@ -120,12 +120,12 @@
     }
 
     /** Launches the task that recents was launched from if possible */
-    public boolean launchPreviousTask() {
+    public boolean launchPreviousTask(boolean animate) {
         if (mTaskStackHorizontalView != null) {
             TaskStack stack = mTaskStackHorizontalView.getStack();
             Task task = stack.getLaunchTarget();
             if (task != null) {
-                launchTaskFomRecents(task);
+                launchTaskFomRecents(task, animate);
                 return true;
             }
         }
@@ -137,18 +137,25 @@
      * attempt to scroll to focus the task before launching.
      * @param task
      */
-    private void launchTaskFomRecents(final Task task) {
-        if(task != mTaskStackHorizontalView.getFocusedTask()) {
-            if(mScrollListener != null) {
+    private void launchTaskFomRecents(final Task task, boolean animate) {
+        if (!animate) {
+            SystemServicesProxy ssp = Recents.getSystemServices();
+            ssp.startActivityFromRecents(getContext(), task.key, task.title, null);
+            return;
+        }
+        mTaskStackHorizontalView.requestFocus();
+        Task focusedTask = mTaskStackHorizontalView.getFocusedTask();
+        if (focusedTask != null && task != focusedTask) {
+            if (mScrollListener != null) {
                 mTaskStackHorizontalView.removeOnScrollListener(mScrollListener);
             }
             mScrollListener = new OnScrollListener() {
                 @Override
                 public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                     super.onScrollStateChanged(recyclerView, newState);
-                    if(newState == RecyclerView.SCROLL_STATE_IDLE) {
+                    if (newState == RecyclerView.SCROLL_STATE_IDLE) {
                         TaskCardView cardView = mTaskStackHorizontalView.getChildViewForTask(task);
-                        if(cardView != null) {
+                        if (cardView != null) {
                             mTransitionHelper.launchTaskFromRecents(mStack, task,
                                     mTaskStackHorizontalView, cardView, null, INVALID_STACK_ID);
                         } else {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/FixedSizeFrameLayout.java b/packages/SystemUI/src/com/android/systemui/recents/views/FixedSizeFrameLayout.java
index 9f2b00a..471df6a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/FixedSizeFrameLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/FixedSizeFrameLayout.java
@@ -88,6 +88,10 @@
      */
     protected void layoutContents(Rect bounds, boolean changed) {
         super.onLayout(changed, bounds.left, bounds.top, bounds.right, bounds.bottom);
+
+        int width = getMeasuredWidth();
+        int height = getMeasuredHeight();
+        onSizeChanged(width, height, width, height);
     }
 
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index 86d68c2..d55c7d8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -519,7 +519,9 @@
                 @Override
                 public void onAnimationStarted() {
                     EventBus.getDefault().send(new DockedFirstAnimationFrameEvent());
-                    mTaskStackView.getStack().removeTask(event.task, AnimationProps.IMMEDIATE,
+                    // Remove the task and don't bother relaying out, as all the tasks will be
+                    // relaid out when the stack changes on the multiwindow change event
+                    mTaskStackView.getStack().removeTask(event.task, null,
                             true /* fromDockGesture */);
                 }
             };
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
index e4da8b3..34d6bce 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
@@ -297,9 +297,6 @@
     private FreePathInterpolator mUnfocusedDimCurveInterpolator;
     private FreePathInterpolator mFocusedDimCurveInterpolator;
 
-    // Indexed from the front of the stack, the normalized x in the unfocused range for each task
-    private float[] mInitialNormX;
-
     // The state of the stack focus (0..1), which controls the transition of the stack from the
     // focused to non-focused state
     @ViewDebug.ExportedProperty(category="recents")
@@ -406,8 +403,10 @@
     /**
      * Sets the system insets.
      */
-    public void setSystemInsets(Rect systemInsets) {
+    public boolean setSystemInsets(Rect systemInsets) {
+        boolean changed = mSystemInsets.equals(systemInsets);
         mSystemInsets.set(systemInsets);
+        return changed;
     }
 
     /**
@@ -545,13 +544,11 @@
             } else {
                 mInitialScrollP = Utilities.clamp(launchTaskIndex - 1, mMinScrollP, mMaxScrollP);
             }
-            mInitialNormX = null;
         } else if (!ssp.hasFreeformWorkspaceSupport() && mNumStackTasks == 1) {
             // If there is one stack task, ignore the min/max/initial scroll positions
             mMinScrollP = 0;
             mMaxScrollP = 0;
             mInitialScrollP = 0;
-            mInitialNormX = null;
         } else {
             // Set the max scroll to be the point where the front most task is visible with the
             // stack bottom offset
@@ -565,42 +562,50 @@
                     launchState.launchedViaDockGesture;
             if (launchState.launchedWithAltTab) {
                 mInitialScrollP = Utilities.clamp(launchTaskIndex, mMinScrollP, mMaxScrollP);
-                mInitialNormX = null;
             } else if (scrollToFront) {
                 mInitialScrollP = Utilities.clamp(launchTaskIndex, mMinScrollP, mMaxScrollP);
-                mInitialNormX = null;
             } else {
                 // We are overriding the initial two task positions, so set the initial scroll
                 // position to match the second task (aka focused task) position
                 float initialTopNormX = getNormalizedXFromUnfocusedY(mInitialTopOffset, FROM_TOP);
                 mInitialScrollP = Math.max(mMinScrollP, Math.min(mMaxScrollP, (mNumStackTasks - 2))
                         - Math.max(0, mUnfocusedRange.getAbsoluteX(initialTopNormX)));
-
-                // Set the initial scroll to the predefined state (which differs from the stack)
-                mInitialNormX = new float[] {
-                        getNormalizedXFromUnfocusedY(mSystemInsets.bottom + mInitialBottomOffset,
-                                FROM_BOTTOM),
-                        initialTopNormX
-                };
             }
         }
     }
 
-    public void updateToInitialState(List<Task> tasks) {
-        if (mInitialNormX == null) {
-            return;
-        }
+    /**
+     * Creates task overrides to ensure the initial stack layout if necessary.
+     */
+    public void setTaskOverridesForInitialState(TaskStack stack) {
+        RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
 
-        mUnfocusedRange.offset(0f);
-        int taskCount = tasks.size();
-        for (int i = taskCount - 1; i >= 0; i--) {
-            int indexFromFront = taskCount - i - 1;
-            if (indexFromFront >= mInitialNormX.length) {
-                break;
+        mTaskIndexOverrideMap.clear();
+
+        boolean scrollToFront = launchState.launchedFromHome ||
+                launchState.launchedViaDockGesture;
+        if (getInitialFocusState() == STATE_UNFOCUSED && mNumStackTasks > 1) {
+            if (!launchState.launchedWithAltTab && !scrollToFront) {
+                // Set the initial scroll to the predefined state (which differs from the stack)
+                float [] initialNormX = new float[] {
+                        getNormalizedXFromUnfocusedY(mSystemInsets.bottom + mInitialBottomOffset,
+                                FROM_BOTTOM),
+                        getNormalizedXFromUnfocusedY(mInitialTopOffset, FROM_TOP)
+                };
+
+                mUnfocusedRange.offset(0f);
+                List<Task> tasks = stack.getStackTasks();
+                int taskCount = tasks.size();
+                for (int i = taskCount - 1; i >= 0; i--) {
+                    int indexFromFront = taskCount - i - 1;
+                    if (indexFromFront >= initialNormX.length) {
+                        break;
+                    }
+                    float newTaskProgress = mInitialScrollP +
+                            mUnfocusedRange.getAbsoluteX(initialNormX[indexFromFront]);
+                    mTaskIndexOverrideMap.put(tasks.get(i).key.id, newTaskProgress);
+                }
             }
-            float newTaskProgress = mInitialScrollP +
-                    mUnfocusedRange.getAbsoluteX(mInitialNormX[indexFromFront]);
-            mTaskIndexOverrideMap.put(tasks.get(i).key.id, newTaskProgress);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index 63018c5..a75d1e1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -28,11 +28,9 @@
 import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.graphics.Rect;
-import android.graphics.RectF;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.GradientDrawable;
 import android.os.Bundle;
-import android.os.Parcelable;
 import android.provider.Settings;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -105,12 +103,6 @@
 
     private static final String TAG = "TaskStackView";
 
-    private final static String KEY_SAVED_STATE_SUPER = "saved_instance_state_super";
-    private final static String KEY_SAVED_STATE_LAYOUT_FOCUSED_STATE =
-            "saved_instance_state_layout_focused_state";
-    private final static String KEY_SAVED_STATE_LAYOUT_STACK_SCROLL =
-            "saved_instance_state_layout_stack_scroll";
-
     // The thresholds at which to show/hide the stack action button.
     private static final float SHOW_STACK_ACTION_BUTTON_SCROLL_THRESHOLD = 0.3f;
     private static final float HIDE_STACK_ACTION_BUTTON_SCROLL_THRESHOLD = 0.3f;
@@ -350,11 +342,9 @@
     /**
      * Updates this TaskStackView to the initial state.
      */
-    public void updateToInitialState(boolean scrollToInitialState) {
-        if (scrollToInitialState) {
-            mStackScroller.setStackScrollToInitialState();
-            mLayoutAlgorithm.updateToInitialState(mStack.getStackTasks());
-        }
+    public void updateToInitialState() {
+        mStackScroller.setStackScrollToInitialState();
+        mLayoutAlgorithm.setTaskOverridesForInitialState(mStack);
     }
 
     /** Updates the list of task views */
@@ -638,18 +628,11 @@
     /**
      * @see #relayoutTaskViews(AnimationProps, ArraySet<Task.TaskKey>, boolean)
      */
-    void relayoutTaskViews(AnimationProps animation) {
+    public void relayoutTaskViews(AnimationProps animation) {
         relayoutTaskViews(animation, mIgnoreTasks, false /* ignoreTaskOverrides */);
     }
 
     /**
-     * @see #relayoutTaskViews(AnimationProps, ArraySet<Task.TaskKey>, boolean)
-     */
-    void relayoutTaskViews(AnimationProps animation, ArraySet<Task.TaskKey> ignoreTasksSet) {
-        relayoutTaskViews(animation, ignoreTasksSet, false /* ignoreTaskOverrides */);
-    }
-
-    /**
      * Relayout the the visible {@link TaskView}s to their current transforms as specified by the
      * {@link TaskStackLayoutAlgorithm} with the given {@param animation}. This call cancels any
      * animations that are current running on those task views, and will ensure that the children
@@ -657,7 +640,7 @@
      *
      * @param ignoreTasksSet the set of tasks to ignore in the relayout
      */
-    void relayoutTaskViews(AnimationProps animation, ArraySet<Task.TaskKey> ignoreTasksSet,
+    private void relayoutTaskViews(AnimationProps animation, ArraySet<Task.TaskKey> ignoreTasksSet,
             boolean ignoreTaskOverrides) {
         // If we had a deferred animation, cancel that
         mDeferredTaskViewLayoutAnimation = null;
@@ -841,7 +824,7 @@
      *
      * @param ignoreTasksSet the set of tasks to ignore in the relayout
      */
-    public void updateLayoutAlgorithm(boolean boundScrollToNewMinMax,
+    private void updateLayoutAlgorithm(boolean boundScrollToNewMinMax,
             ArraySet<Task.TaskKey> ignoreTasksSet) {
         // Compute the min and max scroll values
         mLayoutAlgorithm.update(mStack, ignoreTasksSet);
@@ -1098,24 +1081,6 @@
     }
 
     @Override
-    protected Parcelable onSaveInstanceState() {
-        Bundle savedState = new Bundle();
-        savedState.putParcelable(KEY_SAVED_STATE_SUPER, super.onSaveInstanceState());
-        savedState.putInt(KEY_SAVED_STATE_LAYOUT_FOCUSED_STATE, mLayoutAlgorithm.getFocusState());
-        savedState.putFloat(KEY_SAVED_STATE_LAYOUT_STACK_SCROLL, mStackScroller.getStackScroll());
-        return super.onSaveInstanceState();
-    }
-
-    @Override
-    protected void onRestoreInstanceState(Parcelable state) {
-        Bundle savedState = (Bundle) state;
-        super.onRestoreInstanceState(savedState.getParcelable(KEY_SAVED_STATE_SUPER));
-
-        mLayoutAlgorithm.setFocusState(savedState.getInt(KEY_SAVED_STATE_LAYOUT_FOCUSED_STATE));
-        mStackScroller.setStackScroll(savedState.getFloat(KEY_SAVED_STATE_LAYOUT_STACK_SCROLL));
-    }
-
-    @Override
     public CharSequence getAccessibilityClassName() {
         return TaskStackView.class.getName();
     }
@@ -1181,9 +1146,10 @@
      * Updates the system insets.
      */
     public void setSystemInsets(Rect systemInsets) {
-        if (!systemInsets.equals(mLayoutAlgorithm.mSystemInsets)) {
-            mStableLayoutAlgorithm.setSystemInsets(systemInsets);
-            mLayoutAlgorithm.setSystemInsets(systemInsets);
+        boolean changed = false;
+        changed |= mStableLayoutAlgorithm.setSystemInsets(systemInsets);
+        changed |= mLayoutAlgorithm.setSystemInsets(systemInsets);
+        if (changed) {
             requestLayout();
         }
     }
@@ -1215,12 +1181,14 @@
                 TaskStackLayoutAlgorithm.StackState.getStackStateForStack(mStack));
         mLayoutAlgorithm.initialize(mWindowRect, mStackBounds,
                 TaskStackLayoutAlgorithm.StackState.getStackStateForStack(mStack));
-        updateLayoutAlgorithm(false /* boundScroll */, mIgnoreTasks);
+        updateLayoutAlgorithm(false /* boundScroll */);
 
         // If this is the first layout, then scroll to the front of the stack, then update the
         // TaskViews with the stack so that we can lay them out
         if (mAwaitingFirstLayout || mInitialState != INITIAL_STATE_UPDATE_NONE) {
-            updateToInitialState(mInitialState != INITIAL_STATE_UPDATE_LAYOUT_ONLY);
+            if (mInitialState != INITIAL_STATE_UPDATE_LAYOUT_ONLY) {
+                updateToInitialState();
+            }
             if (!mAwaitingFirstLayout) {
                 mInitialState = INITIAL_STATE_UPDATE_NONE;
             }
@@ -1247,16 +1215,16 @@
      * Measures a TaskView.
      */
     private void measureTaskView(TaskView tv) {
+        Rect padding = new Rect();
         if (tv.getBackground() != null) {
-            tv.getBackground().getPadding(mTmpRect);
-        } else {
-            mTmpRect.setEmpty();
+            tv.getBackground().getPadding(padding);
         }
-        Rect taskRect = mStableLayoutAlgorithm.mTaskRect;
+        mTmpRect.set(mStableLayoutAlgorithm.mTaskRect);
+        mTmpRect.union(mLayoutAlgorithm.mTaskRect);
         tv.measure(
-                MeasureSpec.makeMeasureSpec(taskRect.width() + mTmpRect.left + mTmpRect.right,
+                MeasureSpec.makeMeasureSpec(mTmpRect.width() + padding.left + padding.right,
                         MeasureSpec.EXACTLY),
-                MeasureSpec.makeMeasureSpec(taskRect.height() + mTmpRect.top + mTmpRect.bottom,
+                MeasureSpec.makeMeasureSpec(mTmpRect.height() + padding.top + padding.bottom,
                         MeasureSpec.EXACTLY));
     }
 
@@ -1278,7 +1246,7 @@
         }
 
         // Relayout all of the task views including the ignored ones
-        relayoutTaskViews(AnimationProps.IMMEDIATE, mIgnoreTasks);
+        relayoutTaskViews(AnimationProps.IMMEDIATE);
         clipTaskViews();
 
         if (mAwaitingFirstLayout || !mEnterAnimationComplete) {
@@ -1293,15 +1261,15 @@
      */
     private void layoutTaskView(boolean changed, TaskView tv) {
         if (changed) {
+            Rect padding = new Rect();
             if (tv.getBackground() != null) {
-                tv.getBackground().getPadding(mTmpRect);
-            } else {
-                mTmpRect.setEmpty();
+                tv.getBackground().getPadding(padding);
             }
-            Rect taskRect = mStableLayoutAlgorithm.mTaskRect;
+            mTmpRect.set(mStableLayoutAlgorithm.mTaskRect);
+            mTmpRect.union(mLayoutAlgorithm.mTaskRect);
             tv.cancelTransformAnimation();
-            tv.layout(taskRect.left - mTmpRect.left, taskRect.top - mTmpRect.top,
-                    taskRect.right + mTmpRect.right, taskRect.bottom + mTmpRect.bottom);
+            tv.layout(mTmpRect.left - padding.left, mTmpRect.top - padding.top,
+                    mTmpRect.right + padding.right, mTmpRect.bottom + padding.bottom);
         } else {
             // If the layout has not changed, then just lay it out again in-place
             tv.layout(tv.getLeft(), tv.getTop(), tv.getRight(), tv.getBottom());
@@ -1847,7 +1815,7 @@
             height -= systemInsets.bottom;
             systemInsets.bottom = 0;
             mStackBounds.set(dockState.getDockedTaskStackBounds(getMeasuredWidth(),
-                    height, mDividerSize, mLayoutAlgorithm.mSystemInsets,
+                    height, mDividerSize, systemInsets,
                     mLayoutAlgorithm, getResources(), mWindowRect));
             mLayoutAlgorithm.setSystemInsets(systemInsets);
             mLayoutAlgorithm.initialize(mWindowRect, mStackBounds,
@@ -1982,17 +1950,24 @@
 
     public final void onBusEvent(MultiWindowStateChangedEvent event) {
         if (!event.inMultiWindow) {
-            // Scroll the stack to the front to see the undocked task
-            mStackScroller.animateScroll(mLayoutAlgorithm.mMaxScrollP, new Runnable() {
+            // Defer until the next frame to ensure that we have received all the system insets, and
+            // initial layout updates
+            post(new Runnable() {
                 @Override
                 public void run() {
-                    List<TaskView> taskViews = getTaskViews();
-                    int taskViewCount = taskViews.size();
-                    for (int i = 0; i < taskViewCount; i++) {
-                        TaskView tv = taskViews.get(i);
-                        tv.getHeaderView().rebindToTask(tv.getTask(), tv.mTouchExplorationEnabled,
-                                tv.mIsDisabledInSafeMode);
-                    }
+                    // Scroll the stack to the front to see the undocked task
+                    mStackScroller.animateScroll(mLayoutAlgorithm.mMaxScrollP, new Runnable() {
+                        @Override
+                        public void run() {
+                            List<TaskView> taskViews = getTaskViews();
+                            int taskViewCount = taskViews.size();
+                            for (int i = 0; i < taskViewCount; i++) {
+                                TaskView tv = taskViews.get(i);
+                                tv.getHeaderView().rebindToTask(tv.getTask(),
+                                        tv.mTouchExplorationEnabled, tv.mIsDisabledInSafeMode);
+                            }
+                        }
+                    });
                 }
             });
         }
@@ -2013,9 +1988,12 @@
         }
 
         // Trigger a new layout and update to the initial state if necessary
-        if (event.fromMultiWindow || event.fromOrientationChange) {
+        if (event.fromMultiWindow) {
             mInitialState = INITIAL_STATE_UPDATE_LAYOUT_ONLY;
             requestLayout();
+        } else if (event.fromDeviceOrientationChange) {
+            mInitialState = INITIAL_STATE_UPDATE_ALL;
+            requestLayout();
         }
     }
 
@@ -2110,7 +2088,7 @@
         if (mFocusedTask != null) {
             writer.print(innerPrefix);
             writer.print("Focused task: ");
-            mFocusedTask.dump(innerPrefix, writer);
+            mFocusedTask.dump("", writer);
         }
 
         mLayoutAlgorithm.dump(innerPrefix, writer);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index 6be8a4a..37f5a9f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -152,7 +152,6 @@
     private final TaskViewTransform mTargetAnimationTransform = new TaskViewTransform();
     private ArrayList<Animator> mTmpAnimators = new ArrayList<>();
 
-    View mContent;
     @ViewDebug.ExportedProperty(deepExport=true, prefix="thumbnail_")
     TaskViewThumbnail mThumbnailView;
     @ViewDebug.ExportedProperty(deepExport=true, prefix="header_")
@@ -226,9 +225,9 @@
     @Override
     protected void onFinishInflate() {
         // Bind the views
-        mContent = findViewById(R.id.task_view_content);
         mHeaderView = (TaskViewHeader) findViewById(R.id.task_view_bar);
         mThumbnailView = (TaskViewThumbnail) findViewById(R.id.task_view_thumbnail);
+        mThumbnailView.updateClipToTaskBar(mHeaderView);
         mActionButtonView = findViewById(R.id.lock_to_app_fab);
         mActionButtonView.setOutlineProvider(new ViewOutlineProvider() {
             @Override
@@ -255,6 +254,9 @@
         if (w > 0 && h > 0) {
             mHeaderView.onTaskViewSizeChanged(w, h);
             mThumbnailView.onTaskViewSizeChanged(w, h);
+
+            mActionButtonView.setTranslationX(w - getMeasuredWidth());
+            mActionButtonView.setTranslationY(h - getMeasuredHeight());
         }
     }
 
@@ -276,13 +278,11 @@
     protected void measureContents(int width, int height) {
         int widthWithoutPadding = width - mPaddingLeft - mPaddingRight;
         int heightWithoutPadding = height - mPaddingTop - mPaddingBottom;
+        int widthSpec = MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.EXACTLY);
+        int heightSpec = MeasureSpec.makeMeasureSpec(heightWithoutPadding, MeasureSpec.EXACTLY);
 
         // Measure the content
-        mContent.measure(MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.EXACTLY),
-                MeasureSpec.makeMeasureSpec(heightWithoutPadding, MeasureSpec.EXACTLY));
-
-        // Optimization: Prevent overdraw of the thumbnail under the header view
-        mThumbnailView.updateClipToTaskBar(mHeaderView);
+        measureChildren(widthSpec, heightSpec);
 
         setMeasuredDimension(width, height);
     }
@@ -346,6 +346,8 @@
         mActionButtonView.setScaleX(1f);
         mActionButtonView.setScaleY(1f);
         mActionButtonView.setAlpha(0f);
+        mActionButtonView.setTranslationX(0f);
+        mActionButtonView.setTranslationY(0f);
         mActionButtonView.setTranslationZ(mActionButtonTranslationZ);
         if (mIncompatibleAppToastView != null) {
             mIncompatibleAppToastView.setVisibility(View.INVISIBLE);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
index f98d3d5..fb0fc30 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -350,6 +350,8 @@
         }
         mDismissButton.setVisibility(showDismissIcon ? View.VISIBLE : View.INVISIBLE);
         mDismissButton.setTranslationX(rightInset);
+
+        setLeftTopRightBottom(0, 0, width, getMeasuredHeight());
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
index 62fd585..4de7713 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
@@ -123,6 +123,7 @@
         }
 
         mTaskViewRect.set(0, 0, width, height);
+        setLeftTopRightBottom(0, 0, width, height);
         updateThumbnailScale();
     }
 
@@ -148,22 +149,26 @@
         int thumbnailHeight = Math.min(viewHeight,
                 (int) (mThumbnailRect.height() * mThumbnailScale));
         if (mBitmapShader != null && thumbnailWidth > 0 && thumbnailHeight > 0) {
+            int topOffset = mTaskBar != null
+                    ? mTaskBar.getHeight() - mCornerRadius
+                    : 0;
+
             // Draw the background, there will be some small overdraw with the thumbnail
             if (thumbnailWidth < viewWidth) {
                 // Portrait thumbnail on a landscape task view
-                canvas.drawRoundRect(Math.max(0, thumbnailWidth - mCornerRadius), 0,
+                canvas.drawRoundRect(Math.max(0, thumbnailWidth - mCornerRadius), topOffset,
                         viewWidth, viewHeight,
                         mCornerRadius, mCornerRadius, mBgFillPaint);
             }
             if (thumbnailHeight < viewHeight) {
                 // Landscape thumbnail on a portrait task view
-                canvas.drawRoundRect(0, Math.max(0, thumbnailHeight - mCornerRadius),
+                canvas.drawRoundRect(0, Math.max(topOffset, thumbnailHeight - mCornerRadius),
                         viewWidth, viewHeight,
                         mCornerRadius, mCornerRadius, mBgFillPaint);
             }
 
             // Draw the thumbnail
-            canvas.drawRoundRect(0, 0, thumbnailWidth, thumbnailHeight,
+            canvas.drawRoundRect(0, topOffset, thumbnailWidth, thumbnailHeight,
                     mCornerRadius, mCornerRadius, mDrawPaint);
         } else {
             canvas.drawRoundRect(0, 0, viewWidth, viewHeight, mCornerRadius, mCornerRadius,
@@ -274,10 +279,7 @@
     /** Updates the clip rect based on the given task bar. */
     void updateClipToTaskBar(View taskBar) {
         mTaskBar = taskBar;
-        int top = (int) Math.max(0, taskBar.getTranslationY() +
-                taskBar.getMeasuredHeight() - 1);
-        mClipRect.set(0, top, getMeasuredWidth(), getMeasuredHeight());
-        setClipBounds(mClipRect);
+        invalidate();
     }
 
     /** Updates the visibility of the the thumbnail. */
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
index b512393..397f24e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
@@ -19,11 +19,14 @@
 import android.animation.Animator;
 import android.animation.ObjectAnimator;
 import android.animation.PropertyValuesHolder;
+import android.graphics.Rect;
 import android.graphics.RectF;
 import android.util.IntProperty;
 import android.util.Property;
 import android.view.View;
 
+import com.android.systemui.recents.misc.Utilities;
+
 import java.util.ArrayList;
 
 /**
@@ -31,55 +34,20 @@
  */
 public class TaskViewTransform {
 
-    public static final Property<View, Integer> LEFT =
-            new IntProperty<View>("left") {
+    public static final Property<View, Rect> LTRB =
+            new Property<View, Rect>(Rect.class, "leftTopRightBottom") {
+
+                private Rect mTmpRect = new Rect();
+
                 @Override
-                public void setValue(View object, int v) {
-                    object.setLeft(v);
+                public void set(View v, Rect ltrb) {
+                    v.setLeftTopRightBottom(ltrb.left, ltrb.top, ltrb.right, ltrb.bottom);
                 }
 
                 @Override
-                public Integer get(View object) {
-                    return object.getLeft();
-                }
-            };
-
-    public static final Property<View, Integer> TOP =
-            new IntProperty<View>("top") {
-                @Override
-                public void setValue(View object, int v) {
-                    object.setTop(v);
-                }
-
-                @Override
-                public Integer get(View object) {
-                    return object.getTop();
-                }
-            };
-
-    public static final Property<View, Integer> RIGHT =
-            new IntProperty<View>("right") {
-                @Override
-                public void setValue(View object, int v) {
-                    object.setRight(v);
-                }
-
-                @Override
-                public Integer get(View object) {
-                    return object.getRight();
-                }
-            };
-
-    public static final Property<View, Integer> BOTTOM =
-            new IntProperty<View>("bottom") {
-                @Override
-                public void setValue(View object, int v) {
-                    object.setBottom(v);
-                }
-
-                @Override
-                public Integer get(View object) {
-                    return object.getBottom();
+                public Rect get(View v) {
+                    mTmpRect.set(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
+                    return mTmpRect;
                 }
             };
 
@@ -205,11 +173,12 @@
                 animators.add(animation.apply(AnimationProps.ALPHA, anim));
             }
             if (hasRectChangedFrom(v)) {
+                Rect fromViewRect = new Rect(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
+                Rect toViewRect = new Rect();
+                rect.round(toViewRect);
                 ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(v,
-                        PropertyValuesHolder.ofInt(LEFT, v.getLeft(), (int) rect.left),
-                        PropertyValuesHolder.ofInt(TOP, v.getTop(), (int) rect.top),
-                        PropertyValuesHolder.ofInt(RIGHT, v.getRight(), (int) rect.right),
-                        PropertyValuesHolder.ofInt(BOTTOM, v.getBottom(), (int) rect.bottom));
+                        PropertyValuesHolder.ofObject(LTRB, Utilities.RECT_EVALUATOR,
+                                fromViewRect, toViewRect));
                 animators.add(animation.apply(AnimationProps.BOUNDS, anim));
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 581b611..d7fa567 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -372,7 +372,10 @@
         mDisabledFlags = disabledFlags;
 
         final boolean disableHome = ((disabledFlags & View.STATUS_BAR_DISABLE_HOME) != 0);
-        boolean disableRecent = ((disabledFlags & View.STATUS_BAR_DISABLE_RECENT) != 0);
+
+        // Disable recents always in car mode.
+        boolean disableRecent = (
+                mCarMode || (disabledFlags & View.STATUS_BAR_DISABLE_RECENT) != 0);
         final boolean disableBack = ((disabledFlags & View.STATUS_BAR_DISABLE_BACK) != 0)
                 && ((mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) == 0);
         final boolean disableSearch = ((disabledFlags & View.STATUS_BAR_DISABLE_SEARCH) != 0);
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
index a445e77..5febb9b 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
@@ -35,6 +35,7 @@
 import android.os.Handler;
 import android.os.RemoteException;
 import android.os.SystemProperties;
+import android.text.TextUtils;
 import android.util.Log;
 import android.util.Pair;
 
@@ -144,6 +145,7 @@
     private ComponentName mPipComponentName;
     private MediaController mPipMediaController;
     private boolean mOnboardingShown;
+    private String[] mLastPackagesResourceGranted;
 
     private final Runnable mResizePinnedStackRunnable = new Runnable() {
         @Override
@@ -166,7 +168,7 @@
                 String[] packageNames = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
                 int resourceType = intent.getIntExtra(Intent.EXTRA_MEDIA_RESOURCE_TYPE,
                         INVALID_RESOURCE_TYPE);
-                if (mState != STATE_NO_PIP && packageNames != null && packageNames.length > 0
+                if (packageNames != null && packageNames.length > 0
                         && resourceType == Intent.EXTRA_MEDIA_RESOURCE_TYPE_VIDEO_CODEC) {
                     handleMediaResourceGranted(packageNames);
                 }
@@ -446,41 +448,24 @@
     }
 
     private void handleMediaResourceGranted(String[] packageNames) {
-        StackInfo fullscreenStack = null;
-        try {
-            fullscreenStack = mActivityManager.getStackInfo(FULLSCREEN_WORKSPACE_STACK_ID);
-        } catch (RemoteException e) {
-            Log.e(TAG, "getStackInfo failed", e);
-        }
-        if (fullscreenStack == null) {
-            return;
-        }
-        int fullscreenTopTaskId = fullscreenStack.taskIds[fullscreenStack.taskIds.length - 1];
-        List<RunningTaskInfo> tasks = null;
-        try {
-            tasks = mActivityManager.getTasks(MAX_RUNNING_TASKS_COUNT, 0);
-        } catch (RemoteException e) {
-            Log.e(TAG, "getTasks failed", e);
-        }
-        if (tasks == null) {
-            return;
-        }
-        boolean wasGrantedInFullscreen = false;
-        boolean wasGrantedInPip = false;
-        for (int i = tasks.size() - 1; i >= 0; --i) {
-            RunningTaskInfo task = tasks.get(i);
-            for (int j = packageNames.length - 1; j >= 0; --j) {
-                if (task.topActivity.getPackageName().equals(packageNames[j])) {
-                    if (task.id == fullscreenTopTaskId) {
-                        wasGrantedInFullscreen = true;
-                    } else if (task.id == mPipTaskId) {
-                        wasGrantedInPip= true;
+        if (mState == STATE_NO_PIP) {
+            mLastPackagesResourceGranted = packageNames;
+        } else {
+            boolean requestedFromLastPackages = false;
+            if (mLastPackagesResourceGranted != null) {
+                for (String packageName : mLastPackagesResourceGranted) {
+                    for (String newPackageName : packageNames) {
+                        if (TextUtils.equals(newPackageName, packageName)) {
+                            requestedFromLastPackages = true;
+                            break;
+                        }
                     }
                 }
             }
-        }
-        if (wasGrantedInFullscreen && !wasGrantedInPip) {
-            closePip();
+            mLastPackagesResourceGranted = packageNames;
+            if (!requestedFromLastPackages) {
+                closePip();
+            }
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsOverlayManager.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsOverlayManager.java
index 8567625..d75561b 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsOverlayManager.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsOverlayManager.java
@@ -150,10 +150,14 @@
      * is focused.
      * This should be called only by {@link com.android.systemui.recents.tv.RecentsTvActivity}.
      */
-    private void clearFocus() {
+    public void clearFocus() {
         if (!mIsRecentsShown || !mIsPipFocusedInRecent) {
             return;
         }
+        if (!mRecentsView.hasFocus()) {
+            // Let mRecentsView's focus listener handle clearFocus().
+            mRecentsView.requestFocus();
+        }
         mIsPipFocusedInRecent = false;
         mPipManager.resizePinnedStack(STATE_PIP_RECENTS);
         mWindowManager.updateViewLayout(mOverlayView, mPipRecentsControlsViewLayoutParams);
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index 4198af9..be53cfc 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -65,10 +65,14 @@
     // Which native processes to dump into dropbox's stack traces
     public static final String[] NATIVE_STACKS_OF_INTEREST = new String[] {
         "/system/bin/audioserver",
+        "/system/bin/cameraserver",
+        "/system/bin/drmserver",
+        "/system/bin/mediadrmserver",
         "/system/bin/mediaserver",
         "/system/bin/sdcard",
         "/system/bin/surfaceflinger",
-        "media.log"
+        "media.codec",     // system/bin/mediacodec
+        "media.extractor", // system/bin/mediaextractor
     };
 
     static Watchdog sWatchdog;
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 04a63a1..9703d13 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -628,13 +628,16 @@
         public Bundle result = null;
         public AssistStructure structure = null;
         public AssistContent content = null;
+        public Bundle receiverExtras;
+
         public PendingAssistExtras(ActivityRecord _activity, Bundle _extras, Intent _intent,
-                String _hint, IResultReceiver _receiver, int _userHandle) {
+                String _hint, IResultReceiver _receiver, Bundle _receiverExtras, int _userHandle) {
             activity = _activity;
             extras = _extras;
             intent = _intent;
             hint = _hint;
             receiver = _receiver;
+            receiverExtras = _receiverExtras;
             userHandle = _userHandle;
         }
         @Override
@@ -11806,7 +11809,7 @@
     @Override
     public Bundle getAssistContextExtras(int requestType) {
         PendingAssistExtras pae = enqueueAssistContext(requestType, null, null, null,
-                null, UserHandle.getCallingUserId(), null, PENDING_ASSIST_EXTRAS_TIMEOUT);
+                null, null, true, UserHandle.getCallingUserId(), null, PENDING_ASSIST_EXTRAS_TIMEOUT);
         if (pae == null) {
             return null;
         }
@@ -11870,14 +11873,17 @@
 
     @Override
     public boolean requestAssistContextExtras(int requestType, IResultReceiver receiver,
-            IBinder activityToken) {
-        return enqueueAssistContext(requestType, null, null, receiver, activityToken,
-                UserHandle.getCallingUserId(), null, PENDING_ASSIST_EXTRAS_LONG_TIMEOUT) != null;
+            Bundle receiverExtras,
+            IBinder activityToken, boolean focused) {
+        return enqueueAssistContext(requestType, null, null, receiver, receiverExtras,
+                activityToken, focused,
+                UserHandle.getCallingUserId(), null, PENDING_ASSIST_EXTRAS_LONG_TIMEOUT)
+                != null;
     }
 
     private PendingAssistExtras enqueueAssistContext(int requestType, Intent intent, String hint,
-            IResultReceiver receiver, IBinder activityToken, int userHandle, Bundle args,
-            long timeout) {
+            IResultReceiver receiver, Bundle receiverExtras, IBinder activityToken, boolean focused,
+            int userHandle, Bundle args, long timeout) {
         enforceCallingPermission(android.Manifest.permission.GET_TOP_ACTIVITY_INFO,
                 "enqueueAssistContext()");
         synchronized (this) {
@@ -11890,14 +11896,24 @@
                 Slog.w(TAG, "getAssistContextExtras failed: no process for " + activity);
                 return null;
             }
-            if (activityToken != null) {
-                ActivityRecord caller = ActivityRecord.forTokenLocked(activityToken);
-                if (activity != caller) {
-                    Slog.w(TAG, "enqueueAssistContext failed: caller " + caller
-                            + " is not current top " + activity);
+            if (focused) {
+                if (activityToken != null) {
+                    ActivityRecord caller = ActivityRecord.forTokenLocked(activityToken);
+                    if (activity != caller) {
+                        Slog.w(TAG, "enqueueAssistContext failed: caller " + caller
+                                + " is not current top " + activity);
+                        return null;
+                    }
+                }
+            } else {
+                activity = ActivityRecord.forTokenLocked(activityToken);
+                if (activity == null) {
+                    Slog.w(TAG, "enqueueAssistContext failed: activity for token=" + activityToken
+                            + " couldn't be found");
                     return null;
                 }
             }
+
             PendingAssistExtras pae;
             Bundle extras = new Bundle();
             if (args != null) {
@@ -11905,7 +11921,8 @@
             }
             extras.putString(Intent.EXTRA_ASSIST_PACKAGE, activity.packageName);
             extras.putInt(Intent.EXTRA_ASSIST_UID, activity.app.uid);
-            pae = new PendingAssistExtras(activity, extras, intent, hint, receiver, userHandle);
+            pae = new PendingAssistExtras(activity, extras, intent, hint, receiver, receiverExtras,
+                    userHandle);
             try {
                 activity.app.thread.requestAssistContextExtras(activity.appToken, pae,
                         requestType);
@@ -11975,9 +11992,11 @@
             if ((sendReceiver=pae.receiver) != null) {
                 // Caller wants result sent back to them.
                 sendBundle = new Bundle();
-                sendBundle.putBundle("data", pae.extras);
-                sendBundle.putParcelable("structure", pae.structure);
-                sendBundle.putParcelable("content", pae.content);
+                sendBundle.putBundle(VoiceInteractionSession.KEY_DATA, pae.extras);
+                sendBundle.putParcelable(VoiceInteractionSession.KEY_STRUCTURE, pae.structure);
+                sendBundle.putParcelable(VoiceInteractionSession.KEY_CONTENT, pae.content);
+                sendBundle.putBundle(VoiceInteractionSession.KEY_RECEIVER_EXTRAS,
+                        pae.receiverExtras);
             }
         }
         if (sendReceiver != null) {
@@ -12007,8 +12026,8 @@
 
     public boolean launchAssistIntent(Intent intent, int requestType, String hint, int userHandle,
             Bundle args) {
-        return enqueueAssistContext(requestType, intent, hint, null, null, userHandle, args,
-                PENDING_ASSIST_EXTRAS_TIMEOUT) != null;
+        return enqueueAssistContext(requestType, intent, hint, null, null, null, true,
+                userHandle, args, PENDING_ASSIST_EXTRAS_TIMEOUT) != null;
     }
 
     public void registerProcessObserver(IProcessObserver observer) {
@@ -20962,6 +20981,13 @@
                 mStackSupervisor.notifyAppTransitionDone();
             }
         }
+
+        @Override
+        public List<IBinder> getTopVisibleActivities() {
+            synchronized (ActivityManagerService.this) {
+                return mStackSupervisor.getTopVisibleActivities();
+            }
+        }
     }
 
     private final class SleepTokenImpl extends SleepToken {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 598d9ff..ab3a0b3 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -98,6 +98,7 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
@@ -4282,4 +4283,31 @@
             }
             return result;
     }
+
+    /**
+     * @return a list of activities which are the top ones in each visible stack. The first
+     * entry will be the focused activity.
+     */
+    public List<IBinder> getTopVisibleActivities() {
+        final ActivityDisplay display = mActivityDisplays.get(Display.DEFAULT_DISPLAY);
+        if (display == null) {
+            return Collections.EMPTY_LIST;
+        }
+        ArrayList<IBinder> topActivityTokens = new ArrayList<>();
+        final ArrayList<ActivityStack> stacks = display.mStacks;
+        for (int i = stacks.size() - 1; i >= 0; i--) {
+            ActivityStack stack = stacks.get(i);
+            if (stack.getStackVisibilityLocked(null) == ActivityStack.STACK_VISIBLE) {
+                ActivityRecord top = stack.topActivity();
+                if (top != null) {
+                    if (stack == mFocusedStack) {
+                        topActivityTokens.add(0, top.appToken);
+                    } else {
+                        topActivityTokens.add(top.appToken);
+                    }
+                }
+            }
+        }
+        return topActivityTokens;
+    }
 }
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java b/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java
index d339f69..5e68f8e 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java
@@ -329,6 +329,7 @@
             final String ssid = removeDoubleQuotes(config.SSID);
             if (id.equals(ssid)) {
                 final NetworkPolicy policy = newPolicy(ssid);
+                policy.metered = true;
                 Log.i(TAG, "Creating new policy for " + ssid + ": " + policy);
                 final NetworkPolicy[] newPolicies = new NetworkPolicy[policies.length + 1];
                 System.arraycopy(policies, 0, newPolicies, 0, policies.length);
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index d8c0775..2e81132 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -3396,7 +3396,9 @@
             IShortcutService shortcutService = mShortcutKeyServices.get(shortcutCode);
             if (shortcutService != null) {
                 try {
-                    shortcutService.notifyShortcutKeyPressed(shortcutCode);
+                    if (isUserSetupComplete()) {
+                        shortcutService.notifyShortcutKeyPressed(shortcutCode);
+                    }
                 } catch (RemoteException e) {
                     mShortcutKeyServices.delete(shortcutCode);
                 }
@@ -7188,10 +7190,6 @@
             tmpVisibility &= ~PolicyControl.adjustClearableFlags(win, View.SYSTEM_UI_CLEARABLE_FLAGS);
         }
 
-        if (mUiMode == Configuration.UI_MODE_TYPE_CAR) {
-            tmpVisibility |= StatusBarManager.DISABLE_RECENT;
-        }
-
         final int fullscreenVisibility = updateLightStatusBarLw(0 /* vis */,
                 mTopFullscreenOpaqueWindowState, mTopFullscreenOpaqueOrDimmingWindowState);
         final int dockedVisibility = updateLightStatusBarLw(0 /* vis */,
diff --git a/services/core/java/com/android/server/webkit/SystemImpl.java b/services/core/java/com/android/server/webkit/SystemImpl.java
index 876bb20..361f0d4 100644
--- a/services/core/java/com/android/server/webkit/SystemImpl.java
+++ b/services/core/java/com/android/server/webkit/SystemImpl.java
@@ -59,13 +59,19 @@
     private static final String TAG_AVAILABILITY = "availableByDefault";
     private static final String TAG_SIGNATURE = "signature";
     private static final String TAG_FALLBACK = "isFallback";
+    private final WebViewProviderInfo[] mWebViewProviderPackages;
 
-    /**
-     * Returns all packages declared in the framework resources as potential WebView providers.
-     * @hide
-     * */
-    @Override
-    public WebViewProviderInfo[] getWebViewPackages() {
+    // Initialization-on-demand holder idiom for getting the WebView provider packages once and
+    // for all in a thread-safe manner.
+    private static class LazyHolder {
+        private static final SystemImpl INSTANCE = new SystemImpl();
+    }
+
+    public static SystemImpl getInstance() {
+        return LazyHolder.INSTANCE;
+    }
+
+    private SystemImpl() {
         int numFallbackPackages = 0;
         int numAvailableByDefaultPackages = 0;
         int numAvByDefaultAndNotFallback = 0;
@@ -135,7 +141,16 @@
             throw new AndroidRuntimeException("There must be at least one WebView package "
                     + "that is available by default and not a fallback");
         }
-        return webViewProviders.toArray(new WebViewProviderInfo[webViewProviders.size()]);
+        mWebViewProviderPackages =
+                webViewProviders.toArray(new WebViewProviderInfo[webViewProviders.size()]);
+    }
+    /**
+     * Returns all packages declared in the framework resources as potential WebView providers.
+     * @hide
+     * */
+    @Override
+    public WebViewProviderInfo[] getWebViewPackages() {
+        return mWebViewProviderPackages;
     }
 
     public int getFactoryPackageVersion(String packageName) throws NameNotFoundException {
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateService.java b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
index bbb4951..9b971e0 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateService.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
@@ -55,7 +55,7 @@
 
     public WebViewUpdateService(Context context) {
         super(context);
-        mImpl = new WebViewUpdateServiceImpl(context, new SystemImpl());
+        mImpl = new WebViewUpdateServiceImpl(context, SystemImpl.getInstance());
     }
 
     @Override
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
index 7bd1f63..d90d922 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
@@ -404,7 +404,7 @@
         }
 
 
-        private class ProviderAndPackageInfo {
+        private static class ProviderAndPackageInfo {
             public final WebViewProviderInfo provider;
             public final PackageInfo packageInfo;
 
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 57dc97a..22f0887 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -646,17 +646,24 @@
 
         @Override
         public void onChange(boolean selfChange, Uri uri) {
+            if (uri == null) {
+                return;
+            }
+
             if (mDisplayInversionEnabledUri.equals(uri)) {
                 updateCircularDisplayMaskIfNeeded();
             } else {
                 @UpdateAnimationScaleMode
                 final int mode;
-                if (uri.equals(mWindowAnimationScaleUri)) {
+                if (mWindowAnimationScaleUri.equals(uri)) {
                     mode = WINDOW_ANIMATION_SCALE;
-                } else if (uri.equals(mTransitionAnimationScaleUri)) {
+                } else if (mTransitionAnimationScaleUri.equals(uri)) {
                     mode = TRANSITION_ANIMATION_SCALE;
-                } else { // uri.equals(mAnimationDurationScaleUri)
+                } else if (mAnimationDurationScaleUri.equals(uri)) {
                     mode = ANIMATION_DURATION_SCALE;
+                } else {
+                    // Ignoring unrecognized content changes
+                    return;
                 }
                 Message m = mH.obtainMessage(H.UPDATE_ANIMATION_SCALE, mode, 0);
                 mH.sendMessage(m);
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
index f13e019..53377f9 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
@@ -84,22 +84,15 @@
     private final PhoneStateListener mPhoneStateListener;
     private final PowerManager mPowerManager;
 
-    // The SoundTriggerManager layer handles multiple generic recognition models. We store the
-    // ModelData here in a hashmap.
-    private final HashMap<UUID, ModelData> mGenericModelDataMap;
+    // The SoundTriggerManager layer handles multiple recognition models of type generic and
+    // keyphrase. We store the ModelData here in a hashmap.
+    private final HashMap<UUID, ModelData> mModelDataMap;
 
-    // This ModelData instance ensures that the keyphrase sound model is a singleton and
-    // all other sound models are of type Generic. Any keyphrase sound model will be stored here
-    // and any previously running instances will be replaced. This restriction was earlier
-    // implemented by three instance variables which stored data about the keyphrase
-    // model. That data now gets encapsulated in this ModelData instance.
-    private ModelData mKeyphraseModelData;
-
-    // The keyphrase ID for keyphrase sound models. We store this specially here since ModelData
-    // does not support this.
-    // TODO: The role of the keyphrase ID is a bit unclear. Its just used to ensure that
-    // recognition events have the correct keyphrase ID check.
-    private int mKeyphraseId = INVALID_VALUE;
+    // An index of keyphrase sound models so that we can reach them easily. We support indexing
+    // keyphrase sound models with a keyphrase ID. Sound model with the same keyphrase ID will
+    // replace an existing model, thus there is a 1:1 mapping from keyphrase ID to a voice
+    // sound model.
+    private HashMap<Integer, UUID> mKeyphraseUuidMap;
 
     private boolean mCallActive = false;
     private boolean mIsPowerSaveMode = false;
@@ -119,7 +112,8 @@
         mContext = context;
         mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
         mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
-        mGenericModelDataMap = new HashMap<UUID, ModelData>();
+        mModelDataMap = new HashMap<UUID, ModelData>();
+        mKeyphraseUuidMap = new HashMap<Integer, UUID>();
         mPhoneStateListener = new MyCallStateListener();
         if (status != SoundTrigger.STATUS_OK || modules.size() == 0) {
             Slog.w(TAG, "listModules status=" + status + ", # of modules=" + modules.size());
@@ -153,6 +147,10 @@
 
         synchronized (mLock) {
             ModelData modelData = getOrCreateGenericModelDataLocked(modelId);
+            if (modelData == null) {
+                Slog.w(TAG, "Irrecoverable error occurred, check UUID / sound model data.");
+                return STATUS_ERROR;
+            }
             return startRecognition(soundModel, modelData, callback, recognitionConfig,
                     INVALID_VALUE /* keyphraseId */);
         }
@@ -180,20 +178,48 @@
                         + " soundModel=" + soundModel + ", callback=" + callback.asBinder()
                         + ", recognitionConfig=" + recognitionConfig);
                 Slog.d(TAG, "moduleProperties=" + mModuleProperties);
-                if (mKeyphraseModelData != null) {
-                    Slog.d(TAG, mKeyphraseModelData.toString());
-                } else {
-                    Slog.d(TAG, "Null KeyphraseModelData.");
+                dumpModelStateLocked();
+            }
+
+            ModelData model = getKeyphraseModelDataLocked(keyphraseId);
+            if (model != null && !model.isKeyphraseModel()) {
+                Slog.e(TAG, "Generic model with same UUID exists.");
+                return STATUS_ERROR;
+            }
+
+            // Process existing model first.
+            if (model != null && model.getModelId() != soundModel.uuid) {
+                // The existing model has a different UUID, should be replaced.
+                int status = cleanUpExistingKeyphraseModel(model);
+                removeKeyphraseModelLocked(keyphraseId);
+                if (status != STATUS_OK) {
+                    return status;
                 }
+                model = null;
             }
-            if (mKeyphraseModelData == null) {
-                mKeyphraseModelData = ModelData.createKeyphraseModelData(soundModel.uuid);
+
+            // We need to create a new one: either no previous models existed for given keyphrase id
+            // or the existing model had a different UUID and was cleaned up.
+            if (model == null) {
+                model = createKeyphraseModelDataLocked(soundModel.uuid, keyphraseId);
             }
-            return startRecognition(soundModel, mKeyphraseModelData, callback, recognitionConfig,
+
+            return startRecognition(soundModel, model, callback, recognitionConfig,
                     keyphraseId);
         }
     }
 
+    private int cleanUpExistingKeyphraseModel(ModelData modelData) {
+        // Stop and clean up a previous ModelData if one exists. This usually is used when the
+        // previous model has a different UUID for the same keyphrase ID.
+        int status = tryStopAndUnloadLocked(modelData, true /* stop */, true /* unload */);
+        if (status != STATUS_OK) {
+            Slog.w(TAG, "Unable to stop or unload previous model: " +
+                    modelData.toString());
+        }
+        return status;
+    }
+
     /**
      * Starts recognition for the given sound model. A single routine for both keyphrase and
      * generic sound models.
@@ -228,17 +254,15 @@
                 initializeTelephonyAndPowerStateListeners();
             }
 
-            // If the previous model is different (for the same UUID), ensure that its unloaded
-            // and stopped before proceeding. This works for both keyphrase and generic models.
-            // Specifically for keyphrase since we have 'mKeyphraseModelData' holding a single
-            // allowed instance of such a model, this ensures that a previously loaded (or started)
-            // keyphrase model is appropriately stopped. This ensures no regression with the
-            // previous version of this code as given in the startKeyphrase() routine.
-            //
-            // For generic sound models, all this means is that if we are given a different sound
-            // model with the same UUID, then we will "replace" it.
+            // If the existing SoundModel is different (for the same UUID for Generic and same
+            // keyphrase ID for voice), ensure that it is unloaded and stopped before proceeding.
+            // This works for both keyphrase and generic models. This logic also ensures that a
+            // previously loaded (or started) model is appropriately stopped. Since this is a
+            // generalization of the previous logic with a single keyphrase model, we should have
+            // no regression with the previous version of this code as was given in the
+            // startKeyphrase() routine.
             if (modelData.getSoundModel() != null) {
-                boolean stopModel = false; // Stop the model after checking that its started.
+                boolean stopModel = false; // Stop the model after checking that it is started.
                 boolean unloadModel = false;
                 if (modelData.getSoundModel().equals(soundModel) && modelData.isModelStarted()) {
                     // The model has not changed, but the previous model is "started".
@@ -273,7 +297,7 @@
                 modelData.clearCallback();
             }
 
-            // Load the model if its not loaded.
+            // Load the model if it is not loaded.
             if (!modelData.isModelLoaded()) {
                 // Load the model
                 int[] handle = new int[] { INVALID_VALUE };
@@ -291,9 +315,6 @@
                 Slog.d(TAG, "Sound model loaded with handle:" + handle[0]);
             }
             modelData.setCallback(callback);
-            if (modelData.isKeyphraseModel()) {
-                mKeyphraseId = keyphraseId;
-            }
             modelData.setRequested(true);
             modelData.setRecognitionConfig(recognitionConfig);
             modelData.setSoundModel(soundModel);
@@ -322,8 +343,8 @@
                 return STATUS_ERROR;
             }
 
-            ModelData modelData = mGenericModelDataMap.get(modelId);
-            if (modelData == null) {
+            ModelData modelData = mModelDataMap.get(modelId);
+            if (modelData == null || !modelData.isGenericModel()) {
                 Slog.w(TAG, "Attempting stopRecognition on invalid model with id:" + modelId);
                 return STATUS_ERROR;
             }
@@ -355,21 +376,23 @@
                 return STATUS_ERROR;
             }
 
+            ModelData modelData = getKeyphraseModelDataLocked(keyphraseId);
+            if (modelData == null || !modelData.isKeyphraseModel()) {
+                Slog.e(TAG, "No model exists for given keyphrase Id.");
+                return STATUS_ERROR;
+            }
+
             if (DBG) {
                 Slog.d(TAG, "stopRecognition for keyphraseId=" + keyphraseId + ", callback =" +
                         callback.asBinder());
-                Slog.d(TAG, "current callback=" + (mKeyphraseModelData == null ? "null" :
-                            mKeyphraseModelData.getCallback().asBinder()));
+                Slog.d(TAG, "current callback=" + (modelData == null ? "null" :
+                            modelData.getCallback().asBinder()));
             }
-            int status = stopRecognition(mKeyphraseModelData, callback);
+            int status = stopRecognition(modelData, callback);
             if (status != SoundTrigger.STATUS_OK) {
                 return status;
             }
 
-            // We leave the sound model loaded but not started, this helps us when we start
-            // back.
-            // Also clear the internal state once the recognition has been stopped.
-            internalClearKeyphraseStateLocked();
             return status;
         }
     }
@@ -424,9 +447,6 @@
                 internalClearGlobalStateLocked();
             }
 
-            if (modelData.isKeyphraseModel()) {
-                mKeyphraseId = INVALID_VALUE;
-            }
             return status;
         }
     }
@@ -475,25 +495,18 @@
                 return;
             }
 
-            // Stop Keyphrase recognition if one exists.
-            if (mKeyphraseModelData != null && mKeyphraseModelData.getHandle() != INVALID_VALUE) {
-                mKeyphraseModelData.setRequested(false);
-                int status = updateRecognitionLocked(mKeyphraseModelData, isRecognitionAllowed(),
-                        false /* don't notify for synchronous calls */);
-                internalClearKeyphraseStateLocked();
-            }
-
-            // Stop all generic recognition models.
-            for (ModelData model : mGenericModelDataMap.values()) {
+            // Stop all recognition models.
+            for (ModelData model : mModelDataMap.values()) {
                 if (model.isModelStarted()) {
+                    model.setRequested(false);
                     int status = stopRecognitionLocked(model,
                             false /* do not notify for synchronous calls */);
                     if (status != STATUS_OK) {
-                        // What else can we do if there is an error here.
-                        Slog.w(TAG, "Error stopping generic model: " + model.getHandle());
+                        Slog.w(TAG, "Error stopping keyphrase model: " + model.getHandle());
                     }
                     model.clearState();
                     model.clearCallback();
+                    model.setRecognitionConfig(null);
                 }
             }
             internalClearGlobalStateLocked();
@@ -507,24 +520,27 @@
     int unloadKeyphraseSoundModel(int keyphraseId) {
         synchronized (mLock) {
             MetricsLogger.count(mContext, "sth_unload_keyphrase_sound_model", 1);
-            if (mModule == null || mKeyphraseModelData == null ||
-                    mKeyphraseModelData.getHandle() == INVALID_VALUE) {
+            ModelData modelData = getKeyphraseModelDataLocked(keyphraseId);
+            if (mModule == null || modelData == null || modelData.getHandle() == INVALID_VALUE ||
+                    !modelData.isKeyphraseModel()) {
                 return STATUS_ERROR;
             }
 
             // Stop recognition if it's the current one.
-            mKeyphraseModelData.setRequested(false);
-            int status = updateRecognitionLocked(mKeyphraseModelData, isRecognitionAllowed(),
+            modelData.setRequested(false);
+            int status = updateRecognitionLocked(modelData, isRecognitionAllowed(),
                     false /* don't notify */);
             if (status != SoundTrigger.STATUS_OK) {
                 Slog.w(TAG, "Stop recognition failed for keyphrase ID:" + status);
             }
 
-            status = mModule.unloadSoundModel(mKeyphraseModelData.getHandle());
+            status = mModule.unloadSoundModel(modelData.getHandle());
             if (status != SoundTrigger.STATUS_OK) {
                 Slog.w(TAG, "unloadKeyphraseSoundModel call failed with " + status);
             }
-            mKeyphraseModelData.clearState();
+
+            // Remove it from existence.
+            removeKeyphraseModelLocked(keyphraseId);
             return status;
         }
     }
@@ -535,8 +551,8 @@
             if (modelId == null || mModule == null) {
                 return STATUS_ERROR;
             }
-            ModelData modelData = mGenericModelDataMap.get(modelId);
-            if (modelData == null) {
+            ModelData modelData = mModelDataMap.get(modelId);
+            if (modelData == null || !modelData.isGenericModel()) {
                 Slog.w(TAG, "Unload error: Attempting unload invalid generic model with id:" +
                         modelId);
                 return STATUS_ERROR;
@@ -559,8 +575,10 @@
                 Slog.w(TAG, "unloadGenericSoundModel() call failed with " + status);
                 Slog.w(TAG, "unloadGenericSoundModel() force-marking model as unloaded.");
             }
-            mGenericModelDataMap.remove(modelId);
-            if (DBG) dumpGenericModelStateLocked();
+
+            // Remove it from existence.
+            mModelDataMap.remove(modelId);
+            if (DBG) dumpModelStateLocked();
             return status;
         }
     }
@@ -612,7 +630,7 @@
             return;
         }
         ModelData model = getModelDataForLocked(event.soundModelHandle);
-        if (model == null) {
+        if (model == null || !model.isGenericModel()) {
             Slog.w(TAG, "Generic recognition event: Model does not exist for handle: " +
                     event.soundModelHandle);
             return;
@@ -723,67 +741,64 @@
         } catch (RemoteException e) {
             Slog.w(TAG, "RemoteException in onError", e);
         } finally {
-            internalClearKeyphraseStateLocked();
-            internalClearGenericModelStateLocked();
+            internalClearModelStateLocked();
             internalClearGlobalStateLocked();
         }
     }
 
+    private int getKeyphraseIdFromEvent(KeyphraseRecognitionEvent event) {
+        if (event == null) {
+            Slog.w(TAG, "Null RecognitionEvent received.");
+            return INVALID_VALUE;
+        }
+        KeyphraseRecognitionExtra[] keyphraseExtras =
+                ((KeyphraseRecognitionEvent) event).keyphraseExtras;
+        if (keyphraseExtras == null || keyphraseExtras.length == 0) {
+            Slog.w(TAG, "Invalid keyphrase recognition event!");
+            return INVALID_VALUE;
+        }
+        // TODO: Handle more than one keyphrase extras.
+        return keyphraseExtras[0].id;
+    }
+
     private void onKeyphraseRecognitionSuccessLocked(KeyphraseRecognitionEvent event) {
         Slog.i(TAG, "Recognition success");
         MetricsLogger.count(mContext, "sth_keyphrase_recognition_event", 1);
+        int keyphraseId = getKeyphraseIdFromEvent(event);
+        ModelData modelData = getKeyphraseModelDataLocked(keyphraseId);
 
-        if (mKeyphraseModelData == null) {
-            Slog.e(TAG, "Received onRecognition event for null keyphrase model data.");
+        if (modelData == null || !modelData.isKeyphraseModel()) {
+            Slog.e(TAG, "Keyphase model data does not exist for ID:" + keyphraseId);
             return;
         }
 
-        if (mKeyphraseModelData.getCallback() == null) {
-            Slog.w(TAG, "Received onRecognition event without any listener for it.");
-            return;
-        }
-
-        KeyphraseRecognitionExtra[] keyphraseExtras =
-                ((KeyphraseRecognitionEvent) event).keyphraseExtras;
-        if (keyphraseExtras == null || keyphraseExtras.length == 0) {
-            Slog.w(TAG, "Invalid keyphrase recognition event!");
-            return;
-        }
-        // TODO: Handle more than one keyphrase extras.
-        if (mKeyphraseId != keyphraseExtras[0].id) {
-            Slog.w(TAG, "received onRecognition event for a different keyphrase");
+        if (modelData.getCallback() == null) {
+            Slog.w(TAG, "Received onRecognition event without callback for keyphrase model.");
             return;
         }
 
         try {
-            mKeyphraseModelData.getCallback().onKeyphraseDetected(
-                    (KeyphraseRecognitionEvent) event);
+            modelData.getCallback().onKeyphraseDetected((KeyphraseRecognitionEvent) event);
         } catch (RemoteException e) {
             Slog.w(TAG, "RemoteException in onKeyphraseDetected", e);
         }
 
-        mKeyphraseModelData.setStopped();
+        modelData.setStopped();
 
-        RecognitionConfig config = mKeyphraseModelData.getRecognitionConfig();
+        RecognitionConfig config = modelData.getRecognitionConfig();
         if (config != null) {
             // Whether we should continue by starting this again.
-            mKeyphraseModelData.setRequested(config.allowMultipleTriggers);
+            modelData.setRequested(config.allowMultipleTriggers);
         }
         // TODO: Remove this block if the lower layer supports multiple triggers.
-        if (mKeyphraseModelData.getRequested()) {
-            updateRecognitionLocked(mKeyphraseModelData, isRecognitionAllowed(),
-                true /* notify */);
+        if (modelData.getRequested()) {
+            updateRecognitionLocked(modelData, isRecognitionAllowed(), true /* notify */);
         }
     }
 
     private void updateAllRecognitionsLocked(boolean notify) {
         boolean isAllowed = isRecognitionAllowed();
-        // Keyphrase model.
-        if (mKeyphraseModelData != null) {
-            updateRecognitionLocked(mKeyphraseModelData, isAllowed, notify);
-        }
-        for (UUID modelId : mGenericModelDataMap.keySet()) {
-            ModelData modelData = mGenericModelDataMap.get(modelId);
+        for (ModelData modelData : mModelDataMap.values()) {
             updateRecognitionLocked(modelData, isAllowed, notify);
         }
     }
@@ -809,11 +824,7 @@
         } catch (RemoteException e) {
             Slog.w(TAG, "RemoteException in onError", e);
         } finally {
-            if (mKeyphraseModelData != null) {
-                mKeyphraseModelData.clearState();
-            }
-            internalClearKeyphraseStateLocked();
-            internalClearGenericModelStateLocked();
+            internalClearModelStateLocked();
             internalClearGlobalStateLocked();
             if (mModule != null) {
                 mModule.detach();
@@ -822,10 +833,7 @@
         }
     }
 
-    // internalClearGlobalStateLocked() gets split into two routines. Cleanup that is
-    // specific to keyphrase sound models named as internalClearKeyphraseStateLocked() and
-    // internalClearGlobalStateLocked() for global state. The global cleanup routine will be used
-    // by the cleanup happening with the generic sound models.
+    // internalClearGlobalStateLocked() cleans up the telephony and power save listeners.
     private void internalClearGlobalStateLocked() {
         // Unregister from call state changes.
         mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
@@ -837,20 +845,9 @@
         }
     }
 
-    private void internalClearKeyphraseStateLocked() {
-        if (mKeyphraseModelData != null) {
-            mKeyphraseModelData.setStopped();
-            mKeyphraseModelData.setRequested(false);
-            mKeyphraseModelData.setRecognitionConfig(null);
-            mKeyphraseModelData.setCallback(null);
-        }
-
-        mKeyphraseId = INVALID_VALUE;
-    }
-
-    private void internalClearGenericModelStateLocked() {
-        for (UUID modelId : mGenericModelDataMap.keySet()) {
-            ModelData modelData = mGenericModelDataMap.get(modelId);
+    // Clears state for all models (generic and keyphrase).
+    private void internalClearModelStateLocked() {
+        for (ModelData modelData : mModelDataMap.values()) {
             modelData.clearState();
             modelData.clearCallback();
         }
@@ -884,14 +881,10 @@
         synchronized (mLock) {
             pw.print("  module properties=");
             pw.println(mModuleProperties == null ? "null" : mModuleProperties);
-            pw.print("  keyphrase ID="); pw.println(mKeyphraseId);
 
             pw.print("  call active="); pw.println(mCallActive);
             pw.print("  power save mode active="); pw.println(mIsPowerSaveMode);
             pw.print("  service disabled="); pw.println(mServiceDisabled);
-            if (mKeyphraseModelData != null) {
-                pw.println(mKeyphraseModelData.toString());
-            }
         }
     }
 
@@ -914,34 +907,60 @@
 
     // Sends an error callback to all models with a valid registered callback.
     private void sendErrorCallbacksToAll(int errorCode) throws RemoteException {
-        IRecognitionStatusCallback keyphraseListener = mKeyphraseModelData.getCallback();
-        if (keyphraseListener != null) {
-            keyphraseListener.onError(STATUS_ERROR);
-        }
-        for (UUID modelId: mGenericModelDataMap.keySet()) {
-            ModelData modelData = mGenericModelDataMap.get(modelId);
-            IRecognitionStatusCallback keyphraseCallback = mKeyphraseModelData.getCallback();
-            if (keyphraseCallback != null) {
-                keyphraseCallback.onError(STATUS_ERROR);
+        for (ModelData modelData : mModelDataMap.values()) {
+            IRecognitionStatusCallback callback = modelData.getCallback();
+            if (callback != null) {
+                callback.onError(STATUS_ERROR);
             }
         }
     }
 
     private ModelData getOrCreateGenericModelDataLocked(UUID modelId) {
-        ModelData modelData = mGenericModelDataMap.get(modelId);
+        ModelData modelData = mModelDataMap.get(modelId);
         if (modelData == null) {
             modelData = ModelData.createGenericModelData(modelId);
-            mGenericModelDataMap.put(modelId, modelData);
+            mModelDataMap.put(modelId, modelData);
+        } else if (!modelData.isGenericModel()) {
+            Slog.e(TAG, "UUID already used for non-generic model.");
+            return null;
         }
         return modelData;
     }
 
+    private void removeKeyphraseModelLocked(int keyphraseId) {
+        UUID uuid = mKeyphraseUuidMap.get(keyphraseId);
+        if (uuid == null) {
+            return;
+        }
+        mModelDataMap.remove(uuid);
+        mKeyphraseUuidMap.remove(keyphraseId);
+    }
+
+    private ModelData getKeyphraseModelDataLocked(int keyphraseId) {
+        UUID uuid = mKeyphraseUuidMap.get(keyphraseId);
+        if (uuid == null) {
+            return null;
+        }
+        return mModelDataMap.get(uuid);
+    }
+
+    // Use this to create a new ModelData entry for a keyphrase Id. It will overwrite existing
+    // mapping if one exists.
+    private ModelData createKeyphraseModelDataLocked(UUID modelId, int keyphraseId) {
+        mKeyphraseUuidMap.remove(keyphraseId);
+        mModelDataMap.remove(modelId);
+        mKeyphraseUuidMap.put(keyphraseId, modelId);
+        ModelData modelData = ModelData.createKeyphraseModelData(modelId);
+        mModelDataMap.put(modelId, modelData);
+        return modelData;
+    }
+
     // Instead of maintaining a second hashmap of modelHandle -> ModelData, we just
     // iterate through to find the right object (since we don't expect 100s of models
     // to be stored).
     private ModelData getModelDataForLocked(int modelHandle) {
         // Fetch ModelData object corresponding to the model handle.
-        for (ModelData model : mGenericModelDataMap.values()) {
+        for (ModelData model : mModelDataMap.values()) {
             if (model.getHandle() == modelHandle) {
                 return model;
             }
@@ -1051,9 +1070,9 @@
         return status;
     }
 
-    private void dumpGenericModelStateLocked() {
-        for (UUID modelId : mGenericModelDataMap.keySet()) {
-            ModelData modelData = mGenericModelDataMap.get(modelId);
+    private void dumpModelStateLocked() {
+        for (UUID modelId : mModelDataMap.keySet()) {
+            ModelData modelData = mModelDataMap.get(modelId);
             Slog.i(TAG, "Model :" + modelData.toString());
         }
     }
@@ -1065,14 +1084,7 @@
             mRecognitionRunning = false;
             return mRecognitionRunning;
         }
-        if (mKeyphraseModelData != null && mKeyphraseModelData.getCallback() != null &&
-                mKeyphraseModelData.isModelStarted() &&
-            mKeyphraseModelData.getHandle() != INVALID_VALUE) {
-            mRecognitionRunning = true;
-            return mRecognitionRunning;
-        }
-        for (UUID modelId : mGenericModelDataMap.keySet()) {
-            ModelData modelData = mGenericModelDataMap.get(modelId);
+        for (ModelData modelData : mModelDataMap.values()) {
             if (modelData.isModelStarted()) {
                 mRecognitionRunning = true;
                 return mRecognitionRunning;
@@ -1233,6 +1245,10 @@
             return mModelType == SoundModel.TYPE_KEYPHRASE;
         }
 
+        synchronized boolean isGenericModel() {
+            return mModelType == SoundModel.TYPE_GENERIC_SOUND;
+        }
+
         synchronized String stateToString() {
             switch(mModelState) {
                 case MODEL_NOTLOADED: return "NOT_LOADED";
@@ -1259,7 +1275,17 @@
                     "ModelState: " + stateToString() + "\n" +
                     requestedToString() + "\n" +
                     callbackToString() + "\n" +
-                    uuidToString();
+                    uuidToString() + "\n" + modelTypeToString();
+        }
+
+        synchronized String modelTypeToString() {
+            String type = null;
+            switch (mModelType) {
+                case SoundModel.TYPE_GENERIC_SOUND: type = "Generic"; break;
+                case SoundModel.TYPE_UNKNOWN: type = "Unknown"; break;
+                case SoundModel.TYPE_KEYPHRASE: type = "Keyphrase"; break;
+            }
+            return "Model type: " + type + "\n";
         }
     }
 }
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index 1544723..1e9db18 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -17,6 +17,7 @@
 package com.android.server.voiceinteraction;
 
 import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
 import android.app.ActivityManagerNative;
 import android.app.IActivityManager;
 import android.content.BroadcastReceiver;
@@ -42,9 +43,11 @@
 
 import com.android.internal.app.IVoiceInteractionSessionShowCallback;
 import com.android.internal.app.IVoiceInteractor;
+import com.android.server.LocalServices;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.util.List;
 
 class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConnection.Callback {
     final static String TAG = "VoiceInteractionServiceManager";
@@ -148,8 +151,14 @@
             mActiveSession = new VoiceInteractionSessionConnection(mLock, mSessionComponentName,
                     mUser, mContext, this, mInfo.getServiceInfo().applicationInfo.uid, mHandler);
         }
+        List<IBinder> activityTokens = null;
+        if (activityToken == null) {
+            // Let's get top activities from all visible stacks
+            activityTokens = LocalServices.getService(ActivityManagerInternal.class)
+                    .getTopVisibleActivities();
+        }
         return mActiveSession.showLocked(args, flags, mDisabledShowContext, showCallback,
-                activityToken);
+                activityToken, activityTokens);
     }
 
     public boolean hideSessionLocked() {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
index e04f312..0922a12 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
@@ -45,6 +45,7 @@
 import android.util.Slog;
 import android.view.IWindowManager;
 import android.view.WindowManager;
+
 import com.android.internal.app.IAssistScreenshotReceiver;
 import com.android.internal.app.IVoiceInteractionSessionShowCallback;
 import com.android.internal.app.IVoiceInteractor;
@@ -55,10 +56,15 @@
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.List;
 
 final class VoiceInteractionSessionConnection implements ServiceConnection {
+
     final static String TAG = "VoiceInteractionServiceManager";
 
+    private static final String KEY_RECEIVER_EXTRA_COUNT = "count";
+    private static final String KEY_RECEIVER_EXTRA_INDEX = "index";
+
     final IBinder mToken = new Binder();
     final Object mLock;
     final ComponentName mSessionComponentName;
@@ -82,11 +88,27 @@
     IVoiceInteractionSession mSession;
     IVoiceInteractor mInteractor;
     boolean mHaveAssistData;
-    Bundle mAssistData;
+    int mPendingAssistDataCount;
+    ArrayList<AssistDataForActivity> mAssistData = new ArrayList<>();
     boolean mHaveScreenshot;
     Bitmap mScreenshot;
     ArrayList<IVoiceInteractionSessionShowCallback> mPendingShowCallbacks = new ArrayList<>();
 
+    static class AssistDataForActivity {
+        int activityIndex;
+        int activityCount;
+        Bundle data;
+
+        public AssistDataForActivity(Bundle data) {
+            this.data = data;
+            Bundle receiverExtras = data.getBundle(VoiceInteractionSession.KEY_RECEIVER_EXTRAS);
+            if (receiverExtras != null) {
+                activityIndex = receiverExtras.getInt(KEY_RECEIVER_EXTRA_INDEX);
+                activityCount = receiverExtras.getInt(KEY_RECEIVER_EXTRA_COUNT);
+            }
+        }
+    }
+
     IVoiceInteractionSessionShowCallback mShowCallback =
             new IVoiceInteractionSessionShowCallback.Stub() {
         @Override
@@ -125,7 +147,7 @@
             synchronized (mLock) {
                 if (mShown) {
                     mHaveAssistData = true;
-                    mAssistData = resultData;
+                    mAssistData.add(new AssistDataForActivity(resultData));
                     deliverSessionDataLocked();
                 }
             }
@@ -198,7 +220,8 @@
     }
 
     public boolean showLocked(Bundle args, int flags, int disabledContext,
-            IVoiceInteractionSessionShowCallback showCallback, IBinder activityToken) {
+            IVoiceInteractionSessionShowCallback showCallback, IBinder activityToken,
+            List<IBinder> topActivities) {
         if (mBound) {
             if (!mFullyBound) {
                 mFullyBound = mContext.bindServiceAsUser(mBindIntent, mFullConnection,
@@ -220,30 +243,41 @@
             mShowArgs = args;
             mShowFlags = flags;
             mHaveAssistData = false;
+            mPendingAssistDataCount = 0;
             boolean needDisclosure = false;
             if ((flags&VoiceInteractionSession.SHOW_WITH_ASSIST) != 0) {
                 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ASSIST_STRUCTURE, mCallingUid,
                         mSessionComponentName.getPackageName()) == AppOpsManager.MODE_ALLOWED
                         && structureEnabled) {
-                    try {
-                        MetricsLogger.count(mContext, "assist_with_context", 1);
-                        if (mAm.requestAssistContextExtras(ActivityManager.ASSIST_CONTEXT_FULL,
-                                mAssistReceiver, activityToken)) {
-                            needDisclosure = true;
-                        } else {
-                            // Wasn't allowed...  given that, let's not do the screenshot either.
-                            mHaveAssistData = true;
-                            mAssistData = null;
-                            screenshotEnabled = false;
+                    mAssistData.clear();
+                    final int count = activityToken != null ? 1 : topActivities.size();
+                    for (int i = 0; i < count; i++) {
+                        IBinder topActivity = count == 1 ? activityToken : topActivities.get(i);
+                        try {
+                            MetricsLogger.count(mContext, "assist_with_context", 1);
+                            Bundle receiverExtras = new Bundle();
+                            receiverExtras.putInt(KEY_RECEIVER_EXTRA_INDEX, i);
+                            receiverExtras.putInt(KEY_RECEIVER_EXTRA_COUNT, count);
+                            if (mAm.requestAssistContextExtras(ActivityManager.ASSIST_CONTEXT_FULL,
+                                    mAssistReceiver, receiverExtras, topActivity, i == 0)) {
+                                needDisclosure = true;
+                                mPendingAssistDataCount++;
+                            } else if (i == 0) {
+                                // Wasn't allowed... given that, let's not do the screenshot either.
+                                mHaveAssistData = true;
+                                mAssistData.clear();
+                                screenshotEnabled = false;
+                                break;
+                            }
+                        } catch (RemoteException e) {
                         }
-                    } catch (RemoteException e) {
                     }
                 } else {
                     mHaveAssistData = true;
-                    mAssistData = null;
+                    mAssistData.clear();
                 }
             } else {
-                mAssistData = null;
+                mAssistData.clear();
             }
             mHaveScreenshot = false;
             if ((flags&VoiceInteractionSession.SHOW_WITH_SCREENSHOT) != 0) {
@@ -335,41 +369,26 @@
             return;
         }
         if (mHaveAssistData) {
-            Bundle assistData;
-            AssistStructure structure;
-            AssistContent content;
-            if (mAssistData != null) {
-                assistData = mAssistData.getBundle("data");
-                structure = mAssistData.getParcelable("structure");
-                content = mAssistData.getParcelable("content");
-                int uid = mAssistData.getInt(Intent.EXTRA_ASSIST_UID, -1);
-                if (uid >= 0 && content != null) {
-                    Intent intent = content.getIntent();
-                    if (intent != null) {
-                        ClipData data = intent.getClipData();
-                        if (data != null && Intent.isAccessUriMode(intent.getFlags())) {
-                            grantClipDataPermissions(data, intent.getFlags(), uid,
-                                    mCallingUid, mSessionComponentName.getPackageName());
-                        }
-                    }
-                    ClipData data = content.getClipData();
-                    if (data != null) {
-                        grantClipDataPermissions(data,
-                                Intent.FLAG_GRANT_READ_URI_PERMISSION,
-                                uid, mCallingUid, mSessionComponentName.getPackageName());
-                    }
+            AssistDataForActivity assistData;
+            while (!mAssistData.isEmpty()) {
+                if (mPendingAssistDataCount <= 0) {
+                    Slog.e(TAG, "mPendingAssistDataCount is " + mPendingAssistDataCount);
                 }
-            } else {
-                assistData = null;
-                structure = null;
-                content = null;
+                mPendingAssistDataCount--;
+                assistData = mAssistData.remove(0);
+                if (assistData.data == null) {
+                    try {
+                        mSession.handleAssist(null, null, null, assistData.activityIndex,
+                                assistData.activityCount);
+                    } catch (RemoteException e) {
+                    }
+                } else {
+                    deliverSessionDataLocked(assistData);
+                }
             }
-            try {
-                mSession.handleAssist(assistData, structure, content);
-            } catch (RemoteException e) {
-            }
-            mAssistData = null;
-            mHaveAssistData = false;
+            if (mPendingAssistDataCount <= 0) {
+                mHaveAssistData = false;
+            } // else, more to come
         }
         if (mHaveScreenshot) {
             try {
@@ -381,6 +400,37 @@
         }
     }
 
+    private void deliverSessionDataLocked(AssistDataForActivity assistDataForActivity) {
+        Bundle assistData = assistDataForActivity.data.getBundle(
+                VoiceInteractionSession.KEY_DATA);
+        AssistStructure structure = assistDataForActivity.data.getParcelable(
+                VoiceInteractionSession.KEY_STRUCTURE);
+        AssistContent content = assistDataForActivity.data.getParcelable(
+                VoiceInteractionSession.KEY_CONTENT);
+        int uid = assistDataForActivity.data.getInt(Intent.EXTRA_ASSIST_UID, -1);
+        if (uid >= 0 && content != null) {
+            Intent intent = content.getIntent();
+            if (intent != null) {
+                ClipData data = intent.getClipData();
+                if (data != null && Intent.isAccessUriMode(intent.getFlags())) {
+                    grantClipDataPermissions(data, intent.getFlags(), uid,
+                            mCallingUid, mSessionComponentName.getPackageName());
+                }
+            }
+            ClipData data = content.getClipData();
+            if (data != null) {
+                grantClipDataPermissions(data,
+                        Intent.FLAG_GRANT_READ_URI_PERMISSION,
+                        uid, mCallingUid, mSessionComponentName.getPackageName());
+            }
+        }
+        try {
+            mSession.handleAssist(assistData, structure, content,
+                    assistDataForActivity.activityIndex, assistDataForActivity.activityCount);
+        } catch (RemoteException e) {
+        }
+    }
+
     public boolean hideLocked() {
         if (mBound) {
             if (mShown) {
@@ -388,7 +438,7 @@
                 mShowArgs = null;
                 mShowFlags = 0;
                 mHaveAssistData = false;
-                mAssistData = null;
+                mAssistData.clear();
                 if (mSession != null) {
                     try {
                         mSession.hide();
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 8aa0e34..cfc5305 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -33,8 +33,6 @@
     // From the top of ril.cpp
     int RIL_ERRNO_INVALID_RESPONSE = -1;
 
-    int MAX_INT = 0x7FFFFFFF;
-
     // from RIL_Errno
     int SUCCESS = 0;
     int RADIO_NOT_AVAILABLE = 1;              /* If radio did not start or is resetting */
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
index 450334c..5767f11 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
@@ -194,6 +194,18 @@
     }
 
     @Override
+    public void onHandleAssistSecondary(final Bundle data, final AssistStructure structure,
+            final AssistContent content, int index, int count) {
+        Log.i(TAG, "Got secondary activity assist data " + index + " of " + count);
+        Log.i(TAG, "Showing assist structure after a few seconds...");
+        mContentView.postDelayed(new Runnable() {
+            public void run() {
+                onHandleAssist(data, structure, content);
+            }
+        }, 2000 * index);
+    }
+
+    @Override
     public void onHandleScreenshot(Bitmap screenshot) {
         if (screenshot != null) {
             mScreenshot.setImageBitmap(screenshot);
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java
index 308488a..e0d8249 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java
@@ -24,6 +24,7 @@
 import com.android.ide.common.rendering.api.ViewInfo;
 import com.android.layoutlib.bridge.impl.RenderSessionImpl;
 import com.android.tools.layoutlib.java.System_Delegate;
+import com.android.util.PropertiesMap;
 
 import android.view.View;
 import android.view.ViewGroup;
@@ -70,6 +71,11 @@
     }
 
     @Override
+    public Map<Object, PropertiesMap> getDefaultProperties() {
+        return mSession.getDefaultProperties();
+    }
+
+    @Override
     public Result render(long timeout, boolean forceMeasure) {
         try {
             Bridge.prepareThread();
@@ -196,10 +202,6 @@
         }
     }
 
-    public RenderSessionImpl getSessionImpl() {
-        return mSession;
-    }
-
     /*package*/ BridgeRenderSession(RenderSessionImpl scene, Result lastResult) {
         mSession = scene;
         if (scene != null) {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index fd95bd5..80e230c 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -27,12 +27,13 @@
 import com.android.ide.common.rendering.api.StyleResourceValue;
 import com.android.layoutlib.bridge.Bridge;
 import com.android.layoutlib.bridge.BridgeConstants;
-import com.android.layoutlib.bridge.android.PropertiesMap.Property;
 import com.android.layoutlib.bridge.android.view.WindowManagerImpl;
 import com.android.layoutlib.bridge.impl.ParserFactory;
 import com.android.layoutlib.bridge.impl.Stack;
 import com.android.resources.ResourceType;
 import com.android.util.Pair;
+import com.android.util.PropertiesMap;
+import com.android.util.PropertiesMap.Property;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -153,7 +154,6 @@
     private IBinder mBinder;
     private PackageManager mPackageManager;
 
-
     /**
      * Some applications that target both pre API 17 and post API 17, set the newer attrs to
      * reference the older ones. For example, android:paddingStart will resolve to
@@ -276,8 +276,8 @@
         return mRenderResources;
     }
 
-    public PropertiesMap getDefaultPropMap(Object key) {
-        return mDefaultPropMaps.get(key);
+    public Map<Object, PropertiesMap> getDefaultProperties() {
+        return mDefaultPropMaps;
     }
 
     public Configuration getConfiguration() {
@@ -1862,7 +1862,6 @@
         return false;
     }
 
-
     /**
      * The cached value depends on
      * <ol>
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/PropertiesMap.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/PropertiesMap.java
deleted file mode 100644
index a38d579..0000000
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/PropertiesMap.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * 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.layoutlib.bridge.android;
-
-import com.android.layoutlib.bridge.android.PropertiesMap.Property;
-
-import java.util.HashMap;
-
-/**
- * An alias used for the value in {@link BridgeContext#mDefaultPropMaps}
- */
-public class PropertiesMap extends HashMap<String, Property> {
-
-    public static class Property {
-        public final String resource;
-        public final String value;
-
-        public Property(String resource, String value) {
-            this.resource = resource;
-            this.value = value;
-        }
-    }
-}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
index 2d38831..0c53753 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
@@ -286,7 +286,7 @@
         return mParams;
     }
 
-    public BridgeContext getContext() {
+    protected BridgeContext getContext() {
         return mContext;
     }
 
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
index 11fabc6..3ef568c 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
@@ -48,6 +48,7 @@
 import com.android.resources.ResourceType;
 import com.android.tools.layoutlib.java.System_Delegate;
 import com.android.util.Pair;
+import com.android.util.PropertiesMap;
 
 import android.animation.AnimationThread;
 import android.animation.Animator;
@@ -1415,6 +1416,10 @@
         return mSystemViewInfoList;
     }
 
+    public Map<Object, PropertiesMap> getDefaultProperties() {
+        return getContext().getDefaultProperties();
+    }
+
     public void setScene(RenderSession session) {
         mScene = session;
     }