Merge "Notification cleanup"
diff --git a/api/current.txt b/api/current.txt
index d474464..d42be65 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5667,6 +5667,7 @@
     method public int describeContents();
     method public void setActions(java.util.List<android.app.RemoteAction>);
     method public void setAspectRatio(float);
+    method public void setSourceRectHint(android.graphics.Rect);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.PictureInPictureArgs> CREATOR;
   }
diff --git a/api/system-current.txt b/api/system-current.txt
index 5923261..cd71f1e 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -5859,6 +5859,7 @@
     method public int describeContents();
     method public void setActions(java.util.List<android.app.RemoteAction>);
     method public void setAspectRatio(float);
+    method public void setSourceRectHint(android.graphics.Rect);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.PictureInPictureArgs> CREATOR;
   }
@@ -11393,6 +11394,7 @@
     field public static final int INSTALL_FAILED_PACKAGE_CHANGED = -23; // 0xffffffe9
     field public static final int INSTALL_FAILED_PERMISSION_MODEL_DOWNGRADE = -26; // 0xffffffe6
     field public static final int INSTALL_FAILED_REPLACE_COULDNT_DELETE = -10; // 0xfffffff6
+    field public static final int INSTALL_FAILED_SANDBOX_VERSION_DOWNGRADE = -27; // 0xffffffe5
     field public static final int INSTALL_FAILED_SHARED_USER_INCOMPATIBLE = -8; // 0xfffffff8
     field public static final int INSTALL_FAILED_TEST_ONLY = -15; // 0xfffffff1
     field public static final int INSTALL_FAILED_UPDATE_INCOMPATIBLE = -7; // 0xfffffff9
diff --git a/api/test-current.txt b/api/test-current.txt
index 3c5bb26..a3a6161 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -5678,6 +5678,7 @@
     method public int describeContents();
     method public void setActions(java.util.List<android.app.RemoteAction>);
     method public void setAspectRatio(float);
+    method public void setSourceRectHint(android.graphics.Rect);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.PictureInPictureArgs> CREATOR;
   }
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index 6d4b812..2a2fdbd 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -336,7 +336,7 @@
      *
      * @see #addOnAccountsUpdatedListener
      *
-     * @deprecated use #addOnAccountsUpdatedListener to get account updates in runtime.
+     * @deprecated use {@link #addOnAccountsUpdatedListener} to get account updates in runtime.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     @BroadcastBehavior(includeBackground = true)
@@ -888,9 +888,9 @@
      * This method requires the caller to have a signature match with the authenticator that owns
      * the specified account.
      *
-     * @param account The account for which visibility data should be returned.
+     * @param account The account for which visibility data should be returned
      *
-     * @return Map from package names to visibility for given account.
+     * @return Map from package names to visibility for given account
      */
     public Map<String, Integer> getPackagesAndVisibilityForAccount(Account account) {
         try {
@@ -913,11 +913,11 @@
      *
      * <p>
      *
-     * @param packageName Package name.
-     * @param accountType Account type.
+     * @param packageName Package name
+     * @param accountType {@link Account} type
      *
-     * @return Map with visibility for all accounts of given type.
-     * See {@link #getAccountVisibility} for possilbe values.
+     * @return Map with visibility for all accounts of given type
+     * See {@link #getAccountVisibility} for possible values
      */
     public Map<Account, Integer> getAccountsAndVisibilityForPackage(String packageName,
             String accountType) {
@@ -932,7 +932,7 @@
     }
 
     /**
-     * Set visibility value of given account to certain packageName.
+     * Set visibility value of given account to certain package.
      * Package name must match installed application, or be equal to
      * {@link #PACKAGE_NAME_KEY_LEGACY_VISIBLE} or {@link #PACKAGE_NAME_KEY_LEGACY_NOT_VISIBLE}.
      * <p>
@@ -948,11 +948,11 @@
      * This method requires the caller to have a signature match with the authenticator that owns
      * the specified account.
      *
-     * @param account Account to update visibility
-     * @param packageName Package name of the application to modify account visibility.
-     * @param visibility - new visibility value.
+     * @param account {@link Account} to update visibility
+     * @param packageName Package name of the application to modify account visibility
+     * @param visibility New visibility value
      *
-     * @return True if visibility value was succesfully updated.
+     * @return True, if visibility value was successfully updated.
      */
     public boolean setAccountVisibility(Account account, String packageName,
             @AccountVisibility int visibility) {
@@ -978,10 +978,10 @@
      * This method requires the caller to have a signature match with the authenticator that owns
      * the specified account.
      *
-     * @param account Account to get visibility.
+     * @param account {@link Account} to get visibility
      * @param packageName Package name of the application to get account visibility
      *
-     * @return int Visibility for given account and package.
+     * @return int Visibility of given account.
      */
     public @AccountVisibility int getAccountVisibility(Account account, String packageName) {
         if (account == null)
diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java
index 1294325..0e8326d 100644
--- a/core/java/android/app/ActionBar.java
+++ b/core/java/android/app/ActionBar.java
@@ -1069,6 +1069,11 @@
     }
 
     /** @hide */
+    public boolean closeOptionsMenu() {
+        return false;
+    }
+
+    /** @hide */
     public boolean invalidateOptionsMenu() {
         return false;
     }
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index e149868..4fd3f39 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -3557,7 +3557,8 @@
      * closed, this method does nothing.
      */
     public void closeOptionsMenu() {
-        if (mWindow.hasFeature(Window.FEATURE_OPTIONS_PANEL)) {
+        if (mWindow.hasFeature(Window.FEATURE_OPTIONS_PANEL) &&
+                (mActionBar == null || !mActionBar.closeOptionsMenu())) {
             mWindow.closePanel(Window.FEATURE_OPTIONS_PANEL);
         }
     }
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index e89dc0b..b4e6bd5 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -808,6 +808,11 @@
         public final void scheduleReceiver(Intent intent, ActivityInfo info,
                 CompatibilityInfo compatInfo, int resultCode, String data, Bundle extras,
                 boolean sync, int sendingUser, int processState) {
+            // TODO: Debugging added for bug:36406078 . Remove when done
+            if (Log.isLoggable("36406078", Log.DEBUG)) {
+                Log.d(TAG, "scheduleReceiver");
+            }
+
             updateProcessState(processState, false);
             ReceiverData r = new ReceiverData(intent, resultCode, data, extras,
                     sync, false, mAppThread.asBinder(), sendingUser);
@@ -894,6 +899,11 @@
                 CompatibilityInfo compatInfo, Map services, Bundle coreSettings,
                 String buildSerial) {
 
+            // TODO: Debugging added for bug:36406078 . Remove when done
+            if (Log.isLoggable("36406078", Log.DEBUG)) {
+                Log.d(TAG, "bindApplication: " + processName);
+            }
+
             if (services != null) {
                 // Setup the service cache in the ServiceManager
                 ServiceManager.initServiceCache(services);
@@ -3229,6 +3239,10 @@
         if (receiver.getPendingResult() != null) {
             data.finish();
         }
+        // TODO: Debugging added for bug:36406078 . Remove when done
+        if (Log.isLoggable("36406078", Log.DEBUG)) {
+            Log.d(TAG, "handleReceiver done");
+        }
     }
 
     // Instantiate a BackupAgent and tell it that it's alive
@@ -5764,6 +5778,10 @@
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
+        // TODO: Debugging added for bug:36406078 . Remove when done
+        if (Log.isLoggable("36406078", Log.DEBUG)) {
+            Log.d(TAG, "handleBindApplication done");
+        }
     }
 
     /*package*/ final void finishInstrumentation(int resultCode, Bundle results) {
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index 5ea2480..43cad5b 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -57,6 +57,7 @@
 
     void createNotificationChannelGroups(String pkg, in ParceledListSlice channelGroupList);
     void createNotificationChannels(String pkg, in ParceledListSlice channelsList);
+    void createNotificationChannelsForPackage(String pkg, int uid, in ParceledListSlice channelsList);
     ParceledListSlice getNotificationChannelGroupsForPackage(String pkg, int uid, boolean includeDeleted);
     NotificationChannelGroup getNotificationChannelGroupForPackage(String groupId, String pkg, int uid);
     void updateNotificationChannelForPackage(String pkg, int uid, in NotificationChannel channel);
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 097df31..75998f2 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -453,19 +453,6 @@
     }
 
     /**
-     * @hide
-     */
-    public void createNotificationChannelsForPackage(String pkg,
-            @NonNull List<NotificationChannel> channels) {
-        INotificationManager service = getService();
-        try {
-            service.createNotificationChannels(pkg, new ParceledListSlice(channels));
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
-    }
-
-    /**
      * Returns the notification channel settings for a given channel id.
      */
     public NotificationChannel getNotificationChannel(String channelId) {
diff --git a/core/java/android/app/PictureInPictureArgs.java b/core/java/android/app/PictureInPictureArgs.java
index fbdcbf4..0ce5eeb 100644
--- a/core/java/android/app/PictureInPictureArgs.java
+++ b/core/java/android/app/PictureInPictureArgs.java
@@ -17,6 +17,7 @@
 package android.app;
 
 import android.annotation.Nullable;
+import android.graphics.Rect;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -35,11 +36,19 @@
     private Float mAspectRatio;
 
     /**
-     * The set of actions that are associated with this activity when in picture in picture.
+     * The set of actions that are associated with this activity when in picture-in-picture.
      */
     @Nullable
     private List<RemoteAction> mUserActions;
 
+    /**
+     * The source bounds hint used when entering picture-in-picture, relative to the window bounds.
+     * We can use this internally for the transition into picture-in-picture to ensure that a
+     * particular source rect is visible throughout the whole transition.
+     */
+    @Nullable
+    private Rect mSourceRectHint;
+
     PictureInPictureArgs(Parcel in) {
         if (in.readInt() != 0) {
             mAspectRatio = in.readFloat();
@@ -48,6 +57,9 @@
             mUserActions = new ArrayList<>();
             in.readParcelableList(mUserActions, RemoteAction.class.getClassLoader());
         }
+        if (in.readInt() != 0) {
+            mSourceRectHint = Rect.CREATOR.createFromParcel(in);
+        }
     }
 
     /**
@@ -79,6 +91,9 @@
         if (otherArgs.hasSetActions()) {
             mUserActions = otherArgs.mUserActions;
         }
+        if (otherArgs.hasSourceBoundsHint()) {
+            mSourceRectHint = new Rect(otherArgs.getSourceRectHint());
+        }
     }
 
     /**
@@ -137,9 +152,43 @@
         return mUserActions != null;
     }
 
+    /**
+     * Sets the source bounds hint. These bounds are only used when an activity first enters
+     * picture-in-picture, and describe the bounds in window coordinates of activity entering
+     * picture-in-picture that will be visible following the transition. For the best effect, these
+     * bounds should also match the aspect ratio in the arguments.
+     */
+    public void setSourceRectHint(Rect launchBounds) {
+        if (launchBounds == null) {
+            mSourceRectHint = null;
+        } else {
+            mSourceRectHint = new Rect(launchBounds);
+        }
+    }
+
+    /**
+     * @return the launch bounds
+     * @hide
+     */
+    public Rect getSourceRectHint() {
+        return mSourceRectHint;
+    }
+
+    /**
+     * @return whether there are launch bounds set
+     * @hide
+     */
+    public boolean hasSourceBoundsHint() {
+        return mSourceRectHint != null && !mSourceRectHint.isEmpty();
+    }
+
     @Override
     public PictureInPictureArgs clone() {
-        return new PictureInPictureArgs(mAspectRatio, mUserActions);
+        PictureInPictureArgs args = new PictureInPictureArgs(mAspectRatio, mUserActions);
+        if (mSourceRectHint != null) {
+            args.setSourceRectHint(mSourceRectHint);
+        }
+        return args;
     }
 
     @Override
@@ -161,6 +210,12 @@
         } else {
             out.writeInt(0);
         }
+        if (mSourceRectHint != null) {
+            out.writeInt(1);
+            mSourceRectHint.writeToParcel(out, 0);
+        } else {
+            out.writeInt(0);
+        }
     }
 
     public static final Creator<PictureInPictureArgs> CREATOR =
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index bb35928..71db5d3 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -1069,6 +1069,16 @@
     public static final int INSTALL_FAILED_PERMISSION_MODEL_DOWNGRADE = -26;
 
     /**
+     * Installation return code: this is passed to the
+     * {@link IPackageInstallObserver} if the new package attempts to downgrade the
+     * target sandbox version of the app.
+     *
+     * @hide
+     */
+    @SystemApi
+    public static final int INSTALL_FAILED_SANDBOX_VERSION_DOWNGRADE = -27;
+
+    /**
      * Installation parse return code: this is passed to the
      * {@link IPackageInstallObserver} if the parser was given a path that is
      * not a file, or does not end with the expected '.apk' extension.
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index 6dedbde..5494377 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -50,7 +50,7 @@
  * <li>The real display area specifies the part of the display that contains content
  * including the system decorations.  Even so, the real display area may be smaller than the
  * physical size of the display if the window manager is emulating a smaller display
- * using (adb shell wm size).  Use the following methods to query the
+ * using (adb shell am display-size).  Use the following methods to query the
  * real display area: {@link #getRealSize}, {@link #getRealMetrics}.</li>
  * </ul>
  * </p><p>
@@ -947,7 +947,7 @@
      * The size is adjusted based on the current rotation of the display.
      * </p><p>
      * The real size may be smaller than the physical size of the screen when the
-     * window manager is emulating a smaller display (using adb shell wm size).
+     * window manager is emulating a smaller display (using adb shell am display-size).
      * </p>
      *
      * @param outSize Set to the real size of the display.
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index f559d42..e590739 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -114,6 +114,9 @@
     SurfaceSession mSurfaceSession;
 
     SurfaceControl mSurfaceControl;
+    // In the case of format changes we switch out the surface in-place
+    // we need to preserve the old one until the new one has drawn.
+    SurfaceControl mDeferredDestroySurfaceControl;
     final Rect mTmpRect = new Rect();
     final Configuration mConfiguration = new Configuration();
 
@@ -475,6 +478,7 @@
 
                 if (creating) {
                     mSurfaceSession = new SurfaceSession(viewRoot.mSurface);
+                    mDeferredDestroySurfaceControl = mSurfaceControl;
                     mSurfaceControl = new SurfaceControl(mSurfaceSession,
                             "SurfaceView - " + viewRoot.getTitle().toString(),
                             mSurfaceWidth, mSurfaceHeight, mFormat,
@@ -676,6 +680,12 @@
             Log.i(TAG, System.identityHashCode(this) + " "
                     + "finishedDrawing");
         }
+
+        if (mDeferredDestroySurfaceControl != null) {
+            mDeferredDestroySurfaceControl.destroy();
+            mDeferredDestroySurfaceControl = null;
+        }
+
         mHandler.sendEmptyMessage(DRAW_FINISHED_MSG);
     }
 
diff --git a/core/java/com/android/internal/app/ToolbarActionBar.java b/core/java/com/android/internal/app/ToolbarActionBar.java
index 74424f6..7ce5fc3 100644
--- a/core/java/com/android/internal/app/ToolbarActionBar.java
+++ b/core/java/com/android/internal/app/ToolbarActionBar.java
@@ -419,6 +419,11 @@
     }
 
     @Override
+    public boolean closeOptionsMenu() {
+        return mDecorToolbar.hideOverflowMenu();
+    }
+
+    @Override
     public boolean invalidateOptionsMenu() {
         mDecorToolbar.getViewGroup().removeCallbacks(mMenuInvalidator);
         mDecorToolbar.getViewGroup().postOnAnimation(mMenuInvalidator);
diff --git a/core/java/com/android/internal/notification/SystemNotificationChannels.java b/core/java/com/android/internal/notification/SystemNotificationChannels.java
index c840f26..ef20750 100644
--- a/core/java/com/android/internal/notification/SystemNotificationChannels.java
+++ b/core/java/com/android/internal/notification/SystemNotificationChannels.java
@@ -14,10 +14,13 @@
 
 package com.android.internal.notification;
 
+import android.app.INotificationManager;
 import android.app.Notification;
 import android.app.NotificationChannel;
 import android.app.NotificationManager;
 import android.content.Context;
+import android.content.pm.ParceledListSlice;
+import android.os.RemoteException;
 import android.provider.Settings;
 
 import com.android.internal.R;
@@ -69,6 +72,8 @@
                 context.getString(R.string.notification_channel_car_mode),
                 NotificationManager.IMPORTANCE_LOW));
 
+        channelsList.add(newAccountChannel(context));
+
         channelsList.add(new NotificationChannel(
                 DEVELOPER,
                 context.getString(R.string.notification_channel_developer),
@@ -121,15 +126,23 @@
                 NotificationManager.IMPORTANCE_MIN));
 
         nm.createNotificationChannels(channelsList);
-        createAccountChannelForPackage(context.getPackageName(), context);
     }
 
-    public static void createAccountChannelForPackage(String pkg, Context context) {
-        final NotificationManager nm = context.getSystemService(NotificationManager.class);
-        nm.createNotificationChannelsForPackage(pkg, Arrays.asList(new NotificationChannel(
+    public static void createAccountChannelForPackage(String pkg, int uid, Context context) {
+        final INotificationManager iNotificationManager = NotificationManager.getService();
+        try {
+            iNotificationManager.createNotificationChannelsForPackage(pkg, uid,
+                    new ParceledListSlice(Arrays.asList(newAccountChannel(context))));
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    private static NotificationChannel newAccountChannel(Context context) {
+        return new NotificationChannel(
                 ACCOUNT,
                 context.getString(R.string.notification_channel_account),
-                NotificationManager.IMPORTANCE_LOW)));
+                NotificationManager.IMPORTANCE_LOW);
     }
 
     private SystemNotificationChannels() {}
diff --git a/core/java/com/android/internal/view/menu/CascadingMenuPopup.java b/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
index 1de0af6..ebcec5c 100644
--- a/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
+++ b/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
@@ -441,9 +441,11 @@
 
         popupWindow.show();
 
+        final ListView listView = popupWindow.getListView();
+        listView.setOnKeyListener(this);
+
         // If this is the root menu, show the title if requested.
         if (parentInfo == null && mShowTitle && menu.getHeaderTitle() != null) {
-            final ListView listView = popupWindow.getListView();
             final FrameLayout titleItemView = (FrameLayout) inflater.inflate(
                     R.layout.popup_menu_header_item_layout, listView, false);
             final TextView titleView = (TextView) titleItemView.findViewById(R.id.title);
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 64e1620e..da5d04d 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -212,6 +212,7 @@
     external/giflib \
     external/pdfium/public \
     external/skia/include/private \
+    external/skia/src/codec \
     external/skia/src/core \
     external/skia/src/effects \
     external/skia/src/image \
diff --git a/packages/SettingsLib/res/values/arrays.xml b/packages/SettingsLib/res/values/arrays.xml
index 9ff22c7..0bf1fa4 100644
--- a/packages/SettingsLib/res/values/arrays.xml
+++ b/packages/SettingsLib/res/values/arrays.xml
@@ -102,6 +102,19 @@
 
 
     <!-- Bluetooth settings -->
+    <!-- Titles for Bluetooth AVRCP Versions -->
+    <string-array name="bluetooth_avrcp_versions">
+        <item>AVRCP 1.4 (Default)</item>
+        <item>AVRCP 1.5</item>
+        <item>AVRCP 1.6</item>
+    </string-array>
+
+    <!-- Values for Bluetooth AVRCP Versions -->
+    <string-array name="bluetooth_avrcp_version_values">
+        <item>avrcp14</item>
+        <item>avrcp15</item>
+        <item>avrcp16</item>
+    </string-array>
 
     <!-- Titles for Bluetooth Audio Codec selection preference. [CHAR LIMIT=50] -->
     <string-array name="bluetooth_a2dp_codec_titles">
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index f6c5ade..ca34bb9 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -432,6 +432,11 @@
     <!-- Setting Checkbox title for disabling Bluetooth absolute volume -->
     <string name="bluetooth_disable_absolute_volume">Disable absolute volume</string>
 
+    <!-- UI debug setting: Select Bluetooth AVRCP Version -->
+    <string name="bluetooth_select_avrcp_version_string">Bluetooth AVRCP Version</string>
+    <!-- UI debug setting: Select Bluetooth AVRCP Version -->
+    <string name="bluetooth_select_avrcp_version_dialog_title">Select Bluetooth AVRCP Version</string>
+
     <!-- UI debug setting: Select Bluetooth Audio Codec -->
     <string name="bluetooth_select_a2dp_codec_type">Bluetooth Audio Codec</string>
     <!-- UI debug setting: Select Bluetooth Audio Codec -->
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 490e63d..01fc8ec 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -3697,11 +3697,11 @@
         if (ArrayUtils.isEmpty(packageNames)) {
             return null;
         }
-        // For app op checks related to permissions all packages in the UID
-        // have the same app op state, so doesn't matter which one we pick.
-        // Update: due to visibility changes we want to use package with oldest target SDK,
-
         String packageName = packageNames[0];
+        if (packageNames.length == 1) {
+            return packageName;
+        }
+        // Due to visibility changes we want to use package with oldest target SDK
         int oldestVersion = Integer.MAX_VALUE;
         for (String name : packageNames) {
             try {
@@ -5677,7 +5677,7 @@
             synchronized (mUsers) {
                 userAccounts = mUsers.get(userId);
             }
-            SystemNotificationChannels.createAccountChannelForPackage(packageName, mContext);
+            SystemNotificationChannels.createAccountChannelForPackage(packageName, uid, mContext);
             doNotification(userAccounts, account, null, intent, packageName, userId);
         }
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 2be5e77..92a4b78 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -7870,10 +7870,11 @@
                     r.pictureInPictureArgs.copyOnlySet(args);
                     final float aspectRatio = r.pictureInPictureArgs.getAspectRatio();
                     final List<RemoteAction> actions = r.pictureInPictureArgs.getActions();
-                    final Rect bounds = mWindowManager.getPictureInPictureBounds(DEFAULT_DISPLAY,
+                    final Rect sourceBounds = r.pictureInPictureArgs.getSourceRectHint();
+                    final Rect destBounds = mWindowManager.getPictureInPictureBounds(DEFAULT_DISPLAY,
                             aspectRatio);
-                    mStackSupervisor.moveActivityToPinnedStackLocked(r, "enterPictureInPictureMode",
-                            bounds, true /* moveHomeStackToFront */);
+                    mStackSupervisor.moveActivityToPinnedStackLocked(r, sourceBounds, destBounds,
+                            true /* moveHomeStackToFront */, "enterPictureInPictureMode");
                     final PinnedActivityStack stack = mStackSupervisor.getStack(PINNED_STACK_ID);
                     stack.setPictureInPictureAspectRatio(aspectRatio);
                     stack.setPictureInPictureActions(actions);
@@ -10525,7 +10526,7 @@
     }
 
     @Override
-    public void resizeStack(int stackId, Rect bounds, boolean allowResizeInDockedMode,
+    public void resizeStack(int stackId, Rect destBounds, boolean allowResizeInDockedMode,
             boolean preserveWindows, boolean animate, int animationDuration) {
         enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "resizeStack()");
         long ident = Binder.clearCallingIdentity();
@@ -10535,13 +10536,14 @@
                     if (stackId == PINNED_STACK_ID) {
                         final PinnedActivityStack pinnedStack =
                                 mStackSupervisor.getStack(PINNED_STACK_ID);
-                        pinnedStack.animateResizePinnedStack(bounds, animationDuration);
+                        pinnedStack.animateResizePinnedStack(null /* sourceBounds */, destBounds,
+                                animationDuration);
                     } else {
                         throw new IllegalArgumentException("Stack: " + stackId
                                 + " doesn't support animated resize.");
                     }
                 } else {
-                    mStackSupervisor.resizeStackLocked(stackId, bounds, null /* tempTaskBounds */,
+                    mStackSupervisor.resizeStackLocked(stackId, destBounds, null /* tempTaskBounds */,
                             null /* tempTaskInsetBounds */, preserveWindows,
                             allowResizeInDockedMode, !DEFER_RESUME);
                 }
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 5c49dfd..97d0aa3 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -2295,17 +2295,8 @@
         mResizingTasksDuringAnimation.clear();
     }
 
-    private class MoveTaskToFullscreenArgs {
-        public int fromStackId;
-        public boolean onTop;
-    };
-    // Used only to closure over the arguments to moveTasksToFullscreenStack without
-    // allocation
-    private MoveTaskToFullscreenArgs mMoveToFullscreenArgs = new MoveTaskToFullscreenArgs();
-
-    private void moveTasksToFullscreenStackInnerLocked() {
-        int fromStackId = mMoveToFullscreenArgs.fromStackId;
-        boolean onTop = mMoveToFullscreenArgs.onTop;
+    private void moveTasksToFullscreenStackInSurfaceTransaction(int fromStackId,
+            boolean onTop) {
 
         final ActivityStack stack = getStack(fromStackId);
         if (stack == null) {
@@ -2379,10 +2370,8 @@
     }
 
     void moveTasksToFullscreenStackLocked(int fromStackId, boolean onTop) {
-        mMoveToFullscreenArgs.fromStackId = fromStackId;
-        mMoveToFullscreenArgs.onTop = onTop;
-
-        mWindowManager.inSurfaceTransaction(this::moveTasksToFullscreenStackInnerLocked);
+        mWindowManager.inSurfaceTransaction(
+                () -> moveTasksToFullscreenStackInSurfaceTransaction(fromStackId, onTop));
     }
 
     void resizeDockedStackLocked(Rect dockedBounds, Rect tempDockedTaskBounds,
@@ -2498,11 +2487,7 @@
     }
 
 
-    // Used only to closure over the argument to removeStack without allocation.
-    private int mRemoveStackStackId;
-    void removeStackInnerLocked() {
-        int stackId = mRemoveStackStackId;
-
+    void removeStackInSurfaceTransaction(int stackId) {
         final ActivityStack stack = getStack(stackId);
         if (stack == null) {
             return;
@@ -2546,8 +2531,8 @@
      * instead moved back onto the fullscreen stack.
      */
     void removeStackLocked(int stackId) {
-        mRemoveStackStackId = stackId;
-        mWindowManager.inSurfaceTransaction(this::removeStackInnerLocked);
+        mWindowManager.inSurfaceTransaction(
+                () -> removeStackInSurfaceTransaction(stackId));
     }
 
     /**
@@ -2794,7 +2779,7 @@
         }
     }
 
-    boolean moveTopStackActivityToPinnedStackLocked(int stackId, Rect bounds) {
+    boolean moveTopStackActivityToPinnedStackLocked(int stackId, Rect destBounds) {
         final ActivityStack stack = getStack(stackId, !CREATE_IF_NEEDED, !ON_TOP);
         if (stack == null) {
             throw new IllegalArgumentException(
@@ -2815,13 +2800,14 @@
             return false;
         }
 
-        moveActivityToPinnedStackLocked(r, "moveTopActivityToPinnedStack", bounds,
-                true /* moveHomeStackToFront */);
+        moveActivityToPinnedStackLocked(r, null /* sourceBounds */, destBounds,
+                true /* moveHomeStackToFront */, "moveTopActivityToPinnedStack");
         return true;
     }
 
-    void moveActivityToPinnedStackLocked(ActivityRecord r, String reason, Rect bounds,
-            boolean moveHomeStackToFront) {
+    void moveActivityToPinnedStackLocked(ActivityRecord r, Rect sourceBounds, Rect destBounds,
+            boolean moveHomeStackToFront, String reason) {
+
         mWindowManager.deferSurfaceLayout();
 
         // Need to make sure the pinned stack exist so we can resize it below...
@@ -2889,7 +2875,7 @@
         ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
         resumeFocusedStackTopActivityLocked();
 
-        stack.animateResizePinnedStack(bounds, -1 /* animationDuration */);
+        stack.animateResizePinnedStack(sourceBounds, destBounds, -1 /* animationDuration */);
         mService.mTaskChangeNotificationController.notifyActivityPinned(r.packageName);
     }
 
diff --git a/services/core/java/com/android/server/am/PinnedActivityStack.java b/services/core/java/com/android/server/am/PinnedActivityStack.java
index 1708fe5..32d3082 100644
--- a/services/core/java/com/android/server/am/PinnedActivityStack.java
+++ b/services/core/java/com/android/server/am/PinnedActivityStack.java
@@ -41,8 +41,9 @@
         return new PinnedStackWindowController(mStackId, this, displayId, onTop, outBounds);
     }
 
-    void animateResizePinnedStack(Rect bounds, int animationDuration) {
-        getWindowContainerController().animateResizePinnedStack(bounds, animationDuration);
+    void animateResizePinnedStack(Rect sourceBounds, Rect destBounds, int animationDuration) {
+        getWindowContainerController().animateResizePinnedStack(sourceBounds, destBounds,
+                animationDuration);
     }
 
     void setPictureInPictureAspectRatio(float aspectRatio) {
diff --git a/services/core/java/com/android/server/display/LogicalDisplay.java b/services/core/java/com/android/server/display/LogicalDisplay.java
index f9bc12b..a947b41 100644
--- a/services/core/java/com/android/server/display/LogicalDisplay.java
+++ b/services/core/java/com/android/server/display/LogicalDisplay.java
@@ -62,18 +62,7 @@
 
     private final int mDisplayId;
     private final int mLayerStack;
-    /**
-     * Override information set by the window manager. Will be reported instead of {@link #mInfo}
-     * if not null.
-     * @see #setDisplayInfoOverrideFromWindowManagerLocked(DisplayInfo)
-     * @see #getDisplayInfoLocked()
-     */
-    private DisplayInfo mOverrideDisplayInfo;
-    /**
-     * Current display info. Initialized with {@link #mBaseDisplayInfo}. Set to {@code null} if
-     * needs to be updated.
-     * @see #getDisplayInfoLocked()
-     */
+    private DisplayInfo mOverrideDisplayInfo; // set by the window manager
     private DisplayInfo mInfo;
 
     // The display device that this logical display is based on and which
@@ -272,9 +261,6 @@
 
             mPrimaryDisplayDeviceInfo = deviceInfo;
             mInfo = null;
-            // Make sure that WM will be notified of new changes. It will then decide whether to
-            // apply them or not and will set the value again.
-            mOverrideDisplayInfo = null;
         }
     }
 
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 408f85e..a1aeeea 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1633,22 +1633,34 @@
             savePolicyFile();
         }
 
-        @Override
-        public void createNotificationChannels(String pkg,
-                ParceledListSlice channelsList) throws RemoteException {
-            checkCallerIsSystemOrSameApp(pkg);
+        private void createNotificationChannelsImpl(String pkg, int uid,
+                ParceledListSlice channelsList) {
             List<NotificationChannel> channels = channelsList.getList();
             final int channelsSize = channels.size();
             for (int i = 0; i < channelsSize; i++) {
                 final NotificationChannel channel = channels.get(i);
                 Preconditions.checkNotNull(channel, "channel in list is null");
-                mRankingHelper.createNotificationChannel(pkg, Binder.getCallingUid(), channel,
+                mRankingHelper.createNotificationChannel(pkg, uid, channel,
                         true /* fromTargetApp */);
             }
             savePolicyFile();
         }
 
         @Override
+        public void createNotificationChannels(String pkg,
+                ParceledListSlice channelsList) throws RemoteException {
+            checkCallerIsSystemOrSameApp(pkg);
+            createNotificationChannelsImpl(pkg, Binder.getCallingUid(), channelsList);
+        }
+
+        @Override
+        public void createNotificationChannelsForPackage(String pkg, int uid,
+                ParceledListSlice channelsList) throws RemoteException {
+            checkCallerIsSystem();
+            createNotificationChannelsImpl(pkg, uid, channelsList);
+        }
+
+        @Override
         public NotificationChannel getNotificationChannel(String pkg, String channelId) {
             checkCallerIsSystemOrSameApp(pkg);
             return mRankingHelper.getNotificationChannel(
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 96e2626..25f9c30 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -16692,6 +16692,16 @@
                                         + " target SDK " + oldTargetSdk + " does.");
                         return;
                     }
+                    // Prevent apps from downgrading their targetSandbox.
+                    final int oldTargetSandbox = oldPackage.applicationInfo.targetSandboxVersion;
+                    final int newTargetSandbox = pkg.applicationInfo.targetSandboxVersion;
+                    if (oldTargetSandbox == 2 && newTargetSandbox != 2) {
+                        res.setError(PackageManager.INSTALL_FAILED_SANDBOX_VERSION_DOWNGRADE,
+                                "Package " + pkg.packageName + " new target sandbox "
+                                + newTargetSandbox + " is incompatible with the previous value of"
+                                + oldTargetSandbox + ".");
+                        return;
+                    }
 
                     // Prevent installing of child packages
                     if (oldPackage.parentPackage != null) {
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 111fbd3f..d1f1305 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -368,6 +368,10 @@
                 mEnteringAnimation = true;
                 mService.mActivityManagerAppTransitionNotifier.onAppTransitionFinishedLocked(token);
             }
+            // If we are hidden but there is no delay needed we immediately
+            // apply the Surface transaction so that the ActivityManager
+            // can have some guarantee on the Surface state
+            // following setting the visibility.
             if (hidden && !delayed) {
                 SurfaceControl.openTransaction();
                 for (int i = mChildren.size() - 1; i >= 0; i--) {
diff --git a/services/core/java/com/android/server/wm/BoundsAnimationController.java b/services/core/java/com/android/server/wm/BoundsAnimationController.java
index cd0e6cc..62414e5 100644
--- a/services/core/java/com/android/server/wm/BoundsAnimationController.java
+++ b/services/core/java/com/android/server/wm/BoundsAnimationController.java
@@ -121,8 +121,8 @@
         private final int mFrozenTaskWidth;
         private final int mFrozenTaskHeight;
 
-        BoundsAnimator(AnimateBoundsUser target, Rect from, Rect to,
-                boolean moveToFullScreen, boolean replacement) {
+        BoundsAnimator(AnimateBoundsUser target, Rect from, Rect to, boolean moveToFullScreen,
+                boolean replacement) {
             super();
             mTarget = target;
             mFrom.set(from);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 01a992f..e5b00f3 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -179,23 +179,11 @@
     // Mapping from a token IBinder to a WindowToken object on this display.
     private final HashMap<IBinder, WindowToken> mTokenMap = new HashMap();
 
-    // Initial display metrics.
     int mInitialDisplayWidth = 0;
     int mInitialDisplayHeight = 0;
     int mInitialDisplayDensity = 0;
-
-    /**
-     * Overridden display size. Initialized with {@link #mInitialDisplayWidth}
-     * and {@link #mInitialDisplayHeight}, but can be set via shell command "adb shell wm size".
-     * @see WindowManagerService#setForcedDisplaySize(int, int, int)
-     */
     int mBaseDisplayWidth = 0;
     int mBaseDisplayHeight = 0;
-    /**
-     * Overridden display density for current user. Initialized with {@link #mInitialDisplayDensity}
-     * but can be set from Settings or via shell command "adb shell wm density".
-     * @see WindowManagerService#setForcedDisplayDensityForUser(int, int, int)
-     */
     int mBaseDisplayDensity = 0;
     boolean mDisplayScalingDisabled;
     private final DisplayInfo mDisplayInfo = new DisplayInfo();
@@ -1523,10 +1511,6 @@
     void updateDisplayInfo() {
         mDisplay.getDisplayInfo(mDisplayInfo);
         mDisplay.getMetrics(mDisplayMetrics);
-
-        // Check if display metrics changed and update base values if needed.
-        updateBaseDisplayMetricsIfNeeded();
-
         for (int i = mTaskStackContainers.size() - 1; i >= 0; --i) {
             mTaskStackContainers.get(i).updateDisplayInfo(null);
         }
@@ -1542,11 +1526,10 @@
             }
         }
 
-        updateBaseDisplayMetrics(mDisplayInfo.logicalWidth, mDisplayInfo.logicalHeight,
-                mDisplayInfo.logicalDensityDpi);
-        mInitialDisplayWidth = mDisplayInfo.logicalWidth;
-        mInitialDisplayHeight = mDisplayInfo.logicalHeight;
-        mInitialDisplayDensity = mDisplayInfo.logicalDensityDpi;
+        mBaseDisplayWidth = mInitialDisplayWidth = mDisplayInfo.logicalWidth;
+        mBaseDisplayHeight = mInitialDisplayHeight = mDisplayInfo.logicalHeight;
+        mBaseDisplayDensity = mInitialDisplayDensity = mDisplayInfo.logicalDensityDpi;
+        mBaseDisplayRect.set(0, 0, mBaseDisplayWidth, mBaseDisplayHeight);
     }
 
     void getLogicalDisplayRect(Rect out) {
@@ -1576,50 +1559,6 @@
         }
     }
 
-    /**
-     * If display metrics changed, overrides are not set and it's not just a rotation - update base
-     * values.
-     */
-    private void updateBaseDisplayMetricsIfNeeded() {
-        final int orientation = mDisplayInfo.rotation;
-        final boolean rotated = (orientation == ROTATION_90 || orientation == ROTATION_270);
-        final int newWidth = rotated ? mDisplayInfo.logicalHeight : mDisplayInfo.logicalWidth;
-        final int newHeight = rotated ? mDisplayInfo.logicalWidth : mDisplayInfo.logicalHeight;
-        int density = mDisplayInfo.logicalDensityDpi;
-
-        boolean displayMetricsChanged = false;
-
-        // Check if display size is not forced and changed in new display info.
-        boolean isDisplaySizeForced = mBaseDisplayWidth != mInitialDisplayWidth
-                || mBaseDisplayHeight != mInitialDisplayHeight;
-        if (!isDisplaySizeForced) {
-            displayMetricsChanged = mBaseDisplayWidth != newWidth
-                    || mBaseDisplayHeight != newHeight;
-        }
-
-        // Check if display density is not forced and changed in new display info.
-        final int forcedDensity = mBaseDisplayDensity != mInitialDisplayDensity
-                ? mBaseDisplayDensity : 0;
-        if (forcedDensity != 0) {
-            density = forcedDensity;
-        } else {
-            displayMetricsChanged |= mBaseDisplayDensity != mDisplayInfo.logicalDensityDpi;
-        }
-
-        if (displayMetricsChanged) {
-            updateBaseDisplayMetrics(newWidth, newHeight, density);
-            mService.reconfigureDisplayLocked(this);
-        }
-    }
-
-    /** Update base (override) display metrics. */
-    void updateBaseDisplayMetrics(int baseWidth, int baseHeight, int baseDensity) {
-        mBaseDisplayWidth = baseWidth;
-        mBaseDisplayHeight = baseHeight;
-        mBaseDisplayDensity = baseDensity;
-        mBaseDisplayRect.set(0, 0, mBaseDisplayWidth, mBaseDisplayHeight);
-    }
-
     void getContentRect(Rect out) {
         out.set(mContentRect);
     }
diff --git a/services/core/java/com/android/server/wm/PinnedStackWindowController.java b/services/core/java/com/android/server/wm/PinnedStackWindowController.java
index 34ccf87..0145454 100644
--- a/services/core/java/com/android/server/wm/PinnedStackWindowController.java
+++ b/services/core/java/com/android/server/wm/PinnedStackWindowController.java
@@ -40,29 +40,30 @@
     /**
      * Animates the pinned stack.
      */
-    public void animateResizePinnedStack(Rect bounds, int animationDuration) {
+    public void animateResizePinnedStack(Rect sourceBounds, Rect destBounds,
+            int animationDuration) {
         synchronized (mWindowMap) {
             if (mContainer == null) {
                 throw new IllegalArgumentException("Pinned stack container not found :(");
             }
 
             // Get non-null fullscreen bounds if the bounds are null
-            final boolean moveToFullscreen = bounds == null;
-            bounds = getPinnedStackAnimationBounds(bounds);
+            final boolean moveToFullscreen = destBounds == null;
+            destBounds = getPinnedStackAnimationBounds(destBounds);
 
             // If the bounds are truly null, then there was no fullscreen stack at this time, so
             // animate this to the full display bounds
             final Rect toBounds;
-            if (bounds == null) {
+            if (destBounds == null) {
                 toBounds = new Rect();
                 mContainer.getDisplayContent().getLogicalDisplayRect(toBounds);
             } else {
-                toBounds = bounds;
+                toBounds = destBounds;
             }
 
             final Rect originalBounds = new Rect();
             mContainer.getBounds(originalBounds);
-            mContainer.setAnimatingBounds(toBounds);
+            mContainer.setAnimatingBounds(sourceBounds, toBounds);
             UiThread.getHandler().post(() -> {
                 if (mContainer == null) {
                     return;
@@ -82,13 +83,17 @@
                 return;
             }
 
+            final int displayId = mContainer.getDisplayContent().getDisplayId();
+            final Rect toBounds = mService.getPictureInPictureBounds(displayId, aspectRatio);
+            final Rect targetBounds = new Rect();
+            mContainer.getAnimatingBounds(targetBounds);
             final PinnedStackController pinnedStackController =
                     mContainer.getDisplayContent().getPinnedStackController();
 
             if (Float.compare(aspectRatio, pinnedStackController.getAspectRatio()) != 0) {
-                final int displayId = mContainer.getDisplayContent().getDisplayId();
-                final Rect toBounds = mService.getPictureInPictureBounds(displayId, aspectRatio);
-                animateResizePinnedStack(toBounds, -1 /* duration */);
+                if (!toBounds.equals(targetBounds)) {
+                    animateResizePinnedStack(null /* sourceBounds */, toBounds, -1 /* duration */);
+                }
                 pinnedStackController.setAspectRatio(
                         pinnedStackController.isValidPictureInPictureAspectRatio(aspectRatio)
                                 ? aspectRatio : -1f);
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 442cd54..dc437ea 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -19,7 +19,6 @@
 import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
 import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT;
 import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
-import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
 import static android.app.ActivityManager.StackId.HOME_STACK_ID;
 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
@@ -128,6 +127,7 @@
     private boolean mBoundsAnimating = false;
     private boolean mBoundsAnimatingToFullscreen = false;
     private Rect mBoundsAnimationTarget = new Rect();
+    private Rect mBoundsAnimationSourceBounds = new Rect();
 
     // Temporary storage for the new bounds that should be used after the configuration change.
     // Will be cleared once the client retrieves the new bounds via getBoundsForNewConfiguration().
@@ -323,15 +323,31 @@
      * Sets the bounds animation target bounds.  This can't currently be done in onAnimationStart()
      * since that is started on the UiThread.
      */
-    void setAnimatingBounds(Rect bounds) {
-        if (bounds != null) {
-            mBoundsAnimationTarget.set(bounds);
+    void setAnimatingBounds(Rect sourceBounds, Rect destBounds) {
+        if (sourceBounds != null) {
+            mBoundsAnimationSourceBounds.set(sourceBounds);
+        } else {
+            mBoundsAnimationSourceBounds.setEmpty();
+        }
+        if (destBounds != null) {
+            mBoundsAnimationTarget.set(destBounds);
         } else {
             mBoundsAnimationTarget.setEmpty();
         }
     }
 
     /**
+     * @return the source bounds for the bounds animation.
+     */
+    void getAnimatingSourceBounds(Rect outBounds) {
+        if (mBoundsAnimationSourceBounds != null) {
+            outBounds.set(mBoundsAnimationSourceBounds);
+            return;
+        }
+        outBounds.setEmpty();
+    }
+
+    /**
      * @return the bounds that the task stack is currently being animated towards, or the current
      *         stack bounds if there is no animation in progress.
      */
@@ -1465,7 +1481,6 @@
     public void onAnimationEnd() {
         synchronized (mService.mWindowMap) {
             mBoundsAnimating = false;
-            mBoundsAnimationTarget.setEmpty();
             mService.requestTraversal();
         }
 
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index dd2689b..fa9c2a7 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -5305,8 +5305,8 @@
                     if (displayContent.mBaseDisplayWidth != width
                             || displayContent.mBaseDisplayHeight != height) {
                         Slog.i(TAG_WM, "FORCED DISPLAY SIZE: " + width + "x" + height);
-                        displayContent.updateBaseDisplayMetrics(width, height,
-                                displayContent.mBaseDisplayDensity);
+                        displayContent.mBaseDisplayWidth = width;
+                        displayContent.mBaseDisplayHeight = height;
                     }
                 } catch (NumberFormatException ex) {
                 }
@@ -5331,7 +5331,8 @@
     // displayContent must not be null
     private void setForcedDisplaySizeLocked(DisplayContent displayContent, int width, int height) {
         Slog.i(TAG_WM, "Using new display size: " + width + "x" + height);
-        displayContent.updateBaseDisplayMetrics(width, height, displayContent.mBaseDisplayDensity);
+        displayContent.mBaseDisplayWidth = width;
+        displayContent.mBaseDisplayHeight = height;
         reconfigureDisplayLocked(displayContent);
     }
 
@@ -7316,7 +7317,6 @@
      * WARNING: This method contains locks known to the State of California
      * to cause Deadlocks and other conditions.
      *
-     *
      * Begins a surface transaction with which the AM can batch operations.
      * All Surface updates performed by the WindowManager following this
      * will not appear on screen until after the call to
@@ -7329,7 +7329,6 @@
      * from the new parent are inherited, otherwise it could be revealed
      * mistakenly.
      *
-     *
      * TODO(b/36393204): We can investigate totally replacing #deferSurfaceLayout
      * with something like this but it seems that some existing cases of
      * deferSurfaceLayout may be a little too broad, in particular the total
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 48de7e4..826fb45 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -67,8 +67,6 @@
 import android.view.animation.AnimationUtils;
 import android.view.animation.Transformation;
 
-import com.android.server.wm.WindowManagerService.H;
-
 import java.io.PrintWriter;
 import java.io.FileDescriptor;
 
@@ -156,6 +154,8 @@
     Rect mLastClipRect = new Rect();
     Rect mLastFinalClipRect = new Rect();
     Rect mTmpStackBounds = new Rect();
+    private Rect mTmpAnimatingBounds = new Rect();
+    private Rect mTmpSourceBounds = new Rect();
 
     /**
      * This is rectangle of the window's surface that is not covered by
@@ -1282,6 +1282,7 @@
 
     void setSurfaceBoundariesLocked(final boolean recoveringMemory) {
         final WindowState w = mWin;
+        final LayoutParams attrs = mWin.getAttrs();
         final Task task = w.getTask();
 
         // We got resized, so block all updates until we got the new surface.
@@ -1290,7 +1291,7 @@
         }
 
         mTmpSize.set(w.mShownPosition.x, w.mShownPosition.y, 0, 0);
-        calculateSurfaceBounds(w, w.getAttrs());
+        calculateSurfaceBounds(w, attrs);
 
         mExtraHScale = (float) 1.0;
         mExtraVScale = (float) 1.0;
@@ -1329,23 +1330,59 @@
         float surfaceHeight = mSurfaceController.getHeight();
 
         if (isForceScaled()) {
-            int hInsets = w.getAttrs().surfaceInsets.left + w.getAttrs().surfaceInsets.right;
-            int vInsets = w.getAttrs().surfaceInsets.top + w.getAttrs().surfaceInsets.bottom;
+            int hInsets = attrs.surfaceInsets.left + attrs.surfaceInsets.right;
+            int vInsets = attrs.surfaceInsets.top + attrs.surfaceInsets.bottom;
+            float surfaceContentWidth = surfaceWidth - hInsets;
+            float surfaceContentHeight = surfaceHeight - vInsets;
             if (!mForceScaleUntilResize) {
                 mSurfaceController.forceScaleableInTransaction(true);
             }
 
+            int posX = mTmpSize.left;
+            int posY = mTmpSize.top;
             task.mStack.getDimBounds(mTmpStackBounds);
-            // We want to calculate the scaling based on the content area, not based on
-            // the entire surface, so that we scale in sync with windows that don't have insets.
-            mExtraHScale = mTmpStackBounds.width() / (float)(surfaceWidth - hInsets);
-            mExtraVScale = mTmpStackBounds.height() / (float)(surfaceHeight - vInsets);
+            task.mStack.getAnimatingSourceBounds(mTmpSourceBounds);
+            if (!mTmpSourceBounds.isEmpty()) {
+                // Get the final target stack bounds, if we are not animating, this is just the
+                // current stack bounds
+                task.mStack.getAnimatingBounds(mTmpAnimatingBounds);
+
+                // Calculate the current progress and interpolate the difference between the target
+                // and source bounds
+                float finalWidth = mTmpAnimatingBounds.width();
+                float initialWidth = mTmpSourceBounds.width();
+                float t = (surfaceContentWidth - mTmpStackBounds.width())
+                        / (surfaceContentWidth - mTmpAnimatingBounds.width());
+                mExtraHScale = (initialWidth + t * (finalWidth - initialWidth)) / initialWidth;
+                mExtraVScale = mExtraHScale;
+
+                // Adjust the position to account for the inset bounds
+                posX -= (int) (t * mExtraHScale * mTmpSourceBounds.left);
+                posY -= (int) (t * mExtraVScale * mTmpSourceBounds.top);
+
+                // Always clip to the stack bounds since the surface can be larger with the current
+                // scale
+                clipRect = null;
+                finalClipRect = mTmpStackBounds;
+            } else {
+                // We want to calculate the scaling based on the content area, not based on
+                // the entire surface, so that we scale in sync with windows that don't have insets.
+                mExtraHScale = mTmpStackBounds.width() / surfaceContentWidth;
+                mExtraVScale = mTmpStackBounds.height() / surfaceContentHeight;
+
+                // Since we are scaled to fit in our previously desired crop, we can now
+                // expose the whole window in buffer space, and not risk extending
+                // past where the system would have cropped us
+                clipRect = null;
+                finalClipRect = null;
+            }
 
             // In the case of ForceScaleToStack we scale entire tasks together,
             // and so we need to scale our offsets relative to the task bounds
             // or parent and child windows would fall out of alignment.
-            int posX = (int) (mTmpSize.left - w.mAttrs.x * (1 - mExtraHScale));
-            int posY = (int) (mTmpSize.top - w.mAttrs.y * (1 - mExtraVScale));
+            posX -= (int) (attrs.x * (1 - mExtraHScale));
+            posY -= (int) (attrs.y * (1 - mExtraVScale));
+
             // Imagine we are scaling down. As we scale the buffer down, we decrease the
             // distance between the surface top left, and the start of the surface contents
             // (previously it was surfaceInsets.left pixels in screen space but now it
@@ -1353,17 +1390,11 @@
             // non inset content at the same position, we have to shift the whole window
             // forward. Likewise for scaling up, we've increased this distance, and we need
             // to shift by a negative number to compensate.
-            posX += w.getAttrs().surfaceInsets.left * (1 - mExtraHScale);
-            posY += w.getAttrs().surfaceInsets.top * (1 - mExtraVScale);
+            posX += attrs.surfaceInsets.left * (1 - mExtraHScale);
+            posY += attrs.surfaceInsets.top * (1 - mExtraVScale);
 
-            mSurfaceController.setPositionInTransaction((float)Math.floor(posX),
-                    (float)Math.floor(posY), recoveringMemory);
-
-            // Since we are scaled to fit in our previously desired crop, we can now
-            // expose the whole window in buffer space, and not risk extending
-            // past where the system would have cropped us
-            clipRect = null;
-            finalClipRect = null;
+            mSurfaceController.setPositionInTransaction((float) Math.floor(posX),
+                    (float) Math.floor(posY), recoveringMemory);
 
             // Various surfaces in the scaled stack may resize at different times.
             // We need to ensure for each surface, that we disable transformation matrix
diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
index 308632f..374aee1 100644
--- a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
@@ -22,7 +22,6 @@
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
-import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.nullable;
 import static org.mockito.Mockito.times;
@@ -32,7 +31,6 @@
 import android.accounts.Account;
 import android.accounts.AccountManager;
 import android.accounts.AccountManagerInternal;
-import android.accounts.AuthenticatorDescription;
 import android.accounts.CantAddAccountActivity;
 import android.accounts.IAccountManagerResponse;
 import android.app.AppOpsManager;
@@ -49,11 +47,9 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
-import android.content.pm.RegisteredServicesCacheListener;
 import android.content.pm.ResolveInfo;
 import android.content.pm.Signature;
 import android.content.pm.UserInfo;
-import android.content.pm.RegisteredServicesCache.ServiceInfo;
 import android.database.Cursor;
 import android.database.DatabaseErrorHandler;
 import android.database.sqlite.SQLiteDatabase;
@@ -62,6 +58,7 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.RemoteException;
+import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.test.AndroidTestCase;
@@ -78,16 +75,18 @@
 import org.mockito.MockitoAnnotations;
 
 import java.io.File;
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
 import java.security.GeneralSecurityException;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collection;
+import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
 import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.CyclicBarrier;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
 
 
 /**
@@ -2616,6 +2615,142 @@
         }
     }
 
+    @SmallTest
+    public void testConcurrencyReadWrite() throws Exception {
+        // Test 2 threads calling getAccounts and 1 thread setAuthToken
+        unlockSystemUser();
+        String[] list = new String[]{AccountManagerServiceTestFixtures.CALLER_PACKAGE};
+        when(mMockPackageManager.getPackagesForUid(anyInt())).thenReturn(list);
+
+        Account a1 = new Account("account1",
+                AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1);
+        mAms.addAccountExplicitly(a1, "p1", null);
+        List<String> errors = Collections.synchronizedList(new ArrayList<>());
+        int readerCount = 2;
+        ExecutorService es = Executors.newFixedThreadPool(readerCount + 1);
+        AtomicLong readTotalTime = new AtomicLong(0);
+        AtomicLong writeTotalTime = new AtomicLong(0);
+        final CyclicBarrier cyclicBarrier = new CyclicBarrier(readerCount + 1);
+
+        final int loopSize = 20;
+        for (int t = 0; t < readerCount; t++) {
+            es.submit(() -> {
+                for (int i = 0; i < loopSize; i++) {
+                    String logPrefix = Thread.currentThread().getName() + " " + i;
+                    waitForCyclicBarrier(cyclicBarrier);
+                    cyclicBarrier.reset();
+                    SystemClock.sleep(1); // Ensure that writer wins
+                    Log.d(TAG, logPrefix + " getAccounts started");
+                    long ti = System.currentTimeMillis();
+                    try {
+                        Account[] accounts = mAms.getAccounts(null, mContext.getOpPackageName());
+                        if (accounts == null || accounts.length != 1
+                                || !AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1.equals(
+                                accounts[0].type)) {
+                            String msg = logPrefix + ": Unexpected accounts: " + Arrays
+                                    .toString(accounts);
+                            Log.e(TAG, "    " + msg);
+                            errors.add(msg);
+                        }
+                        Log.d(TAG, logPrefix + " getAccounts done");
+                    } catch (Exception e) {
+                        String msg = logPrefix + ": getAccounts failed " + e;
+                        Log.e(TAG, msg, e);
+                        errors.add(msg);
+                    }
+                    ti = System.currentTimeMillis() - ti;
+                    readTotalTime.addAndGet(ti);
+                }
+            });
+        }
+
+        es.submit(() -> {
+            for (int i = 0; i < loopSize; i++) {
+                String logPrefix = Thread.currentThread().getName() + " " + i;
+                waitForCyclicBarrier(cyclicBarrier);
+                long ti = System.currentTimeMillis();
+                Log.d(TAG, logPrefix + " setAuthToken started");
+                try {
+                    mAms.setAuthToken(a1, "t1", "v" + i);
+                    Log.d(TAG, logPrefix + " setAuthToken done");
+                } catch (Exception e) {
+                    errors.add(logPrefix + ": setAuthToken failed: " + e);
+                }
+                ti = System.currentTimeMillis() - ti;
+                writeTotalTime.addAndGet(ti);
+            }
+        });
+        es.shutdown();
+        assertTrue("Time-out waiting for jobs to finish",
+                es.awaitTermination(10, TimeUnit.SECONDS));
+        es.shutdownNow();
+        assertTrue("Errors: " + errors, errors.isEmpty());
+        Log.i(TAG, "testConcurrencyReadWrite: readTotalTime=" + readTotalTime + " avg="
+                + (readTotalTime.doubleValue() / readerCount / loopSize));
+        Log.i(TAG, "testConcurrencyReadWrite: writeTotalTime=" + writeTotalTime + " avg="
+                + (writeTotalTime.doubleValue() / loopSize));
+    }
+
+    @SmallTest
+    public void testConcurrencyRead() throws Exception {
+        // Test 2 threads calling getAccounts
+        unlockSystemUser();
+        String[] list = new String[]{AccountManagerServiceTestFixtures.CALLER_PACKAGE};
+        when(mMockPackageManager.getPackagesForUid(anyInt())).thenReturn(list);
+
+        Account a1 = new Account("account1",
+                AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1);
+        mAms.addAccountExplicitly(a1, "p1", null);
+        List<String> errors = Collections.synchronizedList(new ArrayList<>());
+        int readerCount = 2;
+        ExecutorService es = Executors.newFixedThreadPool(readerCount + 1);
+        AtomicLong readTotalTime = new AtomicLong(0);
+
+        final int loopSize = 20;
+        for (int t = 0; t < readerCount; t++) {
+            es.submit(() -> {
+                for (int i = 0; i < loopSize; i++) {
+                    String logPrefix = Thread.currentThread().getName() + " " + i;
+                    Log.d(TAG, logPrefix + " getAccounts started");
+                    long ti = System.currentTimeMillis();
+                    try {
+                        Account[] accounts = mAms.getAccounts(null, mContext.getOpPackageName());
+                        if (accounts == null || accounts.length != 1
+                                || !AccountManagerServiceTestFixtures.ACCOUNT_TYPE_1.equals(
+                                accounts[0].type)) {
+                            String msg = logPrefix + ": Unexpected accounts: " + Arrays
+                                    .toString(accounts);
+                            Log.e(TAG, "    " + msg);
+                            errors.add(msg);
+                        }
+                        Log.d(TAG, logPrefix + " getAccounts done");
+                    } catch (Exception e) {
+                        String msg = logPrefix + ": getAccounts failed " + e;
+                        Log.e(TAG, msg, e);
+                        errors.add(msg);
+                    }
+                    ti = System.currentTimeMillis() - ti;
+                    readTotalTime.addAndGet(ti);
+                }
+            });
+        }
+        es.shutdown();
+        assertTrue("Time-out waiting for jobs to finish",
+                es.awaitTermination(10, TimeUnit.SECONDS));
+        es.shutdownNow();
+        assertTrue("Errors: " + errors, errors.isEmpty());
+        Log.i(TAG, "testConcurrencyRead: readTotalTime=" + readTotalTime + " avg="
+                + (readTotalTime.doubleValue() / readerCount / loopSize));
+    }
+
+    private void waitForCyclicBarrier(CyclicBarrier cyclicBarrier) {
+        try {
+            cyclicBarrier.await(LATCH_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+        } catch (Exception e) {
+            throw new IllegalStateException("Should not throw " + e, e);
+        }
+    }
+
     private void waitForLatch(CountDownLatch latch) {
         try {
             latch.await(LATCH_TIMEOUT_MS, TimeUnit.MILLISECONDS);
diff --git a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestService.java b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestService.java
index a2385d6..b550cfa 100644
--- a/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestService.java
+++ b/tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/SoundTriggerTestService.java
@@ -100,7 +100,7 @@
     @Override
     public void onDestroy() {
         super.onDestroy();
-        stopAllRecognitions();
+        stopAllRecognitionsAndUnload();
         unregisterReceiver(mBroadcastReceiver);
     }
 
@@ -171,7 +171,7 @@
     @Override
     public void onTaskRemoved(Intent rootIntent) {
         super.onTaskRemoved(rootIntent);
-        stopAllRecognitions();
+        stopAllRecognitionsAndUnload();
         stopSelf();
     }
 
@@ -197,8 +197,10 @@
         }
     }
 
-    private synchronized void stopAllRecognitions() {
+    private synchronized void stopAllRecognitionsAndUnload() {
+        Log.e(TAG, "Stop all recognitions");
         for (ModelInfo modelInfo : mModelInfoMap.values()) {
+            Log.e(TAG, "Loop " + modelInfo.modelUuid);
             if (modelInfo.detector != null) {
                 Log.i(TAG, "Stopping recognition for " + modelInfo.name);
                 try {
@@ -206,6 +208,12 @@
                 } catch (Exception e) {
                     Log.e(TAG, "Failed to stop recognition", e);
                 }
+                try {
+                    mSoundTriggerUtil.deleteSoundModel(modelInfo.modelUuid);
+                    modelInfo.detector = null;
+                } catch (Exception e) {
+                    Log.e(TAG, "Failed to unload sound model", e);
+                }
             }
         }
     }