Merge "Allow GSM RSSI levels to be customized by CarrierConfig" into qt-dev
diff --git a/api/current.txt b/api/current.txt
index 5997043..bc634c6 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -10307,6 +10307,7 @@
     field public static final String CATEGORY_APP_CALENDAR = "android.intent.category.APP_CALENDAR";
     field public static final String CATEGORY_APP_CONTACTS = "android.intent.category.APP_CONTACTS";
     field public static final String CATEGORY_APP_EMAIL = "android.intent.category.APP_EMAIL";
+    field public static final String CATEGORY_APP_FILES = "android.intent.category.APP_FILES";
     field public static final String CATEGORY_APP_GALLERY = "android.intent.category.APP_GALLERY";
     field public static final String CATEGORY_APP_MAPS = "android.intent.category.APP_MAPS";
     field public static final String CATEGORY_APP_MARKET = "android.intent.category.APP_MARKET";
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index e3c2f42..f7608f5 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -4919,6 +4919,8 @@
     UNKNOWN = 0;
     SOME = 1;
     FULL = 2;
+    PERSISTENT = 3;
+    BFGS = 4;
   }
   optional Action action = 3;
 
diff --git a/config/preloaded-classes b/config/preloaded-classes
index abdbab2..5910c28 100644
--- a/config/preloaded-classes
+++ b/config/preloaded-classes
@@ -756,7 +756,6 @@
 android.content.AsyncQueryHandler$WorkerArgs
 android.content.AsyncQueryHandler$WorkerHandler
 android.content.AsyncQueryHandler
-android.content.AsyncTaskLoader$LoadTask
 android.content.AsyncTaskLoader
 android.content.BroadcastReceiver$PendingResult$1
 android.content.BroadcastReceiver$PendingResult
@@ -3186,7 +3185,6 @@
 android.speech.tts.ITextToSpeechService$Stub$Proxy
 android.speech.tts.ITextToSpeechService
 android.speech.tts.TextToSpeech$Action
-android.speech.tts.TextToSpeech$Connection$SetupConnectionAsyncTask
 android.speech.tts.TextToSpeech$Connection
 android.speech.tts.TextToSpeech$OnInitListener
 android.speech.tts.TextToSpeech
diff --git a/config/preloaded-classes-blacklist b/config/preloaded-classes-blacklist
index 59f605d..cd5a120 100644
--- a/config/preloaded-classes-blacklist
+++ b/config/preloaded-classes-blacklist
@@ -1,6 +1,8 @@
+android.content.AsyncTaskLoader$LoadTask
 android.net.ConnectivityThread$Singleton
 android.os.AsyncTask
 android.os.FileObserver
+android.speech.tts.TextToSpeech$Connection$SetupConnectionAsyncTask
 android.widget.Magnifier
 sun.nio.fs.UnixChannelFactory
 com.android.server.SystemConfig$PermissionEntry
diff --git a/core/java/android/accounts/Account.java b/core/java/android/accounts/Account.java
index 2637764..c822d20 100644
--- a/core/java/android/accounts/Account.java
+++ b/core/java/android/accounts/Account.java
@@ -93,6 +93,12 @@
     public Account(Parcel in) {
         this.name = in.readString();
         this.type = in.readString();
+        if (TextUtils.isEmpty(name)) {
+            throw new android.os.BadParcelableException("the name must not be empty: " + name);
+        }
+        if (TextUtils.isEmpty(type)) {
+            throw new android.os.BadParcelableException("the type must not be empty: " + type);
+        }
         this.accessId = in.readString();
         if (accessId != null) {
             synchronized (sAccessedAccounts) {
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index d87171e..8628d32 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -4731,6 +4731,18 @@
     @SdkConstant(SdkConstantType.INTENT_CATEGORY)
     public static final String CATEGORY_APP_MUSIC = "android.intent.category.APP_MUSIC";
 
+    /**
+     * Used with {@link #ACTION_MAIN} to launch the files application.
+     * The activity should be able to browse and manage files stored on the device.
+     * <p>NOTE: This should not be used as the primary key of an Intent,
+     * since it will not result in the app launching with the correct
+     * action and category.  Instead, use this with
+     * {@link #makeMainSelectorActivity(String, String)} to generate a main
+     * Intent with this category in the selector.</p>
+     */
+    @SdkConstant(SdkConstantType.INTENT_CATEGORY)
+    public static final String CATEGORY_APP_FILES = "android.intent.category.APP_FILES";
+
     // ---------------------------------------------------------------------
     // ---------------------------------------------------------------------
     // Standard extra data keys.
diff --git a/core/java/android/content/om/OverlayInfo.java b/core/java/android/content/om/OverlayInfo.java
index fc79a42..639335e 100644
--- a/core/java/android/content/om/OverlayInfo.java
+++ b/core/java/android/content/om/OverlayInfo.java
@@ -451,7 +451,7 @@
     public String toString() {
         return "OverlayInfo { overlay=" + packageName + ", targetPackage=" + targetPackageName
                 + ((targetOverlayableName == null) ? ""
-                : ", targetOverlyabale=" + targetOverlayableName)
+                : ", targetOverlayable=" + targetOverlayableName)
                 + ", state=" + state + " (" + stateToString(state) + "), userId=" + userId + " }";
     }
 }
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index 9e9e68d..ed5c1b1 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -1148,9 +1148,9 @@
         final Context context = AppGlobals.getInitialApplication();
         final AppOpsManager appOps = context.getSystemService(AppOpsManager.class);
 
-        final boolean hasLegacy = appOps.noteOpNoThrow(AppOpsManager.OP_LEGACY_STORAGE,
+        final boolean hasLegacy = appOps.checkOpNoThrow(AppOpsManager.OP_LEGACY_STORAGE,
                 context.getApplicationInfo().uid,
-                context.getPackageName()) == AppOpsManager.MODE_ALLOWED;
+                context.getOpPackageName()) == AppOpsManager.MODE_ALLOWED;
 
         // STOPSHIP: only use app-op once permission model has fully landed
         final boolean requestedLegacy = !AppGlobals.getInitialApplication().getApplicationInfo()
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index c57bf91..075b650 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -1652,6 +1652,26 @@
      */
     public static boolean checkPermissionAndAppOp(Context context, boolean enforce,
             int pid, int uid, String packageName, String permission, int op) {
+        return checkPermissionAndAppOp(context, enforce, pid, uid, packageName, permission, op,
+                true);
+    }
+
+    /**
+     * Check that given app holds both permission and appop but do not noteOp.
+     * @hide
+     */
+    public static boolean checkPermissionAndCheckOp(Context context, boolean enforce,
+            int pid, int uid, String packageName, String permission, int op) {
+        return checkPermissionAndAppOp(context, enforce, pid, uid, packageName, permission, op,
+                false);
+    }
+
+    /**
+     * Check that given app holds both permission and appop.
+     * @hide
+     */
+    private static boolean checkPermissionAndAppOp(Context context, boolean enforce,
+            int pid, int uid, String packageName, String permission, int op, boolean note) {
         if (context.checkPermission(permission, pid, uid) != PERMISSION_GRANTED) {
             if (enforce) {
                 throw new SecurityException(
@@ -1662,7 +1682,21 @@
         }
 
         AppOpsManager appOps = context.getSystemService(AppOpsManager.class);
-        final int mode = appOps.noteOpNoThrow(op, uid, packageName);
+        final int mode;
+        if (note) {
+            mode = appOps.noteOpNoThrow(op, uid, packageName);
+        } else {
+            try {
+                appOps.checkPackage(uid, packageName);
+            } catch (SecurityException e) {
+                if (enforce) {
+                    throw e;
+                } else {
+                    return false;
+                }
+            }
+            mode = appOps.checkOpNoThrow(op, uid, packageName);
+        }
         switch (mode) {
             case AppOpsManager.MODE_ALLOWED:
                 return true;
diff --git a/core/java/android/service/autofill/AutofillService.java b/core/java/android/service/autofill/AutofillService.java
index 2b7e8b8..5a91802 100644
--- a/core/java/android/service/autofill/AutofillService.java
+++ b/core/java/android/service/autofill/AutofillService.java
@@ -674,6 +674,8 @@
      * Called when the Android system disconnects from the service.
      *
      * <p> At this point this service may no longer be an active {@link AutofillService}.
+     * It should not make calls on {@link AutofillManager} that requires the caller to be
+     * the current service.
      */
     public void onDisconnected() {
     }
diff --git a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
index 96b861b..b00eb8a 100644
--- a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
+++ b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
@@ -41,6 +41,7 @@
 import android.util.SparseArray;
 import android.util.TimeUtils;
 import android.view.autofill.AutofillId;
+import android.view.autofill.AutofillManager;
 import android.view.autofill.AutofillValue;
 import android.view.autofill.IAugmentedAutofillManagerClient;
 import android.view.autofill.IAutofillWindowPresenter;
@@ -183,6 +184,8 @@
      * Called when the Android system disconnects from the service.
      *
      * <p> At this point this service may no longer be an active {@link AugmentedAutofillService}.
+     * It should not make calls on {@link AutofillManager} that requires the caller to be
+     * the current service.
      */
     public void onDisconnected() {
     }
diff --git a/core/java/android/service/contentcapture/ContentCaptureService.java b/core/java/android/service/contentcapture/ContentCaptureService.java
index dc57a15..5be73b9 100644
--- a/core/java/android/service/contentcapture/ContentCaptureService.java
+++ b/core/java/android/service/contentcapture/ContentCaptureService.java
@@ -37,7 +37,6 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.RemoteException;
-import android.service.autofill.AutofillService;
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseIntArray;
@@ -350,7 +349,9 @@
     /**
      * Called when the Android system disconnects from the service.
      *
-     * <p> At this point this service may no longer be an active {@link AutofillService}.
+     * <p> At this point this service may no longer be an active {@link ContentCaptureService}.
+     * It should not make calls on {@link ContentCaptureManager} that requires the caller to be
+     * the current service.
      */
     public void onDisconnected() {
         Slog.i(TAG, "unbinding from " + getClass().getName());
diff --git a/core/java/android/view/IRecentsAnimationController.aidl b/core/java/android/view/IRecentsAnimationController.aidl
index 597b34bf..956161a 100644
--- a/core/java/android/view/IRecentsAnimationController.aidl
+++ b/core/java/android/view/IRecentsAnimationController.aidl
@@ -41,9 +41,11 @@
      * with remote animation targets should be relinquished. If {@param moveHomeToTop} is true, then
      * the home activity should be moved to the top. Otherwise, the home activity is hidden and the
      * user is returned to the app.
+     * @param sendUserLeaveHint If set to true, {@link Activity#onUserLeaving} will be sent to the
+     *                          top resumed app, false otherwise.
      */
     @UnsupportedAppUsage
-    void finish(boolean moveHomeToTop);
+    void finish(boolean moveHomeToTop, boolean sendUserLeaveHint);
 
     /**
      * Called by the handler to indicate that the recents animation input consumer should be
diff --git a/core/java/com/android/internal/app/procstats/ProcessState.java b/core/java/com/android/internal/app/procstats/ProcessState.java
index b26efc0..2f9136a 100644
--- a/core/java/com/android/internal/app/procstats/ProcessState.java
+++ b/core/java/com/android/internal/app/procstats/ProcessState.java
@@ -78,8 +78,8 @@
         STATE_PERSISTENT,               // ActivityManager.PROCESS_STATE_PERSISTENT_UI
         STATE_TOP,                      // ActivityManager.PROCESS_STATE_TOP
         STATE_IMPORTANT_FOREGROUND,     // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE_LOCATION
-        STATE_IMPORTANT_FOREGROUND,     // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
         STATE_IMPORTANT_FOREGROUND,     // ActivityManager.PROCESS_STATE_BOUND_TOP
+        STATE_IMPORTANT_FOREGROUND,     // ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE
         STATE_IMPORTANT_FOREGROUND,     // ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE
         STATE_IMPORTANT_FOREGROUND,     // ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND
         STATE_IMPORTANT_BACKGROUND,     // ActivityManager.PROCESS_STATE_IMPORTANT_BACKGROUND
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 13bcbf6..3135c62 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -317,7 +317,8 @@
                                        buffer->getPixelFormat(),
                                        (jint)buffer->getUsage(),
                                        (jlong)buffer.get(),
-                                       namedColorSpace);
+                                       namedColorSpace,
+                                       false /* capturedSecureLayers */);
 }
 
 static void nativeApplyTransaction(JNIEnv* env, jclass clazz, jlong transactionObj, jboolean sync) {
diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp
index 0996352..77ebd02 100644
--- a/core/jni/fd_utils.cpp
+++ b/core/jni/fd_utils.cpp
@@ -462,7 +462,6 @@
     }
 
     if (std::find(fds_to_ignore.begin(), fds_to_ignore.end(), fd) != fds_to_ignore.end()) {
-      LOG(INFO) << "Ignoring open file descriptor " << fd;
       continue;
     }
 
@@ -496,7 +495,6 @@
     }
 
     if (std::find(fds_to_ignore.begin(), fds_to_ignore.end(), fd) != fds_to_ignore.end()) {
-      LOG(INFO) << "Ignoring open file descriptor " << fd;
       continue;
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
index d4d0519..e02709e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
@@ -83,17 +83,18 @@
  * as needed.
  */
 public class ApplicationsState {
-    static final String TAG = "ApplicationsState";
-    static final boolean DEBUG = false;
-    static final boolean DEBUG_LOCKING = false;
+    private static final String TAG = "ApplicationsState";
 
     public static final int SIZE_UNKNOWN = -1;
     public static final int SIZE_INVALID = -2;
 
-    static final Pattern REMOVE_DIACRITICALS_PATTERN
+    private static final boolean DEBUG = false;
+    private static final boolean DEBUG_LOCKING = false;
+    private static final Object sLock = new Object();
+    private static final Pattern REMOVE_DIACRITICALS_PATTERN
             = Pattern.compile("\\p{InCombiningDiacriticalMarks}+");
 
-    static final Object sLock = new Object();
+    @VisibleForTesting
     static ApplicationsState sInstance;
 
     public static ApplicationsState getInstance(Application app) {
@@ -126,13 +127,12 @@
 
     // Information about all applications.  Synchronize on mEntriesMap
     // to protect access to these.
-    final ArrayList<Session> mSessions = new ArrayList<Session>();
-    final ArrayList<Session> mRebuildingSessions = new ArrayList<Session>();
+    final ArrayList<Session> mSessions = new ArrayList<>();
+    final ArrayList<Session> mRebuildingSessions = new ArrayList<>();
     private InterestingConfigChanges mInterestingConfigChanges = new InterestingConfigChanges();
     // Map: userid => (Map: package name => AppEntry)
-    final SparseArray<HashMap<String, AppEntry>> mEntriesMap =
-            new SparseArray<HashMap<String, AppEntry>>();
-    final ArrayList<AppEntry> mAppEntries = new ArrayList<AppEntry>();
+    final SparseArray<HashMap<String, AppEntry>> mEntriesMap = new SparseArray<>();
+    final ArrayList<AppEntry> mAppEntries = new ArrayList<>();
     List<ApplicationInfo> mApplications = new ArrayList<>();
     long mCurId = 1;
     UUID mCurComputingSizeUuid;
@@ -182,9 +182,10 @@
         mInterestingConfigChanges = interestingConfigChanges;
     }
 
-    public static final @SessionFlags int DEFAULT_SESSION_FLAGS =
+    @SessionFlags
+    public static final int DEFAULT_SESSION_FLAGS =
             FLAG_SESSION_REQUEST_HOME_APP | FLAG_SESSION_REQUEST_ICONS |
-            FLAG_SESSION_REQUEST_SIZES | FLAG_SESSION_REQUEST_LAUNCHER;
+                    FLAG_SESSION_REQUEST_SIZES | FLAG_SESSION_REQUEST_LAUNCHER;
 
     private ApplicationsState(Application app, IPackageManager iPackageManager) {
         mContext = app;
@@ -194,7 +195,7 @@
         mUm = mContext.getSystemService(UserManager.class);
         mStats = mContext.getSystemService(StorageStatsManager.class);
         for (int userId : mUm.getProfileIdsWithDisabled(UserHandle.myUserId())) {
-            mEntriesMap.put(userId, new HashMap<String, AppEntry>());
+            mEntriesMap.put(userId, new HashMap<>());
         }
 
         mThread = new HandlerThread("ApplicationsState.Loader",
@@ -683,9 +684,16 @@
     private AppEntry getEntryLocked(ApplicationInfo info) {
         int userId = UserHandle.getUserId(info.uid);
         AppEntry entry = mEntriesMap.get(userId).get(info.packageName);
-        if (DEBUG) Log.i(TAG, "Looking up entry of pkg " + info.packageName + ": " + entry);
+        if (DEBUG) {
+            Log.i(TAG, "Looking up entry of pkg " + info.packageName + ": " + entry);
+        }
         if (entry == null) {
-            if (DEBUG) Log.i(TAG, "Creating AppEntry for " + info.packageName);
+            if (mHiddenModules.contains(info.packageName)) {
+                return null;
+            }
+            if (DEBUG) {
+                Log.i(TAG, "Creating AppEntry for " + info.packageName);
+            }
             entry = new AppEntry(mContext, info, mCurId++);
             mEntriesMap.get(userId).put(info.packageName, entry);
             mAppEntries.add(entry);
@@ -759,7 +767,8 @@
         boolean mRebuildForeground;
 
         private final boolean mHasLifecycle;
-        @SessionFlags private int mFlags = DEFAULT_SESSION_FLAGS;
+        @SessionFlags
+        private int mFlags = DEFAULT_SESSION_FLAGS;
 
         Session(Callbacks callbacks, Lifecycle lifecycle) {
             mCallbacks = callbacks;
@@ -771,7 +780,8 @@
             }
         }
 
-        public @SessionFlags int getSessionFlags() {
+        @SessionFlags
+        public int getSessionFlags() {
             return mFlags;
         }
 
@@ -863,25 +873,32 @@
                 filter.init(mContext);
             }
 
-            List<AppEntry> apps;
+            final List<AppEntry> apps;
             synchronized (mEntriesMap) {
                 apps = new ArrayList<>(mAppEntries);
             }
 
-            ArrayList<AppEntry> filteredApps = new ArrayList<AppEntry>();
-            if (DEBUG) Log.i(TAG, "Rebuilding...");
-            for (int i = 0; i < apps.size(); i++) {
-                AppEntry entry = apps.get(i);
+            ArrayList<AppEntry> filteredApps = new ArrayList<>();
+            if (DEBUG) {
+                Log.i(TAG, "Rebuilding...");
+            }
+            for (AppEntry entry : apps) {
                 if (entry != null && (filter == null || filter.filterApp(entry))) {
                     synchronized (mEntriesMap) {
-                        if (DEBUG_LOCKING) Log.v(TAG, "rebuild acquired lock");
+                        if (DEBUG_LOCKING) {
+                            Log.v(TAG, "rebuild acquired lock");
+                        }
                         if (comparator != null) {
                             // Only need the label if we are going to be sorting.
                             entry.ensureLabel(mContext);
                         }
-                        if (DEBUG) Log.i(TAG, "Using " + entry.info.packageName + ": " + entry);
+                        if (DEBUG) {
+                            Log.i(TAG, "Using " + entry.info.packageName + ": " + entry);
+                        }
                         filteredApps.add(entry);
-                        if (DEBUG_LOCKING) Log.v(TAG, "rebuild releasing lock");
+                        if (DEBUG_LOCKING) {
+                            Log.v(TAG, "rebuild releasing lock");
+                        }
                     }
                 }
             }
@@ -1290,7 +1307,8 @@
             }
         }
 
-        private @SessionFlags int getCombinedSessionFlags(List<Session> sessions) {
+        @SessionFlags
+        private int getCombinedSessionFlags(List<Session> sessions) {
             synchronized (mEntriesMap) {
                 int flags = 0;
                 for (Session session : sessions) {
@@ -1601,7 +1619,7 @@
             }
             if (object1.info != null && object2.info != null) {
                 compareResult =
-                    sCollator.compare(object1.info.packageName, object2.info.packageName);
+                        sCollator.compare(object1.info.packageName, object2.info.packageName);
                 if (compareResult != 0) {
                     return compareResult;
                 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java
index 2711e31..3a53d29 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java
@@ -22,6 +22,7 @@
 import android.util.Log;
 import android.util.Pair;
 
+import com.android.settingslib.R;
 import com.android.settingslib.bluetooth.BluetoothUtils;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
 
@@ -47,7 +48,9 @@
 
     @Override
     public String getSummary() {
-        return mCachedDevice.getConnectionSummary();
+        return isConnected() || mCachedDevice.isBusy()
+                ? mCachedDevice.getConnectionSummary()
+                : mContext.getString(R.string.bluetooth_disconnected);
     }
 
     @Override
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
index 1d9105c..d2fe5cd 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RecentsAnimationControllerCompat.java
@@ -77,9 +77,15 @@
         }
     }
 
-    public void finish(boolean toHome) {
+    /**
+     * Finish the current recents animation.
+     * @param toHome Going to home or back to the previous app.
+     * @param sendUserLeaveHint determines whether userLeaveHint will be set true to the previous
+     *                          app.
+     */
+    public void finish(boolean toHome, boolean sendUserLeaveHint) {
         try {
-            mAnimationController.finish(toHome);
+            mAnimationController.finish(toHome, sendUserLeaveHint);
         } catch (RemoteException e) {
             Log.e(TAG, "Failed to finish recents animation", e);
         }
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 0786b18..da9cffa 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -3836,9 +3836,9 @@
             }
 
             // Determine if caller is holding runtime permission
-            final boolean hasRead = StorageManager.checkPermissionAndAppOp(mContext, false, 0,
+            final boolean hasRead = StorageManager.checkPermissionAndCheckOp(mContext, false, 0,
                     uid, packageName, READ_EXTERNAL_STORAGE, OP_READ_EXTERNAL_STORAGE);
-            final boolean hasWrite = StorageManager.checkPermissionAndAppOp(mContext, false, 0,
+            final boolean hasWrite = StorageManager.checkPermissionAndCheckOp(mContext, false, 0,
                     uid, packageName, WRITE_EXTERNAL_STORAGE, OP_WRITE_EXTERNAL_STORAGE);
             // STOPSHIP: remove this temporary hack once we have dynamic runtime
             // permissions fully enabled again
diff --git a/services/core/java/com/android/server/SystemServerInitThreadPool.java b/services/core/java/com/android/server/SystemServerInitThreadPool.java
index 5cc9bfd..6bb3200 100644
--- a/services/core/java/com/android/server/SystemServerInitThreadPool.java
+++ b/services/core/java/com/android/server/SystemServerInitThreadPool.java
@@ -22,9 +22,10 @@
 
 import com.android.internal.util.ConcurrentUtils;
 import com.android.internal.util.Preconditions;
+import com.android.server.am.ActivityManagerService;
 
+import java.util.ArrayList;
 import java.util.List;
-import java.util.concurrent.Callable;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Future;
 import java.util.concurrent.TimeUnit;
@@ -47,6 +48,8 @@
     private ExecutorService mService = ConcurrentUtils.newFixedThreadPool(4,
             "system-server-init-thread", Process.THREAD_PRIORITY_FOREGROUND);
 
+    private List<String> mPendingTasks = new ArrayList<>();
+
     public static synchronized SystemServerInitThreadPool get() {
         if (sInstance == null) {
             sInstance = new SystemServerInitThreadPool();
@@ -57,19 +60,26 @@
     }
 
     public Future<?> submit(Runnable runnable, String description) {
-        if (IS_DEBUGGABLE) {
-            return mService.submit(() -> {
-                Slog.d(TAG, "Started executing " + description);
-                try {
-                    runnable.run();
-                } catch (RuntimeException e) {
-                    Slog.e(TAG, "Failure in " + description + ": " + e, e);
-                    throw e;
-                }
-                Slog.d(TAG, "Finished executing "  + description);
-            });
+        synchronized (mPendingTasks) {
+            mPendingTasks.add(description);
         }
-        return mService.submit(runnable);
+        return mService.submit(() -> {
+            if (IS_DEBUGGABLE) {
+                Slog.d(TAG, "Started executing " + description);
+            }
+            try {
+                runnable.run();
+            } catch (RuntimeException e) {
+                Slog.e(TAG, "Failure in " + description + ": " + e, e);
+                throw e;
+            }
+            synchronized (mPendingTasks) {
+                mPendingTasks.remove(description);
+            }
+            if (IS_DEBUGGABLE) {
+                Slog.d(TAG, "Finished executing " + description);
+            }
+        });
     }
 
     static synchronized void shutdown() {
@@ -81,16 +91,36 @@
                         TimeUnit.MILLISECONDS);
             } catch (InterruptedException e) {
                 Thread.currentThread().interrupt();
+                dumpStackTraces();
                 throw new IllegalStateException(TAG + " init interrupted");
             }
+            if (!terminated) {
+                // dump stack must be called before shutdownNow() to collect stacktrace of threads
+                // in the thread pool.
+                dumpStackTraces();
+            }
             List<Runnable> unstartedRunnables = sInstance.mService.shutdownNow();
             if (!terminated) {
+                final List<String> copy = new ArrayList<>();
+                synchronized (sInstance.mPendingTasks) {
+                    copy.addAll(sInstance.mPendingTasks);
+                }
                 throw new IllegalStateException("Cannot shutdown. Unstarted tasks "
-                        + unstartedRunnables);
+                        + unstartedRunnables + " Unfinished tasks " + copy);
             }
             sInstance.mService = null; // Make mService eligible for GC
+            sInstance.mPendingTasks = null;
             Slog.d(TAG, "Shutdown successful");
         }
     }
 
+    /**
+     * A helper function to call ActivityManagerService.dumpStackTraces().
+     */
+    private static void dumpStackTraces() {
+        final ArrayList<Integer> pids = new ArrayList<>();
+        pids.add(Process.myPid());
+        ActivityManagerService.dumpStackTraces(
+                pids, null, null, null);
+    }
 }
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index c647e2e..ac584e9 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -1304,12 +1304,12 @@
             return;
         }
         if (VDBG) {
-            log("notifyUserMobileDataStateChangedForSubscriberPhoneID: subId=" + phoneId
-                    + " state=" + state);
+            log("notifyUserMobileDataStateChangedForSubscriberPhoneID: PhoneId=" + phoneId
+                    + " subId=" + subId + " state=" + state);
         }
         synchronized (mRecords) {
             if (validatePhoneId(phoneId)) {
-                mMessageWaiting[phoneId] = state;
+                mUserMobileDataState[phoneId] = state;
                 for (Record r : mRecords) {
                     if (r.matchPhoneStateListenerEvent(
                             PhoneStateListener.LISTEN_USER_MOBILE_DATA_STATE) &&
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 5d47c9d..44d435f 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -1262,15 +1262,16 @@
                                 // processes).  These should not bring the current process
                                 // into the top state, since they are not on top.  Instead
                                 // give them the best bound state after that.
+                                final int bestState = cr.hasFlag(Context.BIND_INCLUDE_CAPABILITIES)
+                                        ? PROCESS_STATE_FOREGROUND_SERVICE_LOCATION
+                                        : PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
                                 if ((cr.flags & Context.BIND_FOREGROUND_SERVICE) != 0) {
-                                    clientProcState =
-                                            PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
+                                    clientProcState = bestState;
                                 } else if (mService.mWakefulness
                                         == PowerManagerInternal.WAKEFULNESS_AWAKE
                                         && (cr.flags & Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE)
                                                 != 0) {
-                                    clientProcState =
-                                            PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
+                                    clientProcState = bestState;
                                 } else {
                                     clientProcState =
                                             PROCESS_STATE_IMPORTANT_FOREGROUND;
diff --git a/services/core/java/com/android/server/attention/AttentionManagerService.java b/services/core/java/com/android/server/attention/AttentionManagerService.java
index bc78d1a..3dbea0d 100644
--- a/services/core/java/com/android/server/attention/AttentionManagerService.java
+++ b/services/core/java/com/android/server/attention/AttentionManagerService.java
@@ -22,7 +22,6 @@
 import static android.service.attention.AttentionService.ATTENTION_FAILURE_UNKNOWN;
 
 import android.Manifest;
-import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.TestApi;
 import android.annotation.UserIdInt;
@@ -51,6 +50,7 @@
 import android.provider.Settings;
 import android.service.attention.AttentionService;
 import android.service.attention.AttentionService.AttentionFailureCodes;
+import android.service.attention.AttentionService.AttentionSuccessCodes;
 import android.service.attention.IAttentionCallback;
 import android.service.attention.IAttentionService;
 import android.text.TextUtils;
@@ -75,6 +75,7 @@
  */
 public class AttentionManagerService extends SystemService {
     private static final String LOG_TAG = "AttentionManagerService";
+    private static final boolean DEBUG = false;
 
     /**
      * DeviceConfig flag name, allows a CTS to inject a fake implementation.
@@ -156,7 +157,11 @@
     /**
      * Checks whether user attention is at the screen and calls in the provided callback.
      *
-     * @return {@code true} if the framework was able to send the provided callback to the service
+     * Calling this multiple times quickly in a row will result in either a) returning a cached
+     * value, if present, or b) returning {@code false} because only one active request at a time is
+     * allowed.
+     *
+     * @return {@code true} if the framework was able to dispatch the request
      */
     private boolean checkAttention(long timeout, AttentionCallbackInternal callbackInternal) {
         Preconditions.checkNotNull(callbackInternal);
@@ -182,54 +187,30 @@
                 return false;
             }
 
-            if (userState.mService == null) {
-                // make sure every callback is called back
-                if (userState.mPendingAttentionCheck != null) {
-                    userState.mPendingAttentionCheck.cancel(
-                            ATTENTION_FAILURE_CANCELLED);
-                }
-                // fire the check when the service is started
-                userState.mPendingAttentionCheck = new PendingAttentionCheck(
-                        callbackInternal, () -> checkAttention(timeout, callbackInternal));
-            } else {
-                try {
-                    // throttle frequent requests
-                    final AttentionCheckCache cache = userState.mAttentionCheckCache;
-                    if (cache != null && now < cache.mLastComputed + STALE_AFTER_MILLIS) {
-                        callbackInternal.onSuccess(cache.mResult, cache.mTimestamp);
-                        return true;
-                    }
+            // throttle frequent requests
+            final AttentionCheckCache cache = userState.mAttentionCheckCache;
+            if (cache != null && now < cache.mLastComputed + STALE_AFTER_MILLIS) {
+                callbackInternal.onSuccess(cache.mResult, cache.mTimestamp);
+                return true;
+            }
 
+            // prevent spamming with multiple requests, only one at a time is allowed
+            if (userState.mCurrentAttentionCheck != null) {
+                if (!userState.mCurrentAttentionCheck.mIsDispatched
+                        || !userState.mCurrentAttentionCheck.mIsFulfilled) {
+                    return false;
+                }
+            }
+
+            userState.mCurrentAttentionCheck = createAttentionCheck(callbackInternal, userState);
+
+            if (userState.mService != null) {
+                try {
                     // schedule request cancellation if not returned by that point yet
                     cancelAfterTimeoutLocked(timeout);
-
-                    userState.mCurrentAttentionCheck = new AttentionCheck(callbackInternal,
-                            new IAttentionCallback.Stub() {
-                                @Override
-                                public void onSuccess(int result, long timestamp) {
-                                    callbackInternal.onSuccess(result, timestamp);
-                                    synchronized (mLock) {
-                                        userState.mAttentionCheckCache = new AttentionCheckCache(
-                                                SystemClock.uptimeMillis(), result,
-                                                timestamp);
-                                        userState.mCurrentAttentionCheckIsFulfilled = true;
-                                    }
-                                    StatsLog.write(
-                                            StatsLog.ATTENTION_MANAGER_SERVICE_RESULT_REPORTED,
-                                            result);
-                                }
-
-                                @Override
-                                public void onFailure(int error) {
-                                    callbackInternal.onFailure(error);
-                                    userState.mCurrentAttentionCheckIsFulfilled = true;
-                                    StatsLog.write(
-                                            StatsLog.ATTENTION_MANAGER_SERVICE_RESULT_REPORTED,
-                                            error);
-                                }
-                            });
                     userState.mService.checkAttention(
                             userState.mCurrentAttentionCheck.mIAttentionCallback);
+                    userState.mCurrentAttentionCheck.mIsDispatched = true;
                 } catch (RemoteException e) {
                     Slog.e(LOG_TAG, "Cannot call into the AttentionService");
                     return false;
@@ -239,6 +220,44 @@
         }
     }
 
+    private AttentionCheck createAttentionCheck(AttentionCallbackInternal callbackInternal,
+            UserState userState) {
+        final IAttentionCallback iAttentionCallback = new IAttentionCallback.Stub() {
+            @Override
+            public void onSuccess(@AttentionSuccessCodes int result, long timestamp) {
+                // the callback might have been cancelled already
+                if (!userState.mCurrentAttentionCheck.mIsFulfilled) {
+                    callbackInternal.onSuccess(result, timestamp);
+                    userState.mCurrentAttentionCheck.mIsFulfilled = true;
+                }
+
+                synchronized (mLock) {
+                    userState.mAttentionCheckCache = new AttentionCheckCache(
+                            SystemClock.uptimeMillis(), result,
+                            timestamp);
+                }
+                StatsLog.write(
+                        StatsLog.ATTENTION_MANAGER_SERVICE_RESULT_REPORTED,
+                        result);
+            }
+
+            @Override
+            public void onFailure(@AttentionFailureCodes int error) {
+                // the callback might have been cancelled already
+                if (!userState.mCurrentAttentionCheck.mIsFulfilled) {
+                    callbackInternal.onFailure(error);
+                    userState.mCurrentAttentionCheck.mIsFulfilled = true;
+                }
+
+                StatsLog.write(
+                        StatsLog.ATTENTION_MANAGER_SERVICE_RESULT_REPORTED,
+                        error);
+            }
+        };
+
+        return new AttentionCheck(callbackInternal, iAttentionCallback);
+    }
+
     /** Cancels the specified attention check. */
     private void cancelAttentionCheck(AttentionCallbackInternal callbackInternal) {
         synchronized (mLock) {
@@ -246,25 +265,13 @@
             if (userState == null) {
                 return;
             }
-            if (userState.mService == null) {
-                if (userState.mPendingAttentionCheck != null
-                        && userState.mPendingAttentionCheck.mCallbackInternal.equals(
-                        callbackInternal)) {
-                    userState.mPendingAttentionCheck.cancel(ATTENTION_FAILURE_UNKNOWN);
-                    userState.mPendingAttentionCheck = null;
-                }
+
+            if (!userState.mCurrentAttentionCheck.mCallbackInternal.equals(callbackInternal)) {
+                Slog.e(LOG_TAG, "Cannot cancel a non-current request");
                 return;
             }
-            if (userState.mCurrentAttentionCheck.mCallbackInternal.equals(callbackInternal)) {
-                try {
-                    userState.mService.cancelAttentionCheck(
-                            userState.mCurrentAttentionCheck.mIAttentionCallback);
-                } catch (RemoteException e) {
-                    Slog.e(LOG_TAG, "Cannot call into the AttentionService");
-                }
-            } else {
-                Slog.e(LOG_TAG, "Cannot cancel a non-current request");
-            }
+
+            cancel(userState);
         }
     }
 
@@ -272,6 +279,9 @@
     private void disableSelf() {
         final long identity = Binder.clearCallingIdentity();
         try {
+            if (DEBUG) {
+                Slog.d(LOG_TAG, "Disabling self.");
+            }
             Settings.System.putInt(mContext.getContentResolver(), ADAPTIVE_SLEEP, 0);
         } finally {
             Binder.restoreCallingIdentity(identity);
@@ -428,34 +438,21 @@
         }
     }
 
-    private static final class PendingAttentionCheck {
-        private final AttentionCallbackInternal mCallbackInternal;
-        private final Runnable mRunnable;
-
-        PendingAttentionCheck(AttentionCallbackInternal callbackInternal,
-                Runnable runnable) {
-            mCallbackInternal = callbackInternal;
-            mRunnable = runnable;
-        }
-
-        void cancel(@AttentionFailureCodes int failureCode) {
-            mCallbackInternal.onFailure(failureCode);
-        }
-
-        void run() {
-            mRunnable.run();
-        }
-    }
-
     private static final class AttentionCheck {
         private final AttentionCallbackInternal mCallbackInternal;
         private final IAttentionCallback mIAttentionCallback;
+        private boolean mIsDispatched;
+        private boolean mIsFulfilled;
 
         AttentionCheck(AttentionCallbackInternal callbackInternal,
                 IAttentionCallback iAttentionCallback) {
             mCallbackInternal = callbackInternal;
             mIAttentionCallback = iAttentionCallback;
         }
+
+        void cancelInternal() {
+            mCallbackInternal.onFailure(ATTENTION_FAILURE_CANCELLED);
+        }
     }
 
     private static final class UserState {
@@ -469,11 +466,6 @@
         @GuardedBy("mLock")
         AttentionCheck mCurrentAttentionCheck;
         @GuardedBy("mLock")
-        boolean mCurrentAttentionCheckIsFulfilled;
-
-        @GuardedBy("mLock")
-        PendingAttentionCheck mPendingAttentionCheck;
-        @GuardedBy("mLock")
         AttentionCheckCache mAttentionCheckCache;
 
         @UserIdInt
@@ -491,9 +483,17 @@
 
         @GuardedBy("mLock")
         private void handlePendingCallbackLocked() {
-            if (mService != null && mPendingAttentionCheck != null) {
-                mPendingAttentionCheck.run();
-                mPendingAttentionCheck = null;
+            if (!mCurrentAttentionCheck.mIsDispatched) {
+                if (mService != null) {
+                    try {
+                        mService.checkAttention(mCurrentAttentionCheck.mIAttentionCallback);
+                        mCurrentAttentionCheck.mIsDispatched = true;
+                    } catch (RemoteException e) {
+                        Slog.e(LOG_TAG, "Cannot call into the AttentionService");
+                    }
+                } else {
+                    mCurrentAttentionCheck.mCallbackInternal.onFailure(ATTENTION_FAILURE_UNKNOWN);
+                }
             }
         }
 
@@ -526,7 +526,6 @@
             pw.printPair("userId", mUserId);
             synchronized (mLock) {
                 pw.printPair("binding", mBinding);
-                pw.printPair("isAttentionCheckPending", mPendingAttentionCheck != null);
             }
         }
 
@@ -586,14 +585,7 @@
                 // Callee is no longer interested in the attention check result - cancel.
                 case ATTENTION_CHECK_TIMEOUT: {
                     synchronized (mLock) {
-                        final UserState userState = peekCurrentUserStateLocked();
-                        if (userState != null) {
-                            // If not called back already.
-                            if (!userState.mCurrentAttentionCheckIsFulfilled) {
-                                cancel(userState, AttentionService.ATTENTION_FAILURE_TIMED_OUT);
-                            }
-
-                        }
+                        cancel(peekCurrentUserStateLocked());
                     }
                 }
                 break;
@@ -604,19 +596,30 @@
         }
     }
 
-    private void cancel(@NonNull UserState userState, @AttentionFailureCodes int failureCode) {
-        if (userState.mService != null) {
-            try {
-                userState.mService.cancelAttentionCheck(
-                        userState.mCurrentAttentionCheck.mIAttentionCallback);
-            } catch (RemoteException e) {
-                Slog.e(LOG_TAG, "Unable to cancel attention check");
-            }
+    private void cancel(UserState userState) {
+        if (userState == null || userState.mCurrentAttentionCheck == null) {
+            return;
+        }
 
-            if (userState.mPendingAttentionCheck != null) {
-                userState.mPendingAttentionCheck.cancel(failureCode);
-                userState.mPendingAttentionCheck = null;
+        if (userState.mCurrentAttentionCheck.mIsFulfilled) {
+            if (DEBUG) {
+                Slog.d(LOG_TAG, "Trying to cancel the check that has been already fulfilled.");
             }
+            return;
+        }
+        userState.mCurrentAttentionCheck.mIsFulfilled = true;
+
+        if (userState.mService == null) {
+            userState.mCurrentAttentionCheck.cancelInternal();
+            return;
+        }
+
+        try {
+            userState.mService.cancelAttentionCheck(
+                    userState.mCurrentAttentionCheck.mIAttentionCallback);
+        } catch (RemoteException e) {
+            Slog.e(LOG_TAG, "Unable to cancel attention check");
+            userState.mCurrentAttentionCheck.cancelInternal();
         }
     }
 
@@ -626,7 +629,12 @@
             if (userState == null) {
                 return;
             }
-            cancel(userState, ATTENTION_FAILURE_UNKNOWN);
+
+            cancel(userState);
+
+            if (userState.mService == null) {
+                return;
+            }
 
             mContext.unbindService(userState.mConnection);
             userState.mConnection.cleanupService();
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 32781a9..3fc2d37 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -855,8 +855,7 @@
 
     public void onSystemReady() {
         mSystemReady = true;
-        sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE,
-                0, 0, null, 0);
+        scheduleLoadSoundEffects();
 
         mDeviceBroker.onSystemReady();
 
@@ -3225,6 +3224,14 @@
     }
 
     /**
+     * Schedule loading samples into the soundpool.
+     * This method can be overridden to schedule loading at a later time.
+     */
+    protected void scheduleLoadSoundEffects() {
+        sendMsg(mAudioHandler, MSG_LOAD_SOUND_EFFECTS, SENDMSG_QUEUE, 0, 0, null, 0);
+    }
+
+    /**
      *  Unloads samples from the sound pool.
      *  This method can be called to free some memory when
      *  sound effects are disabled.
diff --git a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java
index e7181e2..c32ae97 100644
--- a/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java
+++ b/services/core/java/com/android/server/display/whitebalance/DisplayWhiteBalanceController.java
@@ -271,7 +271,7 @@
         final long time = System.currentTimeMillis();
         float ambientColorTemperature = mColorTemperatureFilter.getEstimate(time);
 
-        if (mAmbientToDisplayColorTemperatureSpline != null) {
+        if (mAmbientToDisplayColorTemperatureSpline != null && ambientColorTemperature != -1.0f) {
             ambientColorTemperature =
                 mAmbientToDisplayColorTemperatureSpline.interpolate(ambientColorTemperature);
         }
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 647e952..6f1929f 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -231,6 +231,7 @@
             Context.BIND_AUTO_CREATE
             | Context.BIND_TREAT_LIKE_ACTIVITY
             | Context.BIND_FOREGROUND_SERVICE
+            | Context.BIND_INCLUDE_CAPABILITIES
             | Context.BIND_SHOWING_UI
             | Context.BIND_SCHEDULE_LIKE_TOP_APP;
 
diff --git a/services/core/java/com/android/server/location/GnssNetworkConnectivityHandler.java b/services/core/java/com/android/server/location/GnssNetworkConnectivityHandler.java
index ab75b21..2948aaf 100644
--- a/services/core/java/com/android/server/location/GnssNetworkConnectivityHandler.java
+++ b/services/core/java/com/android/server/location/GnssNetworkConnectivityHandler.java
@@ -199,29 +199,27 @@
     }
 
     /**
-     * called from native code to update AGPS status
+     * Called from native code to update AGPS connection status, or to request or release a SUPL
+     * connection.
+     *
+     * <p>Note: {@code suplIpAddr} parameter is not present from IAGnssCallback.hal@2.0 onwards
+     * and is set to {@code null}.
      */
     void onReportAGpsStatus(int agpsType, int agpsStatus, byte[] suplIpAddr) {
+        if (DEBUG) Log.d(TAG, "AGPS_DATA_CONNECTION: " + agpsDataConnStatusAsString(agpsStatus));
         switch (agpsStatus) {
             case GPS_REQUEST_AGPS_DATA_CONN:
-                if (DEBUG) Log.d(TAG, "GPS_REQUEST_AGPS_DATA_CONN");
                 runOnHandler(() -> handleRequestSuplConnection(agpsType, suplIpAddr));
                 break;
             case GPS_RELEASE_AGPS_DATA_CONN:
-                if (DEBUG) Log.d(TAG, "GPS_RELEASE_AGPS_DATA_CONN");
                 runOnHandler(() -> handleReleaseSuplConnection(GPS_RELEASE_AGPS_DATA_CONN));
                 break;
             case GPS_AGPS_DATA_CONNECTED:
-                if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONNECTED");
-                break;
             case GPS_AGPS_DATA_CONN_DONE:
-                if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_DONE");
-                break;
             case GPS_AGPS_DATA_CONN_FAILED:
-                if (DEBUG) Log.d(TAG, "GPS_AGPS_DATA_CONN_FAILED");
                 break;
             default:
-                if (DEBUG) Log.d(TAG, "Received Unknown AGPS status: " + agpsStatus);
+                Log.w(TAG, "Received unknown AGPS status: " + agpsStatus);
         }
     }
 
@@ -459,11 +457,17 @@
         }
         mAGpsDataConnectionState = AGPS_DATA_CONNECTION_OPENING;
 
-        NetworkRequest.Builder requestBuilder = new NetworkRequest.Builder();
-        requestBuilder.addCapability(getNetworkCapability(mAGpsType));
-        NetworkRequest request = requestBuilder.build();
+        // The NetworkRequest.Builder class is not used to construct the network request because
+        // the ConnectivityService requires the network request to be constructed in this way
+        // to extend support for requestRouteToHostAddress() method for pre-gnss@2.0 devices.
+        NetworkCapabilities networkCapabilities = new NetworkCapabilities();
+        networkCapabilities.addTransportType(NetworkCapabilities.TRANSPORT_CELLULAR);
+        networkCapabilities.addCapability(getNetworkCapability(mAGpsType));
+        NetworkRequest networkRequest = new NetworkRequest(networkCapabilities,
+                getLegacyDataConnectionType(agpsType), ConnectivityManager.REQUEST_ID_UNSET,
+                NetworkRequest.Type.REQUEST);
         mConnMgr.requestNetwork(
-                request,
+                networkRequest,
                 mSuplConnectivityCallback,
                 mHandler,
                 SUPL_NETWORK_REQUEST_TIMEOUT_MILLIS);
@@ -483,6 +487,19 @@
         }
     }
 
+    private int getLegacyDataConnectionType(int agpsType) {
+        switch (agpsType) {
+            case AGPS_TYPE_C2K:
+            case AGPS_TYPE_SUPL:
+                return ConnectivityManager.TYPE_MOBILE_SUPL;
+            case AGPS_TYPE_EIMS:
+                return ConnectivityManager.TYPE_MOBILE_EMERGENCY;
+            case AGPS_TYPE_IMS:
+                return ConnectivityManager.TYPE_MOBILE_IMS;
+            default:
+                throw new IllegalArgumentException("agpsType: " + agpsType);
+        }
+    }
     private void handleReleaseSuplConnection(int agpsDataConnStatus) {
         if (DEBUG) {
             String message = String.format(
@@ -546,7 +563,7 @@
             case AGPS_DATA_CONNECTION_OPENING:
                 return "OPENING";
             default:
-                return "<Unknown>";
+                return "<Unknown>(" + mAGpsDataConnectionState + ")";
         }
     }
 
@@ -566,7 +583,7 @@
             case GPS_REQUEST_AGPS_DATA_CONN:
                 return "REQUEST";
             default:
-                return "<Unknown>";
+                return "<Unknown>(" + agpsDataConnStatus + ")";
         }
     }
 
@@ -581,7 +598,7 @@
             case AGPS_TYPE_IMS:
                 return "IMS";
             default:
-                return "<Unknown>";
+                return "<Unknown>(" + agpsType + ")";
         }
     }
 
@@ -658,4 +675,4 @@
 
     private native void native_update_network_state(boolean connected, int type, boolean roaming,
             boolean available, String apn, long networkHandle, short capabilities);
-}
\ No newline at end of file
+}
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index f34b2cb..642fa7f 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -38,7 +38,6 @@
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
-import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseBooleanArray;
 import android.util.proto.ProtoOutputStream;
@@ -180,7 +179,7 @@
                                 }
                             }
 
-                            PackagePreferences r = getOrCreatePackagePreferences(name, uid,
+                            PackagePreferences r = getOrCreatePackagePreferencesLocked(name, uid,
                                     XmlUtils.readIntAttribute(
                                             parser, ATT_IMPORTANCE, DEFAULT_IMPORTANCE),
                                     XmlUtils.readIntAttribute(parser, ATT_PRIORITY,
@@ -264,9 +263,9 @@
                             }
 
                             try {
-                                deleteDefaultChannelIfNeeded(r);
+                                deleteDefaultChannelIfNeededLocked(r);
                             } catch (PackageManager.NameNotFoundException e) {
-                                Slog.e(TAG, "deleteDefaultChannelIfNeeded - Exception: " + e);
+                                Slog.e(TAG, "deleteDefaultChannelIfNeededLocked - Exception: " + e);
                             }
                         }
                     }
@@ -276,50 +275,46 @@
         throw new IllegalStateException("Failed to reach END_DOCUMENT");
     }
 
-    private PackagePreferences getPackagePreferences(String pkg, int uid) {
+    private PackagePreferences getPackagePreferencesLocked(String pkg, int uid) {
         final String key = packagePreferencesKey(pkg, uid);
-        synchronized (mPackagePreferences) {
-            return mPackagePreferences.get(key);
-        }
+        return mPackagePreferences.get(key);
     }
 
-    private PackagePreferences getOrCreatePackagePreferences(String pkg, int uid) {
-        return getOrCreatePackagePreferences(pkg, uid,
+    private PackagePreferences getOrCreatePackagePreferencesLocked(String pkg, int uid) {
+        return getOrCreatePackagePreferencesLocked(pkg, uid,
                 DEFAULT_IMPORTANCE, DEFAULT_PRIORITY, DEFAULT_VISIBILITY, DEFAULT_SHOW_BADGE,
                 DEFAULT_ALLOW_BUBBLE);
     }
 
-    private PackagePreferences getOrCreatePackagePreferences(String pkg, int uid, int importance,
-            int priority, int visibility, boolean showBadge, boolean allowBubble) {
+    private PackagePreferences getOrCreatePackagePreferencesLocked(String pkg, int uid,
+            int importance, int priority, int visibility, boolean showBadge, boolean allowBubble) {
         final String key = packagePreferencesKey(pkg, uid);
-        synchronized (mPackagePreferences) {
-            PackagePreferences
-                    r = (uid == UNKNOWN_UID) ? mRestoredWithoutUids.get(pkg)
-                    : mPackagePreferences.get(key);
-            if (r == null) {
-                r = new PackagePreferences();
-                r.pkg = pkg;
-                r.uid = uid;
-                r.importance = importance;
-                r.priority = priority;
-                r.visibility = visibility;
-                r.showBadge = showBadge;
-                r.allowBubble = allowBubble;
+        PackagePreferences
+                r = (uid == UNKNOWN_UID) ? mRestoredWithoutUids.get(pkg)
+                : mPackagePreferences.get(key);
+        if (r == null) {
+            r = new PackagePreferences();
+            r.pkg = pkg;
+            r.uid = uid;
+            r.importance = importance;
+            r.priority = priority;
+            r.visibility = visibility;
+            r.showBadge = showBadge;
+            r.allowBubble = allowBubble;
 
-                try {
-                    createDefaultChannelIfNeeded(r);
-                } catch (PackageManager.NameNotFoundException e) {
-                    Slog.e(TAG, "createDefaultChannelIfNeeded - Exception: " + e);
-                }
-
-                if (r.uid == UNKNOWN_UID) {
-                    mRestoredWithoutUids.put(pkg, r);
-                } else {
-                    mPackagePreferences.put(key, r);
-                }
+            try {
+                createDefaultChannelIfNeededLocked(r);
+            } catch (PackageManager.NameNotFoundException e) {
+                Slog.e(TAG, "createDefaultChannelIfNeededLocked - Exception: " + e);
             }
-            return r;
+
+            if (r.uid == UNKNOWN_UID) {
+                mRestoredWithoutUids.put(pkg, r);
+            } else {
+                mPackagePreferences.put(key, r);
+            }
         }
+        return r;
     }
 
     private boolean shouldHaveDefaultChannel(PackagePreferences r) throws
@@ -336,7 +331,7 @@
         return true;
     }
 
-    private void deleteDefaultChannelIfNeeded(PackagePreferences r) throws
+    private void deleteDefaultChannelIfNeededLocked(PackagePreferences r) throws
             PackageManager.NameNotFoundException {
         if (!r.channels.containsKey(NotificationChannel.DEFAULT_CHANNEL_ID)) {
             // Not present
@@ -352,7 +347,7 @@
         r.channels.remove(NotificationChannel.DEFAULT_CHANNEL_ID);
     }
 
-    private void createDefaultChannelIfNeeded(PackagePreferences r) throws
+    private void createDefaultChannelIfNeededLocked(PackagePreferences r) throws
             PackageManager.NameNotFoundException {
         if (r.channels.containsKey(NotificationChannel.DEFAULT_CHANNEL_ID)) {
             r.channels.get(NotificationChannel.DEFAULT_CHANNEL_ID).setName(mContext.getString(
@@ -479,9 +474,11 @@
      * @param allowed whether bubbles are allowed.
      */
     public void setBubblesAllowed(String pkg, int uid, boolean allowed) {
-        PackagePreferences p = getOrCreatePackagePreferences(pkg, uid);
-        p.allowBubble = allowed;
-        p.lockedAppFields = p.lockedAppFields | LockableAppFields.USER_LOCKED_BUBBLE;
+        synchronized (mPackagePreferences) {
+            PackagePreferences p = getOrCreatePackagePreferencesLocked(pkg, uid);
+            p.allowBubble = allowed;
+            p.lockedAppFields = p.lockedAppFields | LockableAppFields.USER_LOCKED_BUBBLE;
+        }
     }
 
     /**
@@ -493,11 +490,15 @@
      */
     @Override
     public boolean areBubblesAllowed(String pkg, int uid) {
-        return getOrCreatePackagePreferences(pkg, uid).allowBubble;
+        synchronized (mPackagePreferences) {
+            return getOrCreatePackagePreferencesLocked(pkg, uid).allowBubble;
+        }
     }
 
     public int getAppLockedFields(String pkg, int uid) {
-        return getOrCreatePackagePreferences(pkg, uid).lockedAppFields;
+        synchronized (mPackagePreferences) {
+            return getOrCreatePackagePreferencesLocked(pkg, uid).lockedAppFields;
+        }
     }
 
     /**
@@ -505,7 +506,9 @@
      */
     @Override
     public int getImportance(String packageName, int uid) {
-        return getOrCreatePackagePreferences(packageName, uid).importance;
+        synchronized (mPackagePreferences) {
+            return getOrCreatePackagePreferencesLocked(packageName, uid).importance;
+        }
     }
 
     /**
@@ -514,18 +517,24 @@
      * locking field, see {@link NotificationChannel#USER_LOCKED_IMPORTANCE}.
      */
     public boolean getIsAppImportanceLocked(String packageName, int uid) {
-        int userLockedFields = getOrCreatePackagePreferences(packageName, uid).lockedAppFields;
-        return (userLockedFields & LockableAppFields.USER_LOCKED_IMPORTANCE) != 0;
+        synchronized (mPackagePreferences) {
+            int userLockedFields = getOrCreatePackagePreferencesLocked(packageName, uid).lockedAppFields;
+            return (userLockedFields & LockableAppFields.USER_LOCKED_IMPORTANCE) != 0;
+        }
     }
 
     @Override
     public boolean canShowBadge(String packageName, int uid) {
-        return getOrCreatePackagePreferences(packageName, uid).showBadge;
+        synchronized (mPackagePreferences) {
+            return getOrCreatePackagePreferencesLocked(packageName, uid).showBadge;
+        }
     }
 
     @Override
     public void setShowBadge(String packageName, int uid, boolean showBadge) {
-        getOrCreatePackagePreferences(packageName, uid).showBadge = showBadge;
+        synchronized (mPackagePreferences) {
+            getOrCreatePackagePreferencesLocked(packageName, uid).showBadge = showBadge;
+        }
         updateConfig();
     }
 
@@ -534,20 +543,26 @@
         if (groupId == null) {
             return false;
         }
-        PackagePreferences r = getOrCreatePackagePreferences(packageName, uid);
-        NotificationChannelGroup group = r.groups.get(groupId);
-        if (group == null) {
-            return false;
+        synchronized (mPackagePreferences) {
+            PackagePreferences r = getOrCreatePackagePreferencesLocked(packageName, uid);
+            NotificationChannelGroup group = r.groups.get(groupId);
+            if (group == null) {
+                return false;
+            }
+            return group.isBlocked();
         }
-        return group.isBlocked();
     }
 
     int getPackagePriority(String pkg, int uid) {
-        return getOrCreatePackagePreferences(pkg, uid).priority;
+        synchronized (mPackagePreferences) {
+            return getOrCreatePackagePreferencesLocked(pkg, uid).priority;
+        }
     }
 
     int getPackageVisibility(String pkg, int uid) {
-        return getOrCreatePackagePreferences(pkg, uid).visibility;
+        synchronized (mPackagePreferences) {
+            return getOrCreatePackagePreferencesLocked(pkg, uid).visibility;
+        }
     }
 
     @Override
@@ -557,32 +572,34 @@
         Preconditions.checkNotNull(group);
         Preconditions.checkNotNull(group.getId());
         Preconditions.checkNotNull(!TextUtils.isEmpty(group.getName()));
-        PackagePreferences r = getOrCreatePackagePreferences(pkg, uid);
-        if (r == null) {
-            throw new IllegalArgumentException("Invalid package");
-        }
-        final NotificationChannelGroup oldGroup = r.groups.get(group.getId());
-        if (!group.equals(oldGroup)) {
-            // will log for new entries as well as name/description changes
-            MetricsLogger.action(getChannelGroupLog(group.getId(), pkg));
-        }
-        if (oldGroup != null) {
-            group.setChannels(oldGroup.getChannels());
+        synchronized (mPackagePreferences) {
+            PackagePreferences r = getOrCreatePackagePreferencesLocked(pkg, uid);
+            if (r == null) {
+                throw new IllegalArgumentException("Invalid package");
+            }
+            final NotificationChannelGroup oldGroup = r.groups.get(group.getId());
+            if (!group.equals(oldGroup)) {
+                // will log for new entries as well as name/description changes
+                MetricsLogger.action(getChannelGroupLog(group.getId(), pkg));
+            }
+            if (oldGroup != null) {
+                group.setChannels(oldGroup.getChannels());
 
-            // apps can't update the blocked status or app overlay permission
-            if (fromTargetApp) {
-                group.setBlocked(oldGroup.isBlocked());
-                group.unlockFields(group.getUserLockedFields());
-                group.lockFields(oldGroup.getUserLockedFields());
-            } else {
-                // but the system can
-                if (group.isBlocked() != oldGroup.isBlocked()) {
-                    group.lockFields(NotificationChannelGroup.USER_LOCKED_BLOCKED_STATE);
-                    updateChannelsBypassingDnd(mContext.getUserId());
+                // apps can't update the blocked status or app overlay permission
+                if (fromTargetApp) {
+                    group.setBlocked(oldGroup.isBlocked());
+                    group.unlockFields(group.getUserLockedFields());
+                    group.lockFields(oldGroup.getUserLockedFields());
+                } else {
+                    // but the system can
+                    if (group.isBlocked() != oldGroup.isBlocked()) {
+                        group.lockFields(NotificationChannelGroup.USER_LOCKED_BLOCKED_STATE);
+                        updateChannelsBypassingDnd(mContext.getUserId());
+                    }
                 }
             }
+            r.groups.put(group.getId(), group);
         }
-        r.groups.put(group.getId(), group);
     }
 
     @Override
@@ -592,94 +609,96 @@
         Preconditions.checkNotNull(channel);
         Preconditions.checkNotNull(channel.getId());
         Preconditions.checkArgument(!TextUtils.isEmpty(channel.getName()));
-        PackagePreferences r = getOrCreatePackagePreferences(pkg, uid);
-        if (r == null) {
-            throw new IllegalArgumentException("Invalid package");
-        }
-        if (channel.getGroup() != null && !r.groups.containsKey(channel.getGroup())) {
-            throw new IllegalArgumentException("NotificationChannelGroup doesn't exist");
-        }
-        if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channel.getId())) {
-            throw new IllegalArgumentException("Reserved id");
-        }
-        NotificationChannel existing = r.channels.get(channel.getId());
-        // Keep most of the existing settings
-        if (existing != null && fromTargetApp) {
-            if (existing.isDeleted()) {
-                existing.setDeleted(false);
+        synchronized (mPackagePreferences) {
+            PackagePreferences r = getOrCreatePackagePreferencesLocked(pkg, uid);
+            if (r == null) {
+                throw new IllegalArgumentException("Invalid package");
+            }
+            if (channel.getGroup() != null && !r.groups.containsKey(channel.getGroup())) {
+                throw new IllegalArgumentException("NotificationChannelGroup doesn't exist");
+            }
+            if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(channel.getId())) {
+                throw new IllegalArgumentException("Reserved id");
+            }
+            NotificationChannel existing = r.channels.get(channel.getId());
+            // Keep most of the existing settings
+            if (existing != null && fromTargetApp) {
+                if (existing.isDeleted()) {
+                    existing.setDeleted(false);
 
-                // log a resurrected channel as if it's new again
-                MetricsLogger.action(getChannelLog(channel, pkg).setType(
-                        com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_OPEN));
+                    // log a resurrected channel as if it's new again
+                    MetricsLogger.action(getChannelLog(channel, pkg).setType(
+                            com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_OPEN));
+                }
+
+                existing.setName(channel.getName().toString());
+                existing.setDescription(channel.getDescription());
+                existing.setBlockableSystem(channel.isBlockableSystem());
+                if (existing.getGroup() == null) {
+                    existing.setGroup(channel.getGroup());
+                }
+
+                // Apps are allowed to downgrade channel importance if the user has not changed any
+                // fields on this channel yet.
+                final int previousExistingImportance = existing.getImportance();
+                if (existing.getUserLockedFields() == 0 &&
+                        channel.getImportance() < existing.getImportance()) {
+                    existing.setImportance(channel.getImportance());
+                }
+
+                // system apps and dnd access apps can bypass dnd if the user hasn't changed any
+                // fields on the channel yet
+                if (existing.getUserLockedFields() == 0 && hasDndAccess) {
+                    boolean bypassDnd = channel.canBypassDnd();
+                    existing.setBypassDnd(bypassDnd);
+
+                    if (bypassDnd != mAreChannelsBypassingDnd
+                            || previousExistingImportance != existing.getImportance()) {
+                        updateChannelsBypassingDnd(mContext.getUserId());
+                    }
+                }
+
+                updateConfig();
+                return;
+            }
+            if (channel.getImportance() < IMPORTANCE_NONE
+                    || channel.getImportance() > NotificationManager.IMPORTANCE_MAX) {
+                throw new IllegalArgumentException("Invalid importance level");
             }
 
-            existing.setName(channel.getName().toString());
-            existing.setDescription(channel.getDescription());
-            existing.setBlockableSystem(channel.isBlockableSystem());
-            if (existing.getGroup() == null) {
-                existing.setGroup(channel.getGroup());
+            // Reset fields that apps aren't allowed to set.
+            if (fromTargetApp && !hasDndAccess) {
+                channel.setBypassDnd(r.priority == Notification.PRIORITY_MAX);
             }
-
-            // Apps are allowed to downgrade channel importance if the user has not changed any
-            // fields on this channel yet.
-            final int previousExistingImportance = existing.getImportance();
-            if (existing.getUserLockedFields() == 0 &&
-                    channel.getImportance() < existing.getImportance()) {
-                existing.setImportance(channel.getImportance());
+            if (fromTargetApp) {
+                channel.setLockscreenVisibility(r.visibility);
             }
-
-            // system apps and dnd access apps can bypass dnd if the user hasn't changed any
-            // fields on the channel yet
-            if (existing.getUserLockedFields() == 0 && hasDndAccess) {
-                boolean bypassDnd = channel.canBypassDnd();
-                existing.setBypassDnd(bypassDnd);
-
-                if (bypassDnd != mAreChannelsBypassingDnd
-                        || previousExistingImportance != existing.getImportance()) {
-                    updateChannelsBypassingDnd(mContext.getUserId());
+            clearLockedFieldsLocked(channel);
+            channel.setImportanceLockedByOEM(r.oemLockedImportance);
+            if (!channel.isImportanceLockedByOEM()) {
+                if (r.futureOemLockedChannels.remove(channel.getId())) {
+                    channel.setImportanceLockedByOEM(true);
                 }
             }
-
-            updateConfig();
-            return;
-        }
-        if (channel.getImportance() < IMPORTANCE_NONE
-                || channel.getImportance() > NotificationManager.IMPORTANCE_MAX) {
-            throw new IllegalArgumentException("Invalid importance level");
-        }
-
-        // Reset fields that apps aren't allowed to set.
-        if (fromTargetApp && !hasDndAccess) {
-            channel.setBypassDnd(r.priority == Notification.PRIORITY_MAX);
-        }
-        if (fromTargetApp) {
-            channel.setLockscreenVisibility(r.visibility);
-        }
-        clearLockedFields(channel);
-        channel.setImportanceLockedByOEM(r.oemLockedImportance);
-        if (!channel.isImportanceLockedByOEM()) {
-            if (r.futureOemLockedChannels.remove(channel.getId())) {
-                channel.setImportanceLockedByOEM(true);
+            channel.setImportanceLockedByCriticalDeviceFunction(r.defaultAppLockedImportance);
+            if (channel.getLockscreenVisibility() == Notification.VISIBILITY_PUBLIC) {
+                channel.setLockscreenVisibility(
+                        NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE);
             }
-        }
-        channel.setImportanceLockedByCriticalDeviceFunction(r.defaultAppLockedImportance);
-        if (channel.getLockscreenVisibility() == Notification.VISIBILITY_PUBLIC) {
-            channel.setLockscreenVisibility(
-                    NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE);
-        }
-        if (!r.showBadge) {
-            channel.setShowBadge(false);
-        }
+            if (!r.showBadge) {
+                channel.setShowBadge(false);
+            }
 
-        r.channels.put(channel.getId(), channel);
-        if (channel.canBypassDnd() != mAreChannelsBypassingDnd) {
-            updateChannelsBypassingDnd(mContext.getUserId());
+            r.channels.put(channel.getId(), channel);
+            if (channel.canBypassDnd() != mAreChannelsBypassingDnd) {
+                updateChannelsBypassingDnd(mContext.getUserId());
+            }
+            MetricsLogger.action(getChannelLog(channel, pkg).setType(
+                    com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_OPEN));
         }
-        MetricsLogger.action(getChannelLog(channel, pkg).setType(
-                com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_OPEN));
     }
 
-    void clearLockedFields(NotificationChannel channel) {
+    void clearLockedFieldsLocked(NotificationChannel channel) {
         channel.unlockFields(channel.getUserLockedFields());
     }
 
@@ -688,55 +707,58 @@
             boolean fromUser) {
         Preconditions.checkNotNull(updatedChannel);
         Preconditions.checkNotNull(updatedChannel.getId());
-        PackagePreferences r = getOrCreatePackagePreferences(pkg, uid);
-        if (r == null) {
-            throw new IllegalArgumentException("Invalid package");
-        }
-        NotificationChannel channel = r.channels.get(updatedChannel.getId());
-        if (channel == null || channel.isDeleted()) {
-            throw new IllegalArgumentException("Channel does not exist");
-        }
-        if (updatedChannel.getLockscreenVisibility() == Notification.VISIBILITY_PUBLIC) {
-            updatedChannel.setLockscreenVisibility(
-                    NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE);
-        }
-        if (fromUser) {
-            updatedChannel.lockFields(channel.getUserLockedFields());
-            lockFieldsForUpdate(channel, updatedChannel);
-        } else {
-            updatedChannel.unlockFields(updatedChannel.getUserLockedFields());
-        }
-        // no importance updates are allowed if OEM blocked it
-        updatedChannel.setImportanceLockedByOEM(channel.isImportanceLockedByOEM());
-        if (updatedChannel.isImportanceLockedByOEM()) {
-            updatedChannel.setImportance(channel.getImportance());
-        }
-        updatedChannel.setImportanceLockedByCriticalDeviceFunction(r.defaultAppLockedImportance);
-        if (updatedChannel.isImportanceLockedByCriticalDeviceFunction()) {
-            updatedChannel.setImportance(channel.getImportance());
-        }
+        synchronized (mPackagePreferences) {
+            PackagePreferences r = getOrCreatePackagePreferencesLocked(pkg, uid);
+            if (r == null) {
+                throw new IllegalArgumentException("Invalid package");
+            }
+            NotificationChannel channel = r.channels.get(updatedChannel.getId());
+            if (channel == null || channel.isDeleted()) {
+                throw new IllegalArgumentException("Channel does not exist");
+            }
+            if (updatedChannel.getLockscreenVisibility() == Notification.VISIBILITY_PUBLIC) {
+                updatedChannel.setLockscreenVisibility(
+                        NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE);
+            }
+            if (fromUser) {
+                updatedChannel.lockFields(channel.getUserLockedFields());
+                lockFieldsForUpdateLocked(channel, updatedChannel);
+            } else {
+                updatedChannel.unlockFields(updatedChannel.getUserLockedFields());
+            }
+            // no importance updates are allowed if OEM blocked it
+            updatedChannel.setImportanceLockedByOEM(channel.isImportanceLockedByOEM());
+            if (updatedChannel.isImportanceLockedByOEM()) {
+                updatedChannel.setImportance(channel.getImportance());
+            }
+            updatedChannel.setImportanceLockedByCriticalDeviceFunction(
+                    r.defaultAppLockedImportance);
+            if (updatedChannel.isImportanceLockedByCriticalDeviceFunction()) {
+                updatedChannel.setImportance(channel.getImportance());
+            }
 
-        r.channels.put(updatedChannel.getId(), updatedChannel);
+            r.channels.put(updatedChannel.getId(), updatedChannel);
 
-        if (onlyHasDefaultChannel(pkg, uid)) {
-            // copy settings to app level so they are inherited by new channels
-            // when the app migrates
-            r.importance = updatedChannel.getImportance();
-            r.priority = updatedChannel.canBypassDnd()
-                    ? Notification.PRIORITY_MAX : Notification.PRIORITY_DEFAULT;
-            r.visibility = updatedChannel.getLockscreenVisibility();
-            r.showBadge = updatedChannel.canShowBadge();
-        }
+            if (onlyHasDefaultChannel(pkg, uid)) {
+                // copy settings to app level so they are inherited by new channels
+                // when the app migrates
+                r.importance = updatedChannel.getImportance();
+                r.priority = updatedChannel.canBypassDnd()
+                        ? Notification.PRIORITY_MAX : Notification.PRIORITY_DEFAULT;
+                r.visibility = updatedChannel.getLockscreenVisibility();
+                r.showBadge = updatedChannel.canShowBadge();
+            }
 
-        if (!channel.equals(updatedChannel)) {
-            // only log if there are real changes
-            MetricsLogger.action(getChannelLog(updatedChannel, pkg)
-                    .setSubtype(fromUser ? 1 : 0));
-        }
+            if (!channel.equals(updatedChannel)) {
+                // only log if there are real changes
+                MetricsLogger.action(getChannelLog(updatedChannel, pkg)
+                        .setSubtype(fromUser ? 1 : 0));
+            }
 
-        if (updatedChannel.canBypassDnd() != mAreChannelsBypassingDnd
-                || channel.getImportance() != updatedChannel.getImportance()) {
-            updateChannelsBypassingDnd(mContext.getUserId());
+            if (updatedChannel.canBypassDnd() != mAreChannelsBypassingDnd
+                    || channel.getImportance() != updatedChannel.getImportance()) {
+                updateChannelsBypassingDnd(mContext.getUserId());
+            }
         }
         updateConfig();
     }
@@ -745,35 +767,39 @@
     public NotificationChannel getNotificationChannel(String pkg, int uid, String channelId,
             boolean includeDeleted) {
         Preconditions.checkNotNull(pkg);
-        PackagePreferences r = getOrCreatePackagePreferences(pkg, uid);
-        if (r == null) {
+        synchronized (mPackagePreferences) {
+            PackagePreferences r = getOrCreatePackagePreferencesLocked(pkg, uid);
+            if (r == null) {
+                return null;
+            }
+            if (channelId == null) {
+                channelId = NotificationChannel.DEFAULT_CHANNEL_ID;
+            }
+            final NotificationChannel nc = r.channels.get(channelId);
+            if (nc != null && (includeDeleted || !nc.isDeleted())) {
+                return nc;
+            }
             return null;
         }
-        if (channelId == null) {
-            channelId = NotificationChannel.DEFAULT_CHANNEL_ID;
-        }
-        final NotificationChannel nc = r.channels.get(channelId);
-        if (nc != null && (includeDeleted || !nc.isDeleted())) {
-            return nc;
-        }
-        return null;
     }
 
     @Override
     public void deleteNotificationChannel(String pkg, int uid, String channelId) {
-        PackagePreferences r = getPackagePreferences(pkg, uid);
-        if (r == null) {
-            return;
-        }
-        NotificationChannel channel = r.channels.get(channelId);
-        if (channel != null) {
-            channel.setDeleted(true);
-            LogMaker lm = getChannelLog(channel, pkg);
-            lm.setType(com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_CLOSE);
-            MetricsLogger.action(lm);
+        synchronized (mPackagePreferences) {
+            PackagePreferences r = getPackagePreferencesLocked(pkg, uid);
+            if (r == null) {
+                return;
+            }
+            NotificationChannel channel = r.channels.get(channelId);
+            if (channel != null) {
+                channel.setDeleted(true);
+                LogMaker lm = getChannelLog(channel, pkg);
+                lm.setType(com.android.internal.logging.nano.MetricsProto.MetricsEvent.TYPE_CLOSE);
+                MetricsLogger.action(lm);
 
-            if (mAreChannelsBypassingDnd && channel.canBypassDnd()) {
-                updateChannelsBypassingDnd(mContext.getUserId());
+                if (mAreChannelsBypassingDnd && channel.canBypassDnd()) {
+                    updateChannelsBypassingDnd(mContext.getUserId());
+                }
             }
         }
     }
@@ -783,25 +809,29 @@
     public void permanentlyDeleteNotificationChannel(String pkg, int uid, String channelId) {
         Preconditions.checkNotNull(pkg);
         Preconditions.checkNotNull(channelId);
-        PackagePreferences r = getPackagePreferences(pkg, uid);
-        if (r == null) {
-            return;
+        synchronized (mPackagePreferences) {
+            PackagePreferences r = getPackagePreferencesLocked(pkg, uid);
+            if (r == null) {
+                return;
+            }
+            r.channels.remove(channelId);
         }
-        r.channels.remove(channelId);
     }
 
     @Override
     public void permanentlyDeleteNotificationChannels(String pkg, int uid) {
         Preconditions.checkNotNull(pkg);
-        PackagePreferences r = getPackagePreferences(pkg, uid);
-        if (r == null) {
-            return;
-        }
-        int N = r.channels.size() - 1;
-        for (int i = N; i >= 0; i--) {
-            String key = r.channels.keyAt(i);
-            if (!NotificationChannel.DEFAULT_CHANNEL_ID.equals(key)) {
-                r.channels.remove(key);
+        synchronized (mPackagePreferences) {
+            PackagePreferences r = getPackagePreferencesLocked(pkg, uid);
+            if (r == null) {
+                return;
+            }
+            int N = r.channels.size() - 1;
+            for (int i = N; i >= 0; i--) {
+                String key = r.channels.keyAt(i);
+                if (!NotificationChannel.DEFAULT_CHANNEL_ID.equals(key)) {
+                    r.channels.remove(key);
+                }
             }
         }
     }
@@ -875,32 +905,36 @@
     public NotificationChannelGroup getNotificationChannelGroupWithChannels(String pkg,
             int uid, String groupId, boolean includeDeleted) {
         Preconditions.checkNotNull(pkg);
-        PackagePreferences r = getPackagePreferences(pkg, uid);
-        if (r == null || groupId == null || !r.groups.containsKey(groupId)) {
-            return null;
-        }
-        NotificationChannelGroup group = r.groups.get(groupId).clone();
-        group.setChannels(new ArrayList<>());
-        int N = r.channels.size();
-        for (int i = 0; i < N; i++) {
-            final NotificationChannel nc = r.channels.valueAt(i);
-            if (includeDeleted || !nc.isDeleted()) {
-                if (groupId.equals(nc.getGroup())) {
-                    group.addChannel(nc);
+        synchronized (mPackagePreferences) {
+            PackagePreferences r = getPackagePreferencesLocked(pkg, uid);
+            if (r == null || groupId == null || !r.groups.containsKey(groupId)) {
+                return null;
+            }
+            NotificationChannelGroup group = r.groups.get(groupId).clone();
+            group.setChannels(new ArrayList<>());
+            int N = r.channels.size();
+            for (int i = 0; i < N; i++) {
+                final NotificationChannel nc = r.channels.valueAt(i);
+                if (includeDeleted || !nc.isDeleted()) {
+                    if (groupId.equals(nc.getGroup())) {
+                        group.addChannel(nc);
+                    }
                 }
             }
+            return group;
         }
-        return group;
     }
 
     public NotificationChannelGroup getNotificationChannelGroup(String groupId, String pkg,
             int uid) {
         Preconditions.checkNotNull(pkg);
-        PackagePreferences r = getPackagePreferences(pkg, uid);
-        if (r == null) {
-            return null;
+        synchronized (mPackagePreferences) {
+            PackagePreferences r = getPackagePreferencesLocked(pkg, uid);
+            if (r == null) {
+                return null;
+            }
+            return r.groups.get(groupId);
         }
-        return r.groups.get(groupId);
     }
 
     @Override
@@ -908,60 +942,64 @@
             int uid, boolean includeDeleted, boolean includeNonGrouped, boolean includeEmpty) {
         Preconditions.checkNotNull(pkg);
         Map<String, NotificationChannelGroup> groups = new ArrayMap<>();
-        PackagePreferences r = getPackagePreferences(pkg, uid);
-        if (r == null) {
-            return ParceledListSlice.emptyList();
-        }
-        NotificationChannelGroup nonGrouped = new NotificationChannelGroup(null, null);
-        int N = r.channels.size();
-        for (int i = 0; i < N; i++) {
-            final NotificationChannel nc = r.channels.valueAt(i);
-            if (includeDeleted || !nc.isDeleted()) {
-                if (nc.getGroup() != null) {
-                    if (r.groups.get(nc.getGroup()) != null) {
-                        NotificationChannelGroup ncg = groups.get(nc.getGroup());
-                        if (ncg == null) {
-                            ncg = r.groups.get(nc.getGroup()).clone();
-                            ncg.setChannels(new ArrayList<>());
-                            groups.put(nc.getGroup(), ncg);
+        synchronized (mPackagePreferences) {
+            PackagePreferences r = getPackagePreferencesLocked(pkg, uid);
+            if (r == null) {
+                return ParceledListSlice.emptyList();
+            }
+            NotificationChannelGroup nonGrouped = new NotificationChannelGroup(null, null);
+            int N = r.channels.size();
+            for (int i = 0; i < N; i++) {
+                final NotificationChannel nc = r.channels.valueAt(i);
+                if (includeDeleted || !nc.isDeleted()) {
+                    if (nc.getGroup() != null) {
+                        if (r.groups.get(nc.getGroup()) != null) {
+                            NotificationChannelGroup ncg = groups.get(nc.getGroup());
+                            if (ncg == null) {
+                                ncg = r.groups.get(nc.getGroup()).clone();
+                                ncg.setChannels(new ArrayList<>());
+                                groups.put(nc.getGroup(), ncg);
 
+                            }
+                            ncg.addChannel(nc);
                         }
-                        ncg.addChannel(nc);
+                    } else {
+                        nonGrouped.addChannel(nc);
                     }
-                } else {
-                    nonGrouped.addChannel(nc);
                 }
             }
-        }
-        if (includeNonGrouped && nonGrouped.getChannels().size() > 0) {
-            groups.put(null, nonGrouped);
-        }
-        if (includeEmpty) {
-            for (NotificationChannelGroup group : r.groups.values()) {
-                if (!groups.containsKey(group.getId())) {
-                    groups.put(group.getId(), group);
+            if (includeNonGrouped && nonGrouped.getChannels().size() > 0) {
+                groups.put(null, nonGrouped);
+            }
+            if (includeEmpty) {
+                for (NotificationChannelGroup group : r.groups.values()) {
+                    if (!groups.containsKey(group.getId())) {
+                        groups.put(group.getId(), group);
+                    }
                 }
             }
+            return new ParceledListSlice<>(new ArrayList<>(groups.values()));
         }
-        return new ParceledListSlice<>(new ArrayList<>(groups.values()));
     }
 
     public List<NotificationChannel> deleteNotificationChannelGroup(String pkg, int uid,
             String groupId) {
         List<NotificationChannel> deletedChannels = new ArrayList<>();
-        PackagePreferences r = getPackagePreferences(pkg, uid);
-        if (r == null || TextUtils.isEmpty(groupId)) {
-            return deletedChannels;
-        }
+        synchronized (mPackagePreferences) {
+            PackagePreferences r = getPackagePreferencesLocked(pkg, uid);
+            if (r == null || TextUtils.isEmpty(groupId)) {
+                return deletedChannels;
+            }
 
-        r.groups.remove(groupId);
+            r.groups.remove(groupId);
 
-        int N = r.channels.size();
-        for (int i = 0; i < N; i++) {
-            final NotificationChannel nc = r.channels.valueAt(i);
-            if (groupId.equals(nc.getGroup())) {
-                nc.setDeleted(true);
-                deletedChannels.add(nc);
+            int N = r.channels.size();
+            for (int i = 0; i < N; i++) {
+                final NotificationChannel nc = r.channels.valueAt(i);
+                if (groupId.equals(nc.getGroup())) {
+                    nc.setDeleted(true);
+                    deletedChannels.add(nc);
+                }
             }
         }
         return deletedChannels;
@@ -970,11 +1008,15 @@
     @Override
     public Collection<NotificationChannelGroup> getNotificationChannelGroups(String pkg,
             int uid) {
-        PackagePreferences r = getPackagePreferences(pkg, uid);
-        if (r == null) {
-            return new ArrayList<>();
+        List<NotificationChannelGroup> groups = new ArrayList<>();
+        synchronized (mPackagePreferences) {
+            PackagePreferences r = getPackagePreferencesLocked(pkg, uid);
+            if (r == null) {
+                return groups;
+            }
+            groups.addAll(r.groups.values());
         }
-        return r.groups.values();
+        return groups;
     }
 
     @Override
@@ -982,18 +1024,20 @@
             boolean includeDeleted) {
         Preconditions.checkNotNull(pkg);
         List<NotificationChannel> channels = new ArrayList<>();
-        PackagePreferences r = getPackagePreferences(pkg, uid);
-        if (r == null) {
-            return ParceledListSlice.emptyList();
-        }
-        int N = r.channels.size();
-        for (int i = 0; i < N; i++) {
-            final NotificationChannel nc = r.channels.valueAt(i);
-            if (includeDeleted || !nc.isDeleted()) {
-                channels.add(nc);
+        synchronized (mPackagePreferences) {
+            PackagePreferences r = getPackagePreferencesLocked(pkg, uid);
+            if (r == null) {
+                return ParceledListSlice.emptyList();
             }
+            int N = r.channels.size();
+            for (int i = 0; i < N; i++) {
+                final NotificationChannel nc = r.channels.valueAt(i);
+                if (includeDeleted || !nc.isDeleted()) {
+                    channels.add(nc);
+                }
+            }
+            return new ParceledListSlice<>(channels);
         }
-        return new ParceledListSlice<>(channels);
     }
 
     /**
@@ -1008,7 +1052,7 @@
             // notifications from this package aren't blocked
             if (r != null && r.importance != IMPORTANCE_NONE) {
                 for (NotificationChannel channel : r.channels.values()) {
-                    if (channelIsLive(r, channel) && channel.canBypassDnd()) {
+                    if (channelIsLiveLocked(r, channel) && channel.canBypassDnd()) {
                         channels.add(channel);
                     }
                 }
@@ -1024,46 +1068,52 @@
      * upgrades.
      */
     public boolean onlyHasDefaultChannel(String pkg, int uid) {
-        PackagePreferences r = getOrCreatePackagePreferences(pkg, uid);
-        if (r.channels.size() == 1
-                && r.channels.containsKey(NotificationChannel.DEFAULT_CHANNEL_ID)) {
-            return true;
+        synchronized (mPackagePreferences) {
+            PackagePreferences r = getOrCreatePackagePreferencesLocked(pkg, uid);
+            if (r.channels.size() == 1
+                    && r.channels.containsKey(NotificationChannel.DEFAULT_CHANNEL_ID)) {
+                return true;
+            }
+            return false;
         }
-        return false;
     }
 
     public int getDeletedChannelCount(String pkg, int uid) {
         Preconditions.checkNotNull(pkg);
         int deletedCount = 0;
-        PackagePreferences r = getPackagePreferences(pkg, uid);
-        if (r == null) {
+        synchronized (mPackagePreferences) {
+            PackagePreferences r = getPackagePreferencesLocked(pkg, uid);
+            if (r == null) {
+                return deletedCount;
+            }
+            int N = r.channels.size();
+            for (int i = 0; i < N; i++) {
+                final NotificationChannel nc = r.channels.valueAt(i);
+                if (nc.isDeleted()) {
+                    deletedCount++;
+                }
+            }
             return deletedCount;
         }
-        int N = r.channels.size();
-        for (int i = 0; i < N; i++) {
-            final NotificationChannel nc = r.channels.valueAt(i);
-            if (nc.isDeleted()) {
-                deletedCount++;
-            }
-        }
-        return deletedCount;
     }
 
     public int getBlockedChannelCount(String pkg, int uid) {
         Preconditions.checkNotNull(pkg);
         int blockedCount = 0;
-        PackagePreferences r = getPackagePreferences(pkg, uid);
-        if (r == null) {
+        synchronized (mPackagePreferences) {
+            PackagePreferences r = getPackagePreferencesLocked(pkg, uid);
+            if (r == null) {
+                return blockedCount;
+            }
+            int N = r.channels.size();
+            for (int i = 0; i < N; i++) {
+                final NotificationChannel nc = r.channels.valueAt(i);
+                if (!nc.isDeleted() && IMPORTANCE_NONE == nc.getImportance()) {
+                    blockedCount++;
+                }
+            }
             return blockedCount;
         }
-        int N = r.channels.size();
-        for (int i = 0; i < N; i++) {
-            final NotificationChannel nc = r.channels.valueAt(i);
-            if (!nc.isDeleted() && IMPORTANCE_NONE == nc.getImportance()) {
-                blockedCount++;
-            }
-        }
-        return blockedCount;
     }
 
     public int getBlockedAppCount(int userId) {
@@ -1098,7 +1148,7 @@
                 }
 
                 for (NotificationChannel channel : r.channels.values()) {
-                    if (channelIsLive(r, channel) && channel.canBypassDnd()) {
+                    if (channelIsLiveLocked(r, channel) && channel.canBypassDnd()) {
                         count++;
                         break;
                     }
@@ -1136,7 +1186,7 @@
                 }
 
                 for (NotificationChannel channel : r.channels.values()) {
-                    if (channelIsLive(r, channel) && channel.canBypassDnd()) {
+                    if (channelIsLiveLocked(r, channel) && channel.canBypassDnd()) {
                         if (!mAreChannelsBypassingDnd) {
                             mAreChannelsBypassingDnd = true;
                             updateZenPolicy(true);
@@ -1153,7 +1203,7 @@
         }
     }
 
-    private boolean channelIsLive(PackagePreferences pkgPref, NotificationChannel channel) {
+    private boolean channelIsLiveLocked(PackagePreferences pkgPref, NotificationChannel channel) {
         // Channel is in a group that's blocked
         if (isGroupBlocked(pkgPref.pkg, pkgPref.uid, channel.getGroup())) {
             return false;
@@ -1185,7 +1235,9 @@
      */
     @Override
     public void setImportance(String pkgName, int uid, int importance) {
-        getOrCreatePackagePreferences(pkgName, uid).importance = importance;
+        synchronized (mPackagePreferences) {
+            getOrCreatePackagePreferencesLocked(pkgName, uid).importance = importance;
+        }
         updateConfig();
     }
 
@@ -1204,12 +1256,15 @@
      * considered for sentiment adjustments (and thus never show a blocking helper).
      */
     public void setAppImportanceLocked(String packageName, int uid) {
-        PackagePreferences prefs = getOrCreatePackagePreferences(packageName, uid);
-        if ((prefs.lockedAppFields & LockableAppFields.USER_LOCKED_IMPORTANCE) != 0) {
-            return;
-        }
+        synchronized (mPackagePreferences) {
+            PackagePreferences prefs = getOrCreatePackagePreferencesLocked(packageName, uid);
+            if ((prefs.lockedAppFields & LockableAppFields.USER_LOCKED_IMPORTANCE) != 0) {
+                return;
+            }
 
-        prefs.lockedAppFields = prefs.lockedAppFields | LockableAppFields.USER_LOCKED_IMPORTANCE;
+            prefs.lockedAppFields =
+                    prefs.lockedAppFields | LockableAppFields.USER_LOCKED_IMPORTANCE;
+        }
         updateConfig();
     }
 
@@ -1217,15 +1272,17 @@
      * Returns the delegate for a given package, if it's allowed by the package and the user.
      */
     public @Nullable String getNotificationDelegate(String sourcePkg, int sourceUid) {
-        PackagePreferences prefs = getPackagePreferences(sourcePkg, sourceUid);
+        synchronized (mPackagePreferences) {
+            PackagePreferences prefs = getPackagePreferencesLocked(sourcePkg, sourceUid);
 
-        if (prefs == null || prefs.delegate == null) {
-            return null;
+            if (prefs == null || prefs.delegate == null) {
+                return null;
+            }
+            if (!prefs.delegate.mUserAllowed || !prefs.delegate.mEnabled) {
+                return null;
+            }
+            return prefs.delegate.mPkg;
         }
-        if (!prefs.delegate.mUserAllowed || !prefs.delegate.mEnabled) {
-            return null;
-        }
-        return prefs.delegate.mPkg;
     }
 
     /**
@@ -1233,11 +1290,13 @@
      */
     public void setNotificationDelegate(String sourcePkg, int sourceUid,
             String delegatePkg, int delegateUid) {
-        PackagePreferences prefs = getOrCreatePackagePreferences(sourcePkg, sourceUid);
+        synchronized (mPackagePreferences) {
+            PackagePreferences prefs = getOrCreatePackagePreferencesLocked(sourcePkg, sourceUid);
 
-        boolean userAllowed = prefs.delegate == null || prefs.delegate.mUserAllowed;
-        Delegate delegate = new Delegate(delegatePkg, delegateUid, true, userAllowed);
-        prefs.delegate = delegate;
+            boolean userAllowed = prefs.delegate == null || prefs.delegate.mUserAllowed;
+            Delegate delegate = new Delegate(delegatePkg, delegateUid, true, userAllowed);
+            prefs.delegate = delegate;
+        }
         updateConfig();
     }
 
@@ -1245,9 +1304,15 @@
      * Used by an app to turn off its notification delegate.
      */
     public void revokeNotificationDelegate(String sourcePkg, int sourceUid) {
-        PackagePreferences prefs = getPackagePreferences(sourcePkg, sourceUid);
-        if (prefs != null && prefs.delegate != null) {
-            prefs.delegate.mEnabled = false;
+        boolean changed = false;
+        synchronized (mPackagePreferences) {
+            PackagePreferences prefs = getPackagePreferencesLocked(sourcePkg, sourceUid);
+            if (prefs != null && prefs.delegate != null) {
+                prefs.delegate.mEnabled = false;
+                changed = true;
+            }
+        }
+        if (changed) {
             updateConfig();
         }
     }
@@ -1256,9 +1321,15 @@
      * Toggles whether an app can have a notification delegate on behalf of a user.
      */
     public void toggleNotificationDelegate(String sourcePkg, int sourceUid, boolean userAllowed) {
-        PackagePreferences prefs = getPackagePreferences(sourcePkg, sourceUid);
-        if (prefs != null && prefs.delegate != null) {
-            prefs.delegate.mUserAllowed = userAllowed;
+        boolean changed = false;
+        synchronized (mPackagePreferences) {
+            PackagePreferences prefs = getPackagePreferencesLocked(sourcePkg, sourceUid);
+            if (prefs != null && prefs.delegate != null) {
+                prefs.delegate.mUserAllowed = userAllowed;
+                changed = true;
+            }
+        }
+        if (changed) {
             updateConfig();
         }
     }
@@ -1269,13 +1340,16 @@
      */
     public boolean isDelegateAllowed(String sourcePkg, int sourceUid,
             String potentialDelegatePkg, int potentialDelegateUid) {
-        PackagePreferences prefs = getPackagePreferences(sourcePkg, sourceUid);
+        synchronized (mPackagePreferences) {
+            PackagePreferences prefs = getPackagePreferencesLocked(sourcePkg, sourceUid);
 
-        return prefs != null && prefs.isValidDelegate(potentialDelegatePkg, potentialDelegateUid);
+            return prefs != null && prefs.isValidDelegate(potentialDelegatePkg,
+                    potentialDelegateUid);
+        }
     }
 
     @VisibleForTesting
-    void lockFieldsForUpdate(NotificationChannel original, NotificationChannel update) {
+    void lockFieldsForUpdateLocked(NotificationChannel original, NotificationChannel update) {
         if (original.canBypassDnd() != update.canBypassDnd()) {
             update.lockFields(NotificationChannel.USER_LOCKED_PRIORITY);
         }
@@ -1309,30 +1383,30 @@
         pw.print(prefix);
         pw.println("per-package config:");
 
-        pw.println("PackagePreferencess:");
+        pw.println("PackagePreferences:");
         synchronized (mPackagePreferences) {
-            dumpPackagePreferencess(pw, prefix, filter, mPackagePreferences);
+            dumpPackagePreferencesLocked(pw, prefix, filter, mPackagePreferences);
         }
         pw.println("Restored without uid:");
-        dumpPackagePreferencess(pw, prefix, filter, mRestoredWithoutUids);
+        dumpPackagePreferencesLocked(pw, prefix, filter, mRestoredWithoutUids);
     }
 
     public void dump(ProtoOutputStream proto,
             @NonNull NotificationManagerService.DumpFilter filter) {
         synchronized (mPackagePreferences) {
-            dumpPackagePreferencess(proto, RankingHelperProto.RECORDS, filter,
+            dumpPackagePreferencesLocked(proto, RankingHelperProto.RECORDS, filter,
                     mPackagePreferences);
         }
-        dumpPackagePreferencess(proto, RankingHelperProto.RECORDS_RESTORED_WITHOUT_UID, filter,
+        dumpPackagePreferencesLocked(proto, RankingHelperProto.RECORDS_RESTORED_WITHOUT_UID, filter,
                 mRestoredWithoutUids);
     }
 
-    private static void dumpPackagePreferencess(PrintWriter pw, String prefix,
+    private static void dumpPackagePreferencesLocked(PrintWriter pw, String prefix,
             @NonNull NotificationManagerService.DumpFilter filter,
-            ArrayMap<String, PackagePreferences> PackagePreferencess) {
-        final int N = PackagePreferencess.size();
+            ArrayMap<String, PackagePreferences> packagePreferences) {
+        final int N = packagePreferences.size();
         for (int i = 0; i < N; i++) {
-            final PackagePreferences r = PackagePreferencess.valueAt(i);
+            final PackagePreferences r = packagePreferences.valueAt(i);
             if (filter.matches(r.pkg)) {
                 pw.print(prefix);
                 pw.print("  AppSettings: ");
@@ -1369,13 +1443,13 @@
         }
     }
 
-    private static void dumpPackagePreferencess(ProtoOutputStream proto, long fieldId,
+    private static void dumpPackagePreferencesLocked(ProtoOutputStream proto, long fieldId,
             @NonNull NotificationManagerService.DumpFilter filter,
-            ArrayMap<String, PackagePreferences> PackagePreferencess) {
-        final int N = PackagePreferencess.size();
+            ArrayMap<String, PackagePreferences> packagePreferences) {
+        final int N = packagePreferences.size();
         long fToken;
         for (int i = 0; i < N; i++) {
-            final PackagePreferences r = PackagePreferencess.valueAt(i);
+            final PackagePreferences r = packagePreferences.valueAt(i);
             if (filter.matches(r.pkg)) {
                 fToken = proto.start(fieldId);
 
@@ -1626,11 +1700,11 @@
                 // Package upgrade
                 try {
                     synchronized (mPackagePreferences) {
-                        PackagePreferences fullPackagePreferences = getPackagePreferences(pkg,
+                        PackagePreferences fullPackagePreferences = getPackagePreferencesLocked(pkg,
                                 mPm.getPackageUidAsUser(pkg, changeUserId));
                         if (fullPackagePreferences != null) {
-                            createDefaultChannelIfNeeded(fullPackagePreferences);
-                            deleteDefaultChannelIfNeeded(fullPackagePreferences);
+                            createDefaultChannelIfNeededLocked(fullPackagePreferences);
+                            deleteDefaultChannelIfNeededLocked(fullPackagePreferences);
                         }
                     }
                 } catch (PackageManager.NameNotFoundException e) {
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index 51d5acc..ee07c7d 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -166,6 +166,13 @@
  *     . . . .  . . . . . . . . . . . . . . . . . .
  * </pre>
  *
+ * <p>To test the OMS, execute:
+ * <code>
+ * atest FrameworksServicesTests:com.android.server.om  # internal tests
+ * atest OverlayDeviceTests OverlayHostTests            # public API tests
+ * </code>
+ * </p>
+ *
  * <p>Finally, here is a list of keywords used in the OMS context.</p>
  *
  * <ul>
diff --git a/services/core/java/com/android/server/om/OverlayManagerSettings.java b/services/core/java/com/android/server/om/OverlayManagerSettings.java
index 36b5beb..f35c707 100644
--- a/services/core/java/com/android/server/om/OverlayManagerSettings.java
+++ b/services/core/java/com/android/server/om/OverlayManagerSettings.java
@@ -26,6 +26,7 @@
 import android.util.Slog;
 import android.util.Xml;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.XmlUtils;
@@ -327,7 +328,8 @@
         Serializer.persist(mItems, os);
     }
 
-    private static final class Serializer {
+    @VisibleForTesting
+    static final class Serializer {
         private static final String TAG_OVERLAYS = "overlays";
         private static final String TAG_ITEM = "item";
 
@@ -343,7 +345,8 @@
         private static final String ATTR_USER_ID = "userId";
         private static final String ATTR_VERSION = "version";
 
-        private static final int CURRENT_VERSION = 3;
+        @VisibleForTesting
+        static final int CURRENT_VERSION = 3;
 
         public static void restore(@NonNull final ArrayList<SettingsItem> table,
                 @NonNull final InputStream is) throws IOException, XmlPullParserException {
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index d52ba16..9908b36 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -2629,7 +2629,8 @@
                     0, null, new UserHandle(serviceUserId)));
             if (!mContext.bindServiceAsUser(intent, newConn,
                     Context.BIND_AUTO_CREATE | Context.BIND_SHOWING_UI
-                            | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
+                            | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE
+                            | Context.BIND_INCLUDE_CAPABILITIES,
                     new UserHandle(serviceUserId))) {
                 String msg = "Unable to bind service: "
                         + componentName;
diff --git a/services/core/java/com/android/server/wm/BoundsAnimationController.java b/services/core/java/com/android/server/wm/BoundsAnimationController.java
index f9980be..c1d872f 100644
--- a/services/core/java/com/android/server/wm/BoundsAnimationController.java
+++ b/services/core/java/com/android/server/wm/BoundsAnimationController.java
@@ -73,6 +73,13 @@
     /** Schedule a PiP mode changed callback when this animation ends. */
     public static final int SCHEDULE_PIP_MODE_CHANGED_ON_END = 2;
 
+    public static final int BOUNDS = 0;
+    public static final int FADE_IN = 1;
+
+    @IntDef({BOUNDS, FADE_IN}) public @interface AnimationType {}
+
+    private static final int FADE_IN_DURATION = 500;
+
     // Only accessed on UI thread.
     private ArrayMap<BoundsAnimationTarget, BoundsAnimator> mRunningAnimations = new ArrayMap<>();
 
@@ -115,6 +122,7 @@
     private boolean mFinishAnimationAfterTransition = false;
     private final AnimationHandler mAnimationHandler;
     private Choreographer mChoreographer;
+    private @AnimationType int mAnimationType;
 
     private static final int WAIT_FOR_DRAW_TIMEOUT_MS = 3000;
 
@@ -140,6 +148,7 @@
             implements ValueAnimator.AnimatorUpdateListener, ValueAnimator.AnimatorListener {
 
         private final BoundsAnimationTarget mTarget;
+        private final @AnimationType int mAnimationType;
         private final Rect mFrom = new Rect();
         private final Rect mTo = new Rect();
         private final Rect mTmpRect = new Rect();
@@ -166,8 +175,8 @@
 
         // Depending on whether we are animating from
         // a smaller to a larger size
-        private final int mFrozenTaskWidth;
-        private final int mFrozenTaskHeight;
+        private int mFrozenTaskWidth;
+        private int mFrozenTaskHeight;
 
         // Timeout callback to ensure we continue the animation if waiting for resuming or app
         // windows drawn fails
@@ -176,12 +185,13 @@
             resume();
         };
 
-        BoundsAnimator(BoundsAnimationTarget target, Rect from, Rect to,
-                @SchedulePipModeChangedState int schedulePipModeChangedState,
+        BoundsAnimator(BoundsAnimationTarget target, @AnimationType int animationType, Rect from,
+                Rect to, @SchedulePipModeChangedState int schedulePipModeChangedState,
                 @SchedulePipModeChangedState int prevShedulePipModeChangedState,
                 boolean moveFromFullscreen, boolean moveToFullscreen, Rect frozenTask) {
             super();
             mTarget = target;
+            mAnimationType = animationType;
             mFrom.set(from);
             mTo.set(to);
             mSchedulePipModeChangedState = schedulePipModeChangedState;
@@ -195,12 +205,14 @@
             // to their final size immediately so we can use scaling to make the window
             // larger. Likewise if we are going from bigger to smaller, we want to wait until
             // the end so we don't have to upscale from the smaller finished size.
-            if (animatingToLargerSize()) {
-                mFrozenTaskWidth = mTo.width();
-                mFrozenTaskHeight = mTo.height();
-            } else {
-                mFrozenTaskWidth = frozenTask.isEmpty() ? mFrom.width() : frozenTask.width();
-                mFrozenTaskHeight = frozenTask.isEmpty() ? mFrom.height() : frozenTask.height();
+            if (mAnimationType == BOUNDS) {
+                if (animatingToLargerSize()) {
+                    mFrozenTaskWidth = mTo.width();
+                    mFrozenTaskHeight = mTo.height();
+                } else {
+                    mFrozenTaskWidth = frozenTask.isEmpty() ? mFrom.width() : frozenTask.width();
+                    mFrozenTaskHeight = frozenTask.isEmpty() ? mFrom.height() : frozenTask.height();
+                }
             }
         }
 
@@ -222,8 +234,9 @@
             // otherwise.
             boolean continueAnimation;
             if (mPrevSchedulePipModeChangedState == NO_PIP_MODE_CHANGED_CALLBACKS) {
-                continueAnimation = mTarget.onAnimationStart(mSchedulePipModeChangedState ==
-                        SCHEDULE_PIP_MODE_CHANGED_ON_START, false /* forceUpdate */);
+                continueAnimation = mTarget.onAnimationStart(
+                        mSchedulePipModeChangedState == SCHEDULE_PIP_MODE_CHANGED_ON_START,
+                        false /* forceUpdate */, mAnimationType);
 
                 // When starting an animation from fullscreen, pause here and wait for the
                 // windows-drawn signal before we start the rest of the transition down into PiP.
@@ -238,7 +251,8 @@
                 // However, we still need to report to them that they are leaving PiP, so this will
                 // force an update via a mode changed callback.
                 continueAnimation = mTarget.onAnimationStart(
-                        true /* schedulePipModeChangedCallback */, true /* forceUpdate */);
+                        true /* schedulePipModeChangedCallback */, true /* forceUpdate */,
+                        mAnimationType);
             } else {
                 // The animation is already running, but we should check that the TaskStack is still
                 // valid before continuing with the animation
@@ -285,6 +299,13 @@
         @Override
         public void onAnimationUpdate(ValueAnimator animation) {
             final float value = (Float) animation.getAnimatedValue();
+            if (mAnimationType == FADE_IN) {
+                if (!mTarget.setPinnedStackAlpha(value)) {
+                    cancelAndCallAnimationEnd();
+                }
+                return;
+            }
+
             final float remains = 1 - value;
             mTmpRect.left = (int) (mFrom.left * remains + mTo.left * value + 0.5f);
             mTmpRect.top = (int) (mFrom.top * remains + mTo.top * value + 0.5f);
@@ -408,16 +429,29 @@
 
     public void animateBounds(final BoundsAnimationTarget target, Rect from, Rect to,
             int animationDuration, @SchedulePipModeChangedState int schedulePipModeChangedState,
-            boolean moveFromFullscreen, boolean moveToFullscreen) {
+            boolean moveFromFullscreen, boolean moveToFullscreen,
+            @AnimationType int animationType) {
         animateBoundsImpl(target, from, to, animationDuration, schedulePipModeChangedState,
-                moveFromFullscreen, moveToFullscreen);
+                moveFromFullscreen, moveToFullscreen, animationType);
     }
 
     @VisibleForTesting
     BoundsAnimator animateBoundsImpl(final BoundsAnimationTarget target, Rect from, Rect to,
             int animationDuration, @SchedulePipModeChangedState int schedulePipModeChangedState,
-            boolean moveFromFullscreen, boolean moveToFullscreen) {
+            boolean moveFromFullscreen, boolean moveToFullscreen,
+            @AnimationType int animationType) {
         final BoundsAnimator existing = mRunningAnimations.get(target);
+        // animateBoundsImpl gets called twice for each animation. The second time we get the final
+        // to rect that respects the shelf, which is when we want to resize. Our signal for fade in
+        // comes in from how to enter into pip, but we also need to use the to and from rect to
+        // decide which animation we want to run finally.
+        boolean shouldResize = false;
+        if (isRunningFadeInAnimation(target)) {
+            shouldResize = true;
+            if (from.contains(to)) {
+                animationType = FADE_IN;
+            }
+        }
         final boolean replacing = existing != null;
         @SchedulePipModeChangedState int prevSchedulePipModeChangedState =
                 NO_PIP_MODE_CHANGED_CALLBACKS;
@@ -477,18 +511,34 @@
             // Since we are replacing, we skip both animation start and end callbacks
             existing.cancel();
         }
-        final BoundsAnimator animator = new BoundsAnimator(target, from, to,
+        if (shouldResize) {
+            target.setPinnedStackSize(to, null);
+        }
+        final BoundsAnimator animator = new BoundsAnimator(target, animationType, from, to,
                 schedulePipModeChangedState, prevSchedulePipModeChangedState,
                 moveFromFullscreen, moveToFullscreen, frozenTask);
         mRunningAnimations.put(target, animator);
         animator.setFloatValues(0f, 1f);
-        animator.setDuration((animationDuration != -1 ? animationDuration
-                : DEFAULT_TRANSITION_DURATION) * DEBUG_ANIMATION_SLOW_DOWN_FACTOR);
+        animator.setDuration(animationType == FADE_IN ? FADE_IN_DURATION
+                : (animationDuration != -1 ? animationDuration : DEFAULT_TRANSITION_DURATION)
+                        * DEBUG_ANIMATION_SLOW_DOWN_FACTOR);
         animator.setInterpolator(mFastOutSlowInInterpolator);
         animator.start();
         return animator;
     }
 
+    public void setAnimationType(@AnimationType int animationType) {
+        mAnimationType = animationType;
+    }
+
+    /** return the current animation type. */
+    public @AnimationType int getAnimationType() {
+        @AnimationType int animationType = mAnimationType;
+        // Default to BOUNDS.
+        mAnimationType = BOUNDS;
+        return animationType;
+    }
+
     public Handler getHandler() {
         return mHandler;
     }
@@ -498,6 +548,11 @@
         mHandler.post(this::resume);
     }
 
+    private boolean isRunningFadeInAnimation(final BoundsAnimationTarget target) {
+        final BoundsAnimator existing = mRunningAnimations.get(target);
+        return existing != null && existing.mAnimationType == FADE_IN && existing.isStarted();
+    }
+
     private void resume() {
         for (int i = 0; i < mRunningAnimations.size(); i++) {
             final BoundsAnimator b = mRunningAnimations.valueAt(i);
diff --git a/services/core/java/com/android/server/wm/BoundsAnimationTarget.java b/services/core/java/com/android/server/wm/BoundsAnimationTarget.java
index 5cb80de..9f54e49e0 100644
--- a/services/core/java/com/android/server/wm/BoundsAnimationTarget.java
+++ b/services/core/java/com/android/server/wm/BoundsAnimationTarget.java
@@ -32,7 +32,8 @@
      * callbacks
      * @return whether to continue the animation
      */
-    boolean onAnimationStart(boolean schedulePipModeChangedCallback, boolean forceUpdate);
+    boolean onAnimationStart(boolean schedulePipModeChangedCallback, boolean forceUpdate,
+            @BoundsAnimationController.AnimationType int animationType);
 
     /**
      * @return Whether the animation should be paused waiting for the windows to draw before
@@ -53,6 +54,9 @@
      */
     boolean setPinnedStackSize(Rect stackBounds, Rect taskBounds);
 
+    /** Sets the alpha of the animation target */
+    boolean setPinnedStackAlpha(float alpha);
+
     /**
      * Callback for the target to inform it that the animation has ended, so it can do some
      * necessary cleanup.
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index 144efb4..07d3fb9 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -26,6 +26,8 @@
 import static android.view.WindowManager.TRANSIT_NONE;
 
 import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
+import static com.android.server.wm.BoundsAnimationController.BOUNDS;
+import static com.android.server.wm.BoundsAnimationController.FADE_IN;
 import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_PLACE;
 import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_ORIGINAL_POSITION;
 import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_TOP;
@@ -201,7 +203,8 @@
         }
     }
 
-    private void finishAnimation(@RecentsAnimationController.ReorderMode int reorderMode) {
+    private void finishAnimation(@RecentsAnimationController.ReorderMode int reorderMode,
+            boolean sendUserLeaveHint) {
         synchronized (mService.mGlobalLock) {
             if (DEBUG) Slog.d(TAG, "onAnimationFinished(): controller="
                     + mWindowManager.getRecentsAnimationController()
@@ -246,7 +249,18 @@
                     if (reorderMode == REORDER_MOVE_TO_TOP) {
                         // Bring the target stack to the front
                         mStackSupervisor.mNoAnimActivities.add(targetActivity);
-                        targetStack.moveToFront("RecentsAnimation.onAnimationFinished()");
+
+                        if (sendUserLeaveHint) {
+                            // Setting this allows the previous app to PiP.
+                            mStackSupervisor.mUserLeaving = true;
+                            targetStack.moveTaskToFrontLocked(targetActivity.getTaskRecord(),
+                                    true /* noAnimation */, null /* activityOptions */,
+                                    targetActivity.appTimeTracker,
+                                    "RecentsAnimation.onAnimationFinished()");
+                        } else {
+                            targetStack.moveToFront("RecentsAnimation.onAnimationFinished()");
+                        }
+
                         if (DEBUG) {
                             final ActivityStack topStack = getTopNonAlwaysOnTopStack();
                             if (topStack != targetStack) {
@@ -300,11 +314,11 @@
 
     @Override
     public void onAnimationFinished(@RecentsAnimationController.ReorderMode int reorderMode,
-            boolean runSychronously) {
+            boolean runSychronously, boolean sendUserLeaveHint) {
         if (runSychronously) {
-            finishAnimation(reorderMode);
+            finishAnimation(reorderMode, sendUserLeaveHint);
         } else {
-            mService.mH.post(() -> finishAnimation(reorderMode));
+            mService.mH.post(() -> finishAnimation(reorderMode, sendUserLeaveHint));
         }
     }
 
@@ -317,6 +331,10 @@
         }
         final RecentsAnimationController controller =
                 mWindowManager.getRecentsAnimationController();
+        final DisplayContent dc =
+                mService.mRootActivityContainer.getDefaultDisplay().mDisplayContent;
+        dc.mBoundsAnimationController.setAnimationType(
+                controller.shouldCancelWithDeferredScreenshot() ? FADE_IN : BOUNDS);
 
         // Cancel running recents animation and screenshot previous task when the next
         // transition starts in below cases:
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 3813669..d2c510f 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -27,6 +27,7 @@
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
 import static com.android.server.wm.ActivityTaskManagerInternal.APP_TRANSITION_RECENTS_ANIM;
 import static com.android.server.wm.AnimationAdapterProto.REMOTE;
+import static com.android.server.wm.BoundsAnimationController.FADE_IN;
 import static com.android.server.wm.RemoteAnimationAdapterWrapperProto.TARGET;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RECENTS_ANIMATIONS;
 import static com.android.server.wm.WindowManagerInternal.AppTransitionListener;
@@ -142,7 +143,9 @@
     };
 
     public interface RecentsAnimationCallbacks {
-        void onAnimationFinished(@ReorderMode int reorderMode, boolean runSychronously);
+        /** Callback when recents animation is finished. */
+        void onAnimationFinished(@ReorderMode int reorderMode, boolean runSychronously,
+                boolean sendUserLeaveHint);
     }
 
     private final IRecentsAnimationController mController =
@@ -179,7 +182,7 @@
         }
 
         @Override
-        public void finish(boolean moveHomeToTop) {
+        public void finish(boolean moveHomeToTop, boolean sendUserLeaveHint) {
             if (DEBUG_RECENTS_ANIMATIONS) Slog.d(TAG, "finish(" + moveHomeToTop + "):"
                     + " mCanceled=" + mCanceled);
             final long token = Binder.clearCallingIdentity();
@@ -195,7 +198,9 @@
                 mCallbacks.onAnimationFinished(moveHomeToTop
                         ? REORDER_MOVE_TO_TOP
                         : REORDER_MOVE_TO_ORIGINAL_POSITION,
-                        true /* runSynchronously */);
+                        true /* runSynchronously */, sendUserLeaveHint);
+                final DisplayContent dc = mService.mRoot.getDisplayContent(mDisplayId);
+                dc.mBoundsAnimationController.setAnimationType(FADE_IN);
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
@@ -497,7 +502,8 @@
                 Slog.e(TAG, "Failed to cancel recents animation", e);
             }
             // Clean up and return to the previous app
-            mCallbacks.onAnimationFinished(reorderMode, runSynchronously);
+            mCallbacks.onAnimationFinished(reorderMode, runSynchronously,
+                    false /* sendUserLeaveHint */);
         }
     }
 
@@ -542,7 +548,8 @@
                         if (DEBUG_RECENTS_ANIMATIONS) {
                             Slog.d(TAG, "mRecentScreenshotAnimator finish");
                         }
-                        mCallbacks.onAnimationFinished(reorderMode, runSynchronously);
+                        mCallbacks.onAnimationFinished(reorderMode, runSynchronously,
+                                false /* sendUserLeaveHint */);
                     }, mService);
             mRecentScreenshotAnimator.transferAnimation(task.mSurfaceAnimator);
         }
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 09baf8c..bdb4d04 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -34,6 +34,7 @@
 import static android.view.WindowManager.DOCKED_RIGHT;
 import static android.view.WindowManager.DOCKED_TOP;
 
+import static com.android.server.wm.BoundsAnimationController.FADE_IN;
 import static com.android.server.wm.BoundsAnimationController.NO_PIP_MODE_CHANGED_CALLBACKS;
 import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_END;
 import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_START;
@@ -148,6 +149,7 @@
     private boolean mCancelCurrentBoundsAnimation = false;
     private Rect mBoundsAnimationTarget = new Rect();
     private Rect mBoundsAnimationSourceHintBounds = new Rect();
+    private @BoundsAnimationController.AnimationType int mAnimationType;
 
     Rect mPreAnimationBounds = new Rect();
 
@@ -1572,7 +1574,8 @@
     }
 
     @Override  // AnimatesBounds
-    public boolean onAnimationStart(boolean schedulePipModeChangedCallback, boolean forceUpdate) {
+    public boolean onAnimationStart(boolean schedulePipModeChangedCallback, boolean forceUpdate,
+            @BoundsAnimationController.AnimationType int animationType) {
         // Hold the lock since this is called from the BoundsAnimator running on the UiThread
         synchronized (mWmService.mGlobalLock) {
             if (!isAttached()) {
@@ -1583,6 +1586,7 @@
             mBoundsAnimatingRequested = false;
             mBoundsAnimating = true;
             mCancelCurrentBoundsAnimation = false;
+            mAnimationType = animationType;
 
             // If we are changing UI mode, as in the PiP to fullscreen
             // transition, then we need to wait for the window to draw.
@@ -1599,7 +1603,8 @@
                 // I don't believe you...
             }
 
-            if (schedulePipModeChangedCallback && mActivityStack != null) {
+            if ((schedulePipModeChangedCallback || animationType == FADE_IN)
+                    && mActivityStack != null) {
                 // We need to schedule the PiP mode change before the animation up. It is possible
                 // in this case for the animation down to not have been completed, so always
                 // force-schedule and update to the client to ensure that it is notified that it
@@ -1614,6 +1619,21 @@
     @Override  // AnimatesBounds
     public void onAnimationEnd(boolean schedulePipModeChangedCallback, Rect finalStackSize,
             boolean moveToFullscreen) {
+        if (mAnimationType == BoundsAnimationController.FADE_IN) {
+            setPinnedStackAlpha(1f);
+            try {
+                mWmService.mActivityTaskManager.notifyPinnedStackAnimationEnded();
+            } catch (RemoteException e) {
+                // I don't believe you...
+            }
+            return;
+        }
+
+        onBoundAnimationEnd(schedulePipModeChangedCallback, finalStackSize, moveToFullscreen);
+    }
+
+    private void onBoundAnimationEnd(boolean schedulePipModeChangedCallback, Rect finalStackSize,
+            boolean moveToFullscreen) {
         if (inPinnedWindowingMode()) {
             // Update to the final bounds if requested. This is done here instead of in the bounds
             // animator to allow us to coordinate this after we notify the PiP mode changed
@@ -1725,10 +1745,23 @@
         final @SchedulePipModeChangedState int finalSchedulePipModeChangedState =
                 schedulePipModeChangedState;
         final DisplayContent displayContent = getDisplayContent();
+        @BoundsAnimationController.AnimationType int intendedAnimationType =
+                displayContent.mBoundsAnimationController.getAnimationType();
+        if (intendedAnimationType == FADE_IN) {
+            if (fromFullscreen) {
+                setPinnedStackAlpha(0f);
+            }
+            if (toBounds.width() == fromBounds.width()
+                    && toBounds.height() == fromBounds.height()) {
+                intendedAnimationType = BoundsAnimationController.BOUNDS;
+            }
+        }
+
+        final @BoundsAnimationController.AnimationType int animationType = intendedAnimationType;
         displayContent.mBoundsAnimationController.getHandler().post(() -> {
             displayContent.mBoundsAnimationController.animateBounds(this, fromBounds,
                     finalToBounds, animationDuration, finalSchedulePipModeChangedState,
-                    fromFullscreen, toFullscreen);
+                    fromFullscreen, toFullscreen, animationType);
         });
     }
 
@@ -1905,6 +1938,20 @@
         }
     }
 
+    @Override
+    public boolean setPinnedStackAlpha(float alpha) {
+        // Hold the lock since this is called from the BoundsAnimator running on the UiThread
+        synchronized (mWmService.mGlobalLock) {
+            if (mCancelCurrentBoundsAnimation) {
+                return false;
+            }
+            getPendingTransaction().setAlpha(getSurfaceControl(), alpha);
+            scheduleAnimation();
+        }
+
+        return true;
+    }
+
     public DisplayInfo getDisplayInfo() {
         return mDisplayContent.getDisplayInfo();
     }
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java
new file mode 100644
index 0000000..3f9a57e
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java
@@ -0,0 +1,504 @@
+/*
+ * Copyright (C) 2019 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.server.om;
+
+import static android.content.om.OverlayInfo.STATE_DISABLED;
+import static android.content.om.OverlayInfo.STATE_ENABLED;
+import static android.content.om.OverlayInfo.STATE_MISSING_TARGET;
+import static android.content.om.OverlayInfo.STATE_TARGET_IS_BEING_REPLACED;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import android.annotation.NonNull;
+import android.content.om.OverlayInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.util.ArraySet;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+@RunWith(AndroidJUnit4.class)
+public class OverlayManagerServiceImplTests {
+    private OverlayManagerServiceImpl mImpl;
+    private DummyDeviceState mState;
+    private DummyListener mListener;
+
+    private static final String OVERLAY = "com.dummy.overlay";
+    private static final String TARGET = "com.dummy.target";
+    private static final int USER = 0;
+
+    private static final String OVERLAY2 = OVERLAY + "2";
+    private static final String TARGET2 = TARGET + "2";
+    private static final int USER2 = USER + 1;
+
+    private static final String OVERLAY3 = OVERLAY + "3";
+    private static final int USER3 = USER2 + 1;
+
+
+    @Before
+    public void setUp() throws Exception {
+        mState = new DummyDeviceState();
+        mListener = new DummyListener();
+        DummyPackageManagerHelper pmh = new DummyPackageManagerHelper(mState);
+        mImpl = new OverlayManagerServiceImpl(pmh,
+                new DummyIdmapManager(mState, pmh),
+                new OverlayManagerSettings(),
+                new String[0],
+                mListener);
+    }
+
+    // tests: basics
+
+    @Test
+    public void testGetOverlayInfo() throws Exception {
+        installOverlayPackage(OVERLAY, TARGET, USER, false);
+        final OverlayInfo oi = mImpl.getOverlayInfo(OVERLAY, USER);
+        assertNotNull(oi);
+        assertEquals(oi.packageName, OVERLAY);
+        assertEquals(oi.targetPackageName, TARGET);
+        assertEquals(oi.userId, USER);
+    }
+
+    @Test
+    public void testGetOverlayInfosForTarget() throws Exception {
+        installOverlayPackage(OVERLAY, TARGET, USER, false);
+        installOverlayPackage(OVERLAY2, TARGET, USER, false);
+
+        installOverlayPackage(OVERLAY3, TARGET, USER2, false);
+
+        final List<OverlayInfo> ois = mImpl.getOverlayInfosForTarget(TARGET, USER);
+        assertEquals(ois.size(), 2);
+        assertTrue(ois.contains(mImpl.getOverlayInfo(OVERLAY, USER)));
+        assertTrue(ois.contains(mImpl.getOverlayInfo(OVERLAY2, USER)));
+
+        final List<OverlayInfo> ois2 = mImpl.getOverlayInfosForTarget(TARGET, USER2);
+        assertEquals(ois2.size(), 1);
+        assertTrue(ois2.contains(mImpl.getOverlayInfo(OVERLAY3, USER2)));
+
+        final List<OverlayInfo> ois3 = mImpl.getOverlayInfosForTarget(TARGET, USER3);
+        assertNotNull(ois3);
+        assertEquals(ois3.size(), 0);
+
+        final List<OverlayInfo> ois4 = mImpl.getOverlayInfosForTarget("no.such.overlay", USER);
+        assertNotNull(ois4);
+        assertEquals(ois4.size(), 0);
+    }
+
+    @Test
+    public void testGetOverlayInfosForUser() throws Exception {
+        installOverlayPackage(OVERLAY, TARGET, USER, false);
+        installOverlayPackage(OVERLAY2, TARGET, USER, false);
+        installOverlayPackage(OVERLAY3, TARGET2, USER, false);
+
+        final Map<String, List<OverlayInfo>> everything = mImpl.getOverlaysForUser(USER);
+        assertEquals(everything.size(), 2);
+
+        final List<OverlayInfo> ois = everything.get(TARGET);
+        assertNotNull(ois);
+        assertEquals(ois.size(), 2);
+        assertTrue(ois.contains(mImpl.getOverlayInfo(OVERLAY, USER)));
+        assertTrue(ois.contains(mImpl.getOverlayInfo(OVERLAY2, USER)));
+
+        final List<OverlayInfo> ois2 = everything.get(TARGET2);
+        assertNotNull(ois2);
+        assertEquals(ois2.size(), 1);
+        assertTrue(ois2.contains(mImpl.getOverlayInfo(OVERLAY3, USER)));
+
+        final Map<String, List<OverlayInfo>> everything2 = mImpl.getOverlaysForUser(USER2);
+        assertNotNull(everything2);
+        assertEquals(everything2.size(), 0);
+    }
+
+    @Test
+    public void testPriority() throws Exception {
+        installOverlayPackage(OVERLAY, TARGET, USER, false);
+        installOverlayPackage(OVERLAY2, TARGET, USER, false);
+        installOverlayPackage(OVERLAY3, TARGET, USER, false);
+
+        final OverlayInfo o1 = mImpl.getOverlayInfo(OVERLAY, USER);
+        final OverlayInfo o2 = mImpl.getOverlayInfo(OVERLAY2, USER);
+        final OverlayInfo o3 = mImpl.getOverlayInfo(OVERLAY3, USER);
+
+        assertOverlayInfoList(TARGET, USER, o1, o2, o3);
+
+        assertTrue(mImpl.setLowestPriority(OVERLAY3, USER));
+        assertOverlayInfoList(TARGET, USER, o3, o1, o2);
+
+        assertTrue(mImpl.setHighestPriority(OVERLAY3, USER));
+        assertOverlayInfoList(TARGET, USER, o1, o2, o3);
+
+        assertTrue(mImpl.setPriority(OVERLAY, OVERLAY2, USER));
+        assertOverlayInfoList(TARGET, USER, o2, o1, o3);
+    }
+
+    @Test
+    public void testOverlayInfoStateTransitions() throws Exception {
+        assertNull(mImpl.getOverlayInfo(OVERLAY, USER));
+
+        installOverlayPackage(OVERLAY, TARGET, USER, true);
+        assertState(STATE_MISSING_TARGET, OVERLAY, USER);
+
+        installTargetPackage(TARGET, USER);
+        assertState(STATE_DISABLED, OVERLAY, USER);
+
+        mImpl.setEnabled(OVERLAY, true, USER);
+        assertState(STATE_ENABLED, OVERLAY, USER);
+
+        beginUpgradeTargetPackage(TARGET, USER);
+        assertState(STATE_TARGET_IS_BEING_REPLACED, OVERLAY, USER);
+
+        endUpgradeTargetPackage(TARGET, USER);
+        assertState(STATE_ENABLED, OVERLAY, USER);
+
+        uninstallTargetPackage(TARGET, USER);
+        assertState(STATE_MISSING_TARGET, OVERLAY, USER);
+
+        installTargetPackage(TARGET, USER);
+        assertState(STATE_ENABLED, OVERLAY, USER);
+    }
+
+    @Test
+    public void testUpdateOverlaysForUser() throws Exception {
+        installTargetPackage(TARGET, USER);
+        installTargetPackage("some.other.target", USER);
+        installOverlayPackage(OVERLAY, TARGET, USER, true);
+
+        // do nothing, expect no change
+        List<String> a = mImpl.updateOverlaysForUser(USER);
+        assertEquals(1, a.size());
+        assertTrue(a.contains(TARGET));
+
+        // upgrade overlay, keep target
+        upgradeOverlayPackage(OVERLAY, TARGET, USER, true);
+        List<String> b = mImpl.updateOverlaysForUser(USER);
+        assertEquals(1, b.size());
+        assertTrue(b.contains(TARGET));
+
+        // do nothing, expect no change
+        List<String> c = mImpl.updateOverlaysForUser(USER);
+        assertEquals(1, c.size());
+        assertTrue(c.contains(TARGET));
+
+        // upgrade overlay, switch to new target
+        upgradeOverlayPackage(OVERLAY, "some.other.target", USER, true);
+        List<String> d = mImpl.updateOverlaysForUser(USER);
+        assertEquals(2, d.size());
+        assertTrue(d.containsAll(Arrays.asList(TARGET, "some.other.target")));
+
+        // do nothing, expect no change
+        List<String> e = mImpl.updateOverlaysForUser(USER);
+        assertEquals(1, e.size());
+        assertTrue(e.contains("some.other.target"));
+    }
+
+    @Test
+    public void testOnOverlayPackageUpgraded() throws Exception {
+        installTargetPackage(TARGET, USER);
+        installOverlayPackage(OVERLAY, TARGET, USER, true);
+        mImpl.onOverlayPackageReplacing(OVERLAY, USER);
+        mListener.count = 0;
+        mImpl.onOverlayPackageReplaced(OVERLAY, USER);
+        assertEquals(1, mListener.count);
+
+        // upgrade to a version where the overlay has changed its target
+        upgradeOverlayPackage(OVERLAY, "some.other.target", USER, true);
+        mImpl.onOverlayPackageReplacing(OVERLAY, USER);
+        mListener.count = 0;
+        mImpl.onOverlayPackageReplaced(OVERLAY, USER);
+        // expect once for the old target package, once for the new target package
+        assertEquals(2, mListener.count);
+
+        upgradeOverlayPackage(OVERLAY, "some.other.target", USER, true);
+        mImpl.onOverlayPackageReplacing(OVERLAY, USER);
+        mListener.count = 0;
+        mImpl.onOverlayPackageReplaced(OVERLAY, USER);
+        assertEquals(1, mListener.count);
+    }
+
+    // tests: listener interface
+
+    @Test
+    public void testListener() throws Exception {
+        installOverlayPackage(OVERLAY, TARGET, USER, true);
+        assertEquals(1, mListener.count);
+        mListener.count = 0;
+
+        installTargetPackage(TARGET, USER);
+        assertEquals(1, mListener.count);
+        mListener.count = 0;
+
+        mImpl.setEnabled(OVERLAY, true, USER);
+        assertEquals(1, mListener.count);
+        mListener.count = 0;
+
+        mImpl.setEnabled(OVERLAY, true, USER);
+        assertEquals(0, mListener.count);
+    }
+
+    // helper methods
+
+    private void assertState(int expected, final String overlayPackageName, int userId) {
+        int actual = mImpl.getOverlayInfo(OVERLAY, USER).state;
+        String msg = String.format("expected %s but was %s:",
+                OverlayInfo.stateToString(expected), OverlayInfo.stateToString(actual));
+        assertEquals(msg, expected, actual);
+    }
+
+    private void assertOverlayInfoList(final String targetPackageName, int userId,
+            OverlayInfo... overlayInfos) {
+        final List<OverlayInfo> expected =
+                mImpl.getOverlayInfosForTarget(targetPackageName, userId);
+        final List<OverlayInfo> actual = Arrays.asList(overlayInfos);
+        assertEquals(expected, actual);
+    }
+
+    private void installTargetPackage(String packageName, int userId) {
+        if (mState.select(packageName, userId) != null) {
+            throw new IllegalStateException("package already installed");
+        }
+        mState.add(packageName, null, userId, false);
+        mImpl.onTargetPackageAdded(packageName, userId);
+    }
+
+    private void beginUpgradeTargetPackage(String packageName, int userId) {
+        if (mState.select(packageName, userId) == null) {
+            throw new IllegalStateException("package not installed");
+        }
+        mState.add(packageName, null, userId, false);
+        mImpl.onTargetPackageReplacing(packageName, userId);
+    }
+
+    private void endUpgradeTargetPackage(String packageName, int userId) {
+        if (mState.select(packageName, userId) == null) {
+            throw new IllegalStateException("package not installed");
+        }
+        mState.add(packageName, null, userId, false);
+        mImpl.onTargetPackageReplaced(packageName, userId);
+    }
+
+    private void uninstallTargetPackage(String packageName, int userId) {
+        if (mState.select(packageName, userId) == null) {
+            throw new IllegalStateException("package not installed");
+        }
+        mState.remove(packageName, userId);
+        mImpl.onTargetPackageRemoved(packageName, userId);
+    }
+
+    private void installOverlayPackage(String packageName, String targetPackageName, int userId,
+            boolean canCreateIdmap) {
+        if (mState.select(packageName, userId) != null) {
+            throw new IllegalStateException("package already installed");
+        }
+        mState.add(packageName, targetPackageName, userId, canCreateIdmap);
+        mImpl.onOverlayPackageAdded(packageName, userId);
+    }
+
+    private void upgradeOverlayPackage(String packageName, String targetPackageName, int userId,
+            boolean canCreateIdmap) {
+        DummyDeviceState.Package pkg = mState.select(packageName, userId);
+        if (pkg == null) {
+            throw new IllegalStateException("package not installed, cannot upgrade");
+        }
+        pkg.targetPackageName = targetPackageName;
+        pkg.canCreateIdmap = canCreateIdmap;
+    }
+
+    private void uninstallOverlayPackage(String packageName, int userId) {
+        // implement this when adding support for downloadable overlays
+        throw new IllegalArgumentException("not implemented");
+    }
+
+    private static final class DummyDeviceState {
+        private List<Package> mPackages = new ArrayList<>();
+
+        public void add(String packageName, String targetPackageName, int userId,
+                boolean canCreateIdmap) {
+            remove(packageName, userId);
+            Package pkg = new Package();
+            pkg.packageName = packageName;
+            pkg.targetPackageName = targetPackageName;
+            pkg.userId = userId;
+            pkg.canCreateIdmap = canCreateIdmap;
+            mPackages.add(pkg);
+        }
+
+        public void remove(String packageName, int userId) {
+            final Iterator<Package> iter = mPackages.iterator();
+            while (iter.hasNext()) {
+                final Package pkg = iter.next();
+                if (pkg.packageName.equals(packageName) && pkg.userId == userId) {
+                    iter.remove();
+                    return;
+                }
+            }
+        }
+
+        public List<Package> select(int userId) {
+            List<Package> out = new ArrayList<>();
+            final int packageCount = mPackages.size();
+            for (int i = 0; i < packageCount; i++) {
+                final Package pkg = mPackages.get(i);
+                if (pkg.userId == userId) {
+                    out.add(pkg);
+                }
+            }
+            return out;
+        }
+
+        public Package select(String packageName, int userId) {
+            final int packageCount = mPackages.size();
+            for (int i = 0; i < packageCount; i++) {
+                final Package pkg = mPackages.get(i);
+                if (pkg.packageName.equals(packageName) && pkg.userId == userId) {
+                    return pkg;
+                }
+            }
+            return null;
+        }
+
+        private static final class Package {
+            public String packageName;
+            public int userId;
+            public String targetPackageName;
+            public boolean canCreateIdmap;
+        }
+    }
+
+    private static final class DummyPackageManagerHelper implements
+            OverlayManagerServiceImpl.PackageManagerHelper {
+        private final DummyDeviceState mState;
+
+        DummyPackageManagerHelper(DummyDeviceState state) {
+            mState = state;
+        }
+
+        @Override
+        public PackageInfo getPackageInfo(@NonNull String packageName, int userId) {
+            final DummyDeviceState.Package pkg = mState.select(packageName, userId);
+            if (pkg == null) {
+                return null;
+            }
+            ApplicationInfo ai = new ApplicationInfo();
+            ai.sourceDir = String.format("%s/%s/base.apk",
+                    pkg.targetPackageName == null ? "/system/app/" : "/vendor/overlay/",
+                    pkg.packageName);
+            PackageInfo pi = new PackageInfo();
+            pi.applicationInfo = ai;
+            pi.packageName = pkg.packageName;
+            pi.overlayTarget = pkg.targetPackageName;
+            pi.overlayCategory = "dummy-category-" + pkg.targetPackageName;
+            return pi;
+        }
+
+        @Override
+        public boolean signaturesMatching(@NonNull String packageName1,
+                @NonNull String packageName2, int userId) {
+            return false;
+        }
+
+        @Override
+        public List<PackageInfo> getOverlayPackages(int userId) {
+            List<PackageInfo> out = new ArrayList<>();
+            final List<DummyDeviceState.Package> packages = mState.select(userId);
+            final int packageCount = packages.size();
+            for (int i = 0; i < packageCount; i++) {
+                final DummyDeviceState.Package pkg = packages.get(i);
+                if (pkg.targetPackageName != null) {
+                    out.add(getPackageInfo(pkg.packageName, pkg.userId));
+                }
+            }
+            return out;
+        }
+    }
+
+    private static class DummyIdmapManager extends IdmapManager {
+        private final DummyDeviceState mState;
+        private Set<String> mIdmapFiles = new ArraySet<>();
+
+        DummyIdmapManager(DummyDeviceState state, DummyPackageManagerHelper packageManagerHelper) {
+            super(null, packageManagerHelper);
+            mState = state;
+        }
+
+        @Override
+        boolean createIdmap(@NonNull final PackageInfo targetPackage,
+                @NonNull final PackageInfo overlayPackage, int userId) {
+            final DummyDeviceState.Package t = mState.select(targetPackage.packageName, userId);
+            if (t == null) {
+                return false;
+            }
+            final DummyDeviceState.Package o = mState.select(overlayPackage.packageName, userId);
+            if (o == null) {
+                return false;
+            }
+            if (!o.canCreateIdmap) {
+                return false;
+            }
+            final String key = createKey(overlayPackage.packageName, userId);
+            mIdmapFiles.add(key);
+            return true;
+        }
+
+        @Override
+        boolean removeIdmap(@NonNull final OverlayInfo oi, final int userId) {
+            final String key = createKey(oi.packageName, oi.userId);
+            if (!mIdmapFiles.contains(key)) {
+                return false;
+            }
+            mIdmapFiles.remove(key);
+            return true;
+        }
+
+        @Override
+        boolean idmapExists(@NonNull final OverlayInfo oi) {
+            final String key = createKey(oi.packageName, oi.userId);
+            return mIdmapFiles.contains(key);
+        }
+
+        @Override
+        boolean idmapExists(@NonNull final PackageInfo overlayPackage, final int userId) {
+            final String key = createKey(overlayPackage.packageName, userId);
+            return mIdmapFiles.contains(key);
+        }
+
+        private String createKey(@NonNull final String packageName, final int userId) {
+            return String.format("%s:%d", packageName, userId);
+        }
+    }
+
+    private static class DummyListener implements OverlayManagerServiceImpl.OverlayChangeListener {
+        public int count;
+
+        public void onOverlaysChanged(@NonNull String targetPackage, int userId) {
+            count++;
+        }
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerSettingsTests.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerSettingsTests.java
new file mode 100644
index 0000000..8ff8b6e
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerSettingsTests.java
@@ -0,0 +1,505 @@
+/*
+ * Copyright (C) 2019 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.server.om;
+
+import static android.content.om.OverlayInfo.STATE_DISABLED;
+import static android.content.om.OverlayInfo.STATE_ENABLED;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import android.content.om.OverlayInfo;
+import android.text.TextUtils;
+import android.util.Xml;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.xmlpull.v1.XmlPullParser;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.IntStream;
+import java.util.stream.Stream;
+
+@RunWith(AndroidJUnit4.class)
+public class OverlayManagerSettingsTests {
+    private OverlayManagerSettings mSettings;
+
+    private static final OverlayInfo OVERLAY_A0 = new OverlayInfo(
+            "com.dummy.overlay_a",
+            "com.dummy.target",
+            null,
+            "some-category",
+            "/data/app/com.dummy.overlay_a-1/base.apk",
+            STATE_DISABLED,
+            0,
+            0,
+            false);
+
+    private static final OverlayInfo OVERLAY_B0 = new OverlayInfo(
+            "com.dummy.overlay_b",
+            "com.dummy.target",
+            null,
+            "some-category",
+            "/data/app/com.dummy.overlay_b-1/base.apk",
+            STATE_DISABLED,
+            0,
+            0,
+            false);
+
+    private static final OverlayInfo OVERLAY_C0 = new OverlayInfo(
+            "com.dummy.overlay_c",
+            "com.dummy.target",
+            null,
+            "some-category",
+            "/data/app/com.dummy.overlay_c-1/base.apk",
+            STATE_DISABLED,
+            0,
+            0,
+            false);
+
+    private static final OverlayInfo OVERLAY_A1 = new OverlayInfo(
+            "com.dummy.overlay_a",
+            "com.dummy.target",
+            null,
+            "some-category",
+            "/data/app/com.dummy.overlay_a-1/base.apk",
+            STATE_DISABLED,
+            1,
+            0,
+            false);
+
+    private static final OverlayInfo OVERLAY_B1 = new OverlayInfo(
+            "com.dummy.overlay_b",
+            "com.dummy.target",
+            null,
+            "some-category",
+            "/data/app/com.dummy.overlay_b-1/base.apk",
+            STATE_DISABLED,
+            1,
+            0,
+            false);
+
+    @Before
+    public void setUp() throws Exception {
+        mSettings = new OverlayManagerSettings();
+    }
+
+    // tests: generic functionality
+
+    @Test
+    public void testSettingsInitiallyEmpty() throws Exception {
+        final int userId = 0;
+        Map<String, List<OverlayInfo>> map = mSettings.getOverlaysForUser(userId);
+        assertEquals(0, map.size());
+    }
+
+    @Test
+    public void testBasicSetAndGet() throws Exception {
+        assertDoesNotContain(mSettings, OVERLAY_A0.packageName, OVERLAY_A0.userId);
+
+        insert(OVERLAY_A0);
+        assertContains(mSettings, OVERLAY_A0);
+        OverlayInfo oi = mSettings.getOverlayInfo(OVERLAY_A0.packageName, OVERLAY_A0.userId);
+        assertEquals(OVERLAY_A0, oi);
+
+        assertTrue(mSettings.remove(OVERLAY_A0.packageName, OVERLAY_A0.userId));
+        assertDoesNotContain(mSettings, OVERLAY_A0.packageName, OVERLAY_A0.userId);
+    }
+
+    @Test
+    public void testGetUsers() throws Exception {
+        int[] users = mSettings.getUsers();
+        assertEquals(0, users.length);
+
+        insert(OVERLAY_A0);
+        users = mSettings.getUsers();
+        assertEquals(1, users.length);
+        assertContains(users, OVERLAY_A0.userId);
+
+        insert(OVERLAY_A1);
+        insert(OVERLAY_B1);
+        users = mSettings.getUsers();
+        assertEquals(2, users.length);
+        assertContains(users, OVERLAY_A0.userId);
+        assertContains(users, OVERLAY_A1.userId);
+    }
+
+    @Test
+    public void testGetOverlaysForUser() throws Exception {
+        insert(OVERLAY_A0);
+        insert(OVERLAY_B0);
+        insert(OVERLAY_A1);
+        insert(OVERLAY_B1);
+
+        Map<String, List<OverlayInfo>> map = mSettings.getOverlaysForUser(OVERLAY_A0.userId);
+        assertEquals(1, map.keySet().size());
+        assertTrue(map.keySet().contains(OVERLAY_A0.targetPackageName));
+
+        List<OverlayInfo> list = map.get(OVERLAY_A0.targetPackageName);
+        assertEquals(2, list.size());
+        assertTrue(list.contains(OVERLAY_A0));
+        assertTrue(list.contains(OVERLAY_B0));
+
+        // getOverlaysForUser should never return null
+        map = mSettings.getOverlaysForUser(-1);
+        assertNotNull(map);
+        assertEquals(0, map.size());
+    }
+
+    @Test
+    public void testRemoveUser() throws Exception {
+        insert(OVERLAY_A0);
+        insert(OVERLAY_B0);
+        insert(OVERLAY_A1);
+
+        assertContains(mSettings, OVERLAY_A0);
+        assertContains(mSettings, OVERLAY_B0);
+        assertContains(mSettings, OVERLAY_A1);
+
+        mSettings.removeUser(OVERLAY_A0.userId);
+
+        assertDoesNotContain(mSettings, OVERLAY_A0);
+        assertDoesNotContain(mSettings, OVERLAY_B0);
+        assertContains(mSettings, OVERLAY_A1);
+    }
+
+    @Test
+    public void testOrderOfNewlyAddedItems() throws Exception {
+        // new items are appended to the list
+        insert(OVERLAY_A0);
+        insert(OVERLAY_B0);
+        insert(OVERLAY_C0);
+
+        List<OverlayInfo> list =
+                mSettings.getOverlaysForTarget(OVERLAY_A0.targetPackageName, OVERLAY_A0.userId);
+        assertListsAreEqual(list, OVERLAY_A0, OVERLAY_B0, OVERLAY_C0);
+
+        // overlays keep their positions when updated
+        mSettings.setState(OVERLAY_B0.packageName, OVERLAY_B0.userId, STATE_ENABLED);
+        OverlayInfo oi = mSettings.getOverlayInfo(OVERLAY_B0.packageName, OVERLAY_B0.userId);
+
+        list = mSettings.getOverlaysForTarget(OVERLAY_A0.targetPackageName, OVERLAY_A0.userId);
+        assertListsAreEqual(list, OVERLAY_A0, oi, OVERLAY_C0);
+    }
+
+    @Test
+    public void testSetPriority() throws Exception {
+        insert(OVERLAY_A0);
+        insert(OVERLAY_B0);
+        insert(OVERLAY_C0);
+
+        List<OverlayInfo> list =
+                mSettings.getOverlaysForTarget(OVERLAY_A0.targetPackageName, OVERLAY_A0.userId);
+        assertListsAreEqual(list, OVERLAY_A0, OVERLAY_B0, OVERLAY_C0);
+
+        boolean changed = mSettings.setPriority(OVERLAY_B0.packageName, OVERLAY_C0.packageName,
+                OVERLAY_B0.userId);
+        assertTrue(changed);
+        list = mSettings.getOverlaysForTarget(OVERLAY_A0.targetPackageName, OVERLAY_A0.userId);
+        assertListsAreEqual(list, OVERLAY_A0, OVERLAY_C0, OVERLAY_B0);
+
+        changed =
+            mSettings.setPriority(OVERLAY_B0.packageName, "does.not.exist", OVERLAY_B0.userId);
+        assertFalse(changed);
+        list = mSettings.getOverlaysForTarget(OVERLAY_A0.targetPackageName, OVERLAY_A0.userId);
+        assertListsAreEqual(list, OVERLAY_A0, OVERLAY_C0, OVERLAY_B0);
+
+        OverlayInfo otherTarget = new OverlayInfo(
+                "com.dummy.overlay_other",
+                "com.dummy.some.other.target",
+                null,
+                "some-category",
+                "/data/app/com.dummy.overlay_other-1/base.apk",
+                STATE_DISABLED,
+                0,
+                0,
+                false);
+        insert(otherTarget);
+        changed = mSettings.setPriority(OVERLAY_A0.packageName, otherTarget.packageName,
+                OVERLAY_A0.userId);
+        assertFalse(changed);
+    }
+
+    @Test
+    public void testSetLowestPriority() throws Exception {
+        insert(OVERLAY_A0);
+        insert(OVERLAY_B0);
+        insert(OVERLAY_C0);
+
+        List<OverlayInfo> list =
+                mSettings.getOverlaysForTarget(OVERLAY_A0.targetPackageName, OVERLAY_A0.userId);
+        assertListsAreEqual(list, OVERLAY_A0, OVERLAY_B0, OVERLAY_C0);
+
+        boolean changed = mSettings.setLowestPriority(OVERLAY_B0.packageName, OVERLAY_B0.userId);
+        assertTrue(changed);
+
+        list = mSettings.getOverlaysForTarget(OVERLAY_A0.targetPackageName, OVERLAY_A0.userId);
+        assertListsAreEqual(list, OVERLAY_B0, OVERLAY_A0, OVERLAY_C0);
+    }
+
+    @Test
+    public void testSetHighestPriority() throws Exception {
+        insert(OVERLAY_A0);
+        insert(OVERLAY_B0);
+        insert(OVERLAY_C0);
+
+        List<OverlayInfo> list =
+                mSettings.getOverlaysForTarget(OVERLAY_A0.targetPackageName, OVERLAY_A0.userId);
+        assertListsAreEqual(list, OVERLAY_A0, OVERLAY_B0, OVERLAY_C0);
+
+        boolean changed = mSettings.setHighestPriority(OVERLAY_B0.packageName, OVERLAY_B0.userId);
+        assertTrue(changed);
+
+        list = mSettings.getOverlaysForTarget(OVERLAY_A0.targetPackageName, OVERLAY_A0.userId);
+        assertListsAreEqual(list, OVERLAY_A0, OVERLAY_C0, OVERLAY_B0);
+    }
+
+    // tests: persist and restore
+
+    @Test
+    public void testPersistEmpty() throws Exception {
+        ByteArrayOutputStream os = new ByteArrayOutputStream();
+        mSettings.persist(os);
+        String xml = new String(os.toByteArray(), "utf-8");
+
+        assertEquals(1, countXmlTags(xml, "overlays"));
+        assertEquals(0, countXmlTags(xml, "item"));
+    }
+
+    @Test
+    public void testPersistDifferentOverlaysSameUser() throws Exception {
+        insert(OVERLAY_A0);
+        insert(OVERLAY_B0);
+
+        ByteArrayOutputStream os = new ByteArrayOutputStream();
+        mSettings.persist(os);
+        final String xml = new String(os.toByteArray(), "utf-8");
+
+        assertEquals(1, countXmlTags(xml, "overlays"));
+        assertEquals(2, countXmlTags(xml, "item"));
+        assertEquals(1, countXmlAttributesWhere(xml, "item", "packageName",
+                    OVERLAY_A0.packageName));
+        assertEquals(1, countXmlAttributesWhere(xml, "item", "packageName",
+                    OVERLAY_B0.packageName));
+        assertEquals(2, countXmlAttributesWhere(xml, "item", "userId",
+                    Integer.toString(OVERLAY_A0.userId)));
+    }
+
+    @Test
+    public void testPersistSameOverlayDifferentUsers() throws Exception {
+        insert(OVERLAY_A0);
+        insert(OVERLAY_A1);
+
+        ByteArrayOutputStream os = new ByteArrayOutputStream();
+        mSettings.persist(os);
+        String xml = new String(os.toByteArray(), "utf-8");
+
+        assertEquals(1, countXmlTags(xml, "overlays"));
+        assertEquals(2, countXmlTags(xml, "item"));
+        assertEquals(2, countXmlAttributesWhere(xml, "item", "packageName",
+                    OVERLAY_A0.packageName));
+        assertEquals(1, countXmlAttributesWhere(xml, "item", "userId",
+                    Integer.toString(OVERLAY_A0.userId)));
+        assertEquals(1, countXmlAttributesWhere(xml, "item", "userId",
+                    Integer.toString(OVERLAY_A1.userId)));
+    }
+
+    @Test
+    public void testPersistEnabled() throws Exception {
+        insert(OVERLAY_A0);
+        mSettings.setEnabled(OVERLAY_A0.packageName, OVERLAY_A0.userId, true);
+
+        ByteArrayOutputStream os = new ByteArrayOutputStream();
+        mSettings.persist(os);
+        String xml = new String(os.toByteArray(), "utf-8");
+
+        assertEquals(1, countXmlAttributesWhere(xml, "item", "isEnabled", "true"));
+    }
+
+    @Test
+    public void testRestoreEmpty() throws Exception {
+        final int version = OverlayManagerSettings.Serializer.CURRENT_VERSION;
+        final String xml =
+                "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+                + "<overlays version=\"" + version + "\" />\n";
+        ByteArrayInputStream is = new ByteArrayInputStream(xml.getBytes("utf-8"));
+
+        mSettings.restore(is);
+        assertDoesNotContain(mSettings, "com.dummy.overlay", 0);
+    }
+
+    @Test
+    public void testRestoreSingleUserSingleOverlay() throws Exception {
+        final int version = OverlayManagerSettings.Serializer.CURRENT_VERSION;
+        final String xml =
+                "<?xml version='1.0' encoding='utf-8' standalone='yes'?>\n"
+                + "<overlays version='" + version + "'>\n"
+                + "<item packageName='com.dummy.overlay'\n"
+                + "      userId='1234'\n"
+                + "      targetPackageName='com.dummy.target'\n"
+                + "      baseCodePath='/data/app/com.dummy.overlay-1/base.apk'\n"
+                + "      state='" + STATE_DISABLED + "'\n"
+                + "      isEnabled='false'\n"
+                + "      category='dummy-category'\n"
+                + "      isStatic='false'\n"
+                + "      priority='0' />\n"
+                + "</overlays>\n";
+        ByteArrayInputStream is = new ByteArrayInputStream(xml.getBytes("utf-8"));
+
+        mSettings.restore(is);
+        OverlayInfo oi = mSettings.getOverlayInfo("com.dummy.overlay", 1234);
+        assertNotNull(oi);
+        assertEquals("com.dummy.overlay", oi.packageName);
+        assertEquals("com.dummy.target", oi.targetPackageName);
+        assertEquals("/data/app/com.dummy.overlay-1/base.apk", oi.baseCodePath);
+        assertEquals(1234, oi.userId);
+        assertEquals(STATE_DISABLED, oi.state);
+        assertFalse(mSettings.getEnabled("com.dummy.overlay", 1234));
+    }
+
+    @Test
+    public void testPersistAndRestore() throws Exception {
+        insert(OVERLAY_A0);
+        insert(OVERLAY_B1);
+
+        ByteArrayOutputStream os = new ByteArrayOutputStream();
+        mSettings.persist(os);
+        String xml = new String(os.toByteArray(), "utf-8");
+        ByteArrayInputStream is = new ByteArrayInputStream(xml.getBytes("utf-8"));
+        OverlayManagerSettings newSettings = new OverlayManagerSettings();
+        newSettings.restore(is);
+
+        OverlayInfo a = newSettings.getOverlayInfo(OVERLAY_A0.packageName, OVERLAY_A0.userId);
+        assertEquals(OVERLAY_A0, a);
+
+        OverlayInfo b = newSettings.getOverlayInfo(OVERLAY_B1.packageName, OVERLAY_B1.userId);
+        assertEquals(OVERLAY_B1, b);
+    }
+
+    private int countXmlTags(String xml, String tagToLookFor) throws Exception {
+        int count = 0;
+        XmlPullParser parser = Xml.newPullParser();
+        parser.setInput(new StringReader(xml));
+        int event = parser.getEventType();
+        while (event != XmlPullParser.END_DOCUMENT) {
+            if (event == XmlPullParser.START_TAG && tagToLookFor.equals(parser.getName())) {
+                count++;
+            }
+            event = parser.next();
+        }
+        return count;
+    }
+
+    private int countXmlAttributesWhere(String xml, String tag, String attr, String value)
+            throws Exception {
+        int count = 0;
+        XmlPullParser parser = Xml.newPullParser();
+        parser.setInput(new StringReader(xml));
+        int event = parser.getEventType();
+        while (event != XmlPullParser.END_DOCUMENT) {
+            if (event == XmlPullParser.START_TAG && tag.equals(parser.getName())) {
+                String v = parser.getAttributeValue(null, attr);
+                if (value.equals(v)) {
+                    count++;
+                }
+            }
+            event = parser.next();
+        }
+        return count;
+    }
+
+    private void insert(OverlayInfo oi) throws Exception {
+        mSettings.init(oi.packageName, oi.userId, oi.targetPackageName, null, oi.baseCodePath,
+                false, 0, oi.category);
+        mSettings.setState(oi.packageName, oi.userId, oi.state);
+        mSettings.setEnabled(oi.packageName, oi.userId, false);
+    }
+
+    private static void assertContains(final OverlayManagerSettings settings,
+            final OverlayInfo oi) {
+        assertContains(settings, oi.packageName, oi.userId);
+    }
+
+    private static void assertContains(final OverlayManagerSettings settings,
+            final String packageName, int userId) {
+        try {
+            settings.getOverlayInfo(packageName, userId);
+        } catch (OverlayManagerSettings.BadKeyException e) {
+            fail(String.format("settings does not contain packageName=%s userId=%d",
+                        packageName, userId));
+        }
+    }
+
+    private static void assertDoesNotContain(final OverlayManagerSettings settings,
+            final OverlayInfo oi) {
+        assertDoesNotContain(settings, oi.packageName, oi.userId);
+    }
+
+    private static void assertDoesNotContain(final OverlayManagerSettings settings,
+            final String packageName, int userId) {
+        try {
+            settings.getOverlayInfo(packageName, userId);
+            fail(String.format("settings contains packageName=%s userId=%d", packageName, userId));
+        } catch (OverlayManagerSettings.BadKeyException e) {
+            // do nothing: we expect to end up here
+        }
+    }
+
+    private static void assertContains(int[] haystack, int needle) {
+        List<Integer> list = IntStream.of(haystack)
+                .boxed()
+                .collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
+        if (!list.contains(needle)) {
+            fail(String.format("integer array [%s] does not contain value %s",
+                        TextUtils.join(",", list), needle));
+        }
+    }
+
+    private static void assertDoesNotContain(int[] haystack, int needle) {
+        List<Integer> list = IntStream.of(haystack)
+                .boxed()
+                .collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
+        if (list.contains(needle)) {
+            fail(String.format("integer array [%s] contains value %s",
+                        TextUtils.join(",", list), needle));
+        }
+    }
+
+    private static void assertListsAreEqual(List<OverlayInfo> list, OverlayInfo... array) {
+        List<OverlayInfo> other = Stream.of(array)
+                .collect(ArrayList::new, ArrayList::add, ArrayList::addAll);
+        assertListsAreEqual(list, other);
+    }
+
+    private static void assertListsAreEqual(List<OverlayInfo> list, List<OverlayInfo> other) {
+        if (!list.equals(other)) {
+            fail(String.format("lists [%s] and [%s] differ",
+                        TextUtils.join(",", list), TextUtils.join(",", other)));
+        }
+    }
+}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index 6ed78b3..b34bd25 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -940,12 +940,12 @@
     @Test
     public void testClearLockedFields() {
         final NotificationChannel channel = getChannel();
-        mHelper.clearLockedFields(channel);
+        mHelper.clearLockedFieldsLocked(channel);
         assertEquals(0, channel.getUserLockedFields());
 
         channel.lockFields(NotificationChannel.USER_LOCKED_PRIORITY
                 | NotificationChannel.USER_LOCKED_IMPORTANCE);
-        mHelper.clearLockedFields(channel);
+        mHelper.clearLockedFieldsLocked(channel);
         assertEquals(0, channel.getUserLockedFields());
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/BoundsAnimationControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/BoundsAnimationControllerTests.java
index 9ce5795..beec1a8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/BoundsAnimationControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/BoundsAnimationControllerTests.java
@@ -18,6 +18,8 @@
 
 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
 
+import static com.android.server.wm.BoundsAnimationController.BOUNDS;
+import static com.android.server.wm.BoundsAnimationController.FADE_IN;
 import static com.android.server.wm.BoundsAnimationController.NO_PIP_MODE_CHANGED_CALLBACKS;
 import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_END;
 import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_START;
@@ -131,6 +133,8 @@
         boolean mCancelRequested;
         Rect mStackBounds;
         Rect mTaskBounds;
+        float mAlpha;
+        @BoundsAnimationController.AnimationType int mAnimationType;
 
         void initialize(Rect from) {
             mAwaitingAnimationStart = true;
@@ -148,11 +152,12 @@
 
         @Override
         public boolean onAnimationStart(boolean schedulePipModeChangedCallback,
-                boolean forceUpdate) {
+                boolean forceUpdate, @BoundsAnimationController.AnimationType int animationType) {
             mAwaitingAnimationStart = false;
             mAnimationStarted = true;
             mSchedulePipModeChangedOnStart = schedulePipModeChangedCallback;
             mForcePipModeChangedCallback = forceUpdate;
+            mAnimationType = animationType;
             return true;
         }
 
@@ -185,6 +190,12 @@
             mMovedToFullscreen = moveToFullscreen;
             mTaskBounds = null;
         }
+
+        @Override
+        public boolean setPinnedStackAlpha(float alpha) {
+            mAlpha = alpha;
+            return true;
+        }
     }
 
     /**
@@ -201,6 +212,7 @@
         private Rect mTo;
         private Rect mLargerBounds;
         private Rect mExpectedFinalBounds;
+        private @BoundsAnimationController.AnimationType int mAnimationType;
 
         BoundsAnimationDriver(BoundsAnimationController controller,
                 TestBoundsAnimationTarget target, MockValueAnimator mockValueAnimator) {
@@ -209,7 +221,8 @@
             mMockAnimator = mockValueAnimator;
         }
 
-        BoundsAnimationDriver start(Rect from, Rect to) {
+        BoundsAnimationDriver start(Rect from, Rect to,
+                @BoundsAnimationController.AnimationType int animationType) {
             if (mAnimator != null) {
                 throw new IllegalArgumentException("Call restart() to restart an animation");
             }
@@ -223,7 +236,7 @@
             assertTrue(mTarget.mAwaitingAnimationStart);
             assertFalse(mTarget.mAnimationStarted);
 
-            startImpl(from, to);
+            startImpl(from, to, animationType);
 
             // Ensure that the animator is paused for the all windows drawn signal when animating
             // to/from fullscreen
@@ -253,7 +266,7 @@
             mTarget.mAnimationStarted = false;
 
             // Start animation
-            startImpl(mTarget.mStackBounds, to);
+            startImpl(mTarget.mStackBounds, to, BOUNDS);
 
             if (toSameBounds) {
                 // Same animator if same final bounds
@@ -273,13 +286,15 @@
             return this;
         }
 
-        private BoundsAnimationDriver startImpl(Rect from, Rect to) {
+        private BoundsAnimationDriver startImpl(Rect from, Rect to,
+                @BoundsAnimationController.AnimationType int animationType) {
             boolean fromFullscreen = from.equals(BOUNDS_FULL);
             boolean toFullscreen = to.equals(BOUNDS_FULL);
             mFrom = new Rect(from);
             mTo = new Rect(to);
             mExpectedFinalBounds = new Rect(to);
             mLargerBounds = getLargerBounds(mFrom, mTo);
+            mAnimationType = animationType;
 
             // Start animation
             final @SchedulePipModeChangedState int schedulePipModeChangedState = toFullscreen
@@ -288,17 +303,19 @@
                             ? SCHEDULE_PIP_MODE_CHANGED_ON_END
                             : NO_PIP_MODE_CHANGED_CALLBACKS;
             mAnimator = mController.animateBoundsImpl(mTarget, from, to, DURATION,
-                    schedulePipModeChangedState, fromFullscreen, toFullscreen);
+                    schedulePipModeChangedState, fromFullscreen, toFullscreen, animationType);
 
-            // Original stack bounds, frozen task bounds
-            assertEquals(mFrom, mTarget.mStackBounds);
-            assertEqualSizeAtOffset(mLargerBounds, mTarget.mTaskBounds);
+            if (animationType == BOUNDS) {
+                // Original stack bounds, frozen task bounds
+                assertEquals(mFrom, mTarget.mStackBounds);
+                assertEqualSizeAtOffset(mLargerBounds, mTarget.mTaskBounds);
 
-            // Animating to larger size
-            if (mFrom.equals(mLargerBounds)) {
-                assertFalse(mAnimator.animatingToLargerSize());
-            } else if (mTo.equals(mLargerBounds)) {
-                assertTrue(mAnimator.animatingToLargerSize());
+                // Animating to larger size
+                if (mFrom.equals(mLargerBounds)) {
+                    assertFalse(mAnimator.animatingToLargerSize());
+                } else if (mTo.equals(mLargerBounds)) {
+                    assertTrue(mAnimator.animatingToLargerSize());
+                }
             }
 
             return this;
@@ -315,16 +332,20 @@
         BoundsAnimationDriver update(float t) {
             mAnimator.onAnimationUpdate(mMockAnimator.getWithValue(t));
 
-            // Temporary stack bounds, frozen task bounds
-            if (t == 0f) {
-                assertEquals(mFrom, mTarget.mStackBounds);
-            } else if (t == 1f) {
-                assertEquals(mTo, mTarget.mStackBounds);
+            if (mAnimationType == BOUNDS) {
+                // Temporary stack bounds, frozen task bounds
+                if (t == 0f) {
+                    assertEquals(mFrom, mTarget.mStackBounds);
+                } else if (t == 1f) {
+                    assertEquals(mTo, mTarget.mStackBounds);
+                } else {
+                    assertNotEquals(mFrom, mTarget.mStackBounds);
+                    assertNotEquals(mTo, mTarget.mStackBounds);
+                }
+                assertEqualSizeAtOffset(mLargerBounds, mTarget.mTaskBounds);
             } else {
-                assertNotEquals(mFrom, mTarget.mStackBounds);
-                assertNotEquals(mTo, mTarget.mStackBounds);
+                assertEquals((float) mMockAnimator.getAnimatedValue(), mTarget.mAlpha, 0.01f);
             }
-            assertEqualSizeAtOffset(mLargerBounds, mTarget.mTaskBounds);
             return this;
         }
 
@@ -353,10 +374,14 @@
         BoundsAnimationDriver end() {
             mAnimator.end();
 
-            // Final stack bounds
-            assertEquals(mTo, mTarget.mStackBounds);
-            assertEquals(mExpectedFinalBounds, mTarget.mAnimationEndFinalStackBounds);
-            assertNull(mTarget.mTaskBounds);
+            if (mAnimationType == BOUNDS) {
+                // Final stack bounds
+                assertEquals(mTo, mTarget.mStackBounds);
+                assertEquals(mExpectedFinalBounds, mTarget.mAnimationEndFinalStackBounds);
+                assertNull(mTarget.mTaskBounds);
+            } else {
+                assertEquals(mTarget.mAlpha, 1f, 0.01f);
+            }
 
             return this;
         }
@@ -413,7 +438,7 @@
     @UiThreadTest
     @Test
     public void testFullscreenToFloatingTransition() {
-        mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING)
+        mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING, BOUNDS)
                 .expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
                 .update(0f)
                 .update(0.5f)
@@ -425,7 +450,7 @@
     @UiThreadTest
     @Test
     public void testFloatingToFullscreenTransition() {
-        mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL)
+        mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL, BOUNDS)
                 .expectStarted(SCHEDULE_PIP_MODE_CHANGED)
                 .update(0f)
                 .update(0.5f)
@@ -437,7 +462,7 @@
     @UiThreadTest
     @Test
     public void testFloatingToSmallerFloatingTransition() {
-        mDriver.start(BOUNDS_FLOATING, BOUNDS_SMALLER_FLOATING)
+        mDriver.start(BOUNDS_FLOATING, BOUNDS_SMALLER_FLOATING, BOUNDS)
                 .expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
                 .update(0f)
                 .update(0.5f)
@@ -449,7 +474,7 @@
     @UiThreadTest
     @Test
     public void testFloatingToLargerFloatingTransition() {
-        mDriver.start(BOUNDS_SMALLER_FLOATING, BOUNDS_FLOATING)
+        mDriver.start(BOUNDS_SMALLER_FLOATING, BOUNDS_FLOATING, BOUNDS)
                 .expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
                 .update(0f)
                 .update(0.5f)
@@ -463,7 +488,7 @@
     @UiThreadTest
     @Test
     public void testFullscreenToFloatingCancelFromTarget() {
-        mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING)
+        mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING, BOUNDS)
                 .expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
                 .update(0.25f)
                 .cancel()
@@ -473,7 +498,7 @@
     @UiThreadTest
     @Test
     public void testFullscreenToFloatingCancelFromAnimationToSameBounds() {
-        mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING)
+        mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING, BOUNDS)
                 .expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
                 .update(0.25f)
                 .restart(BOUNDS_FLOATING, false /* expectStartedAndPipModeChangedCallback */)
@@ -484,7 +509,7 @@
     @UiThreadTest
     @Test
     public void testFullscreenToFloatingCancelFromAnimationToFloatingBounds() {
-        mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING)
+        mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING, BOUNDS)
                 .expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
                 .update(0.25f)
                 .restart(BOUNDS_SMALLER_FLOATING,
@@ -498,7 +523,7 @@
     public void testFullscreenToFloatingCancelFromAnimationToFullscreenBounds() {
         // When animating from fullscreen and the animation is interruped, we expect the animation
         // start callback to be made, with a forced pip mode change callback
-        mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING)
+        mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING, BOUNDS)
                 .expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
                 .update(0.25f)
                 .restart(BOUNDS_FULL, true /* expectStartedAndPipModeChangedCallback */)
@@ -511,7 +536,7 @@
     @UiThreadTest
     @Test
     public void testFloatingToFullscreenCancelFromTarget() {
-        mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL)
+        mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL, BOUNDS)
                 .expectStarted(SCHEDULE_PIP_MODE_CHANGED)
                 .update(0.25f)
                 .cancel()
@@ -521,7 +546,7 @@
     @UiThreadTest
     @Test
     public void testFloatingToFullscreenCancelFromAnimationToSameBounds() {
-        mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL)
+        mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL, BOUNDS)
                 .expectStarted(SCHEDULE_PIP_MODE_CHANGED)
                 .update(0.25f)
                 .restart(BOUNDS_FULL, false /* expectStartedAndPipModeChangedCallback */)
@@ -532,7 +557,7 @@
     @UiThreadTest
     @Test
     public void testFloatingToFullscreenCancelFromAnimationToFloatingBounds() {
-        mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL)
+        mDriver.start(BOUNDS_FLOATING, BOUNDS_FULL, BOUNDS)
                 .expectStarted(SCHEDULE_PIP_MODE_CHANGED)
                 .update(0.25f)
                 .restart(BOUNDS_SMALLER_FLOATING,
@@ -546,7 +571,7 @@
     @UiThreadTest
     @Test
     public void testFloatingToSmallerFloatingCancelFromTarget() {
-        mDriver.start(BOUNDS_FLOATING, BOUNDS_SMALLER_FLOATING)
+        mDriver.start(BOUNDS_FLOATING, BOUNDS_SMALLER_FLOATING, BOUNDS)
                 .expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
                 .update(0.25f)
                 .cancel()
@@ -556,13 +581,25 @@
     @UiThreadTest
     @Test
     public void testFloatingToLargerFloatingCancelFromTarget() {
-        mDriver.start(BOUNDS_SMALLER_FLOATING, BOUNDS_FLOATING)
+        mDriver.start(BOUNDS_SMALLER_FLOATING, BOUNDS_FLOATING, BOUNDS)
                 .expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
                 .update(0.25f)
                 .cancel()
                 .expectEnded(!SCHEDULE_PIP_MODE_CHANGED, !MOVE_TO_FULLSCREEN);
     }
 
+    @UiThreadTest
+    @Test
+    public void testFadeIn() {
+        mDriver.start(BOUNDS_FULL, BOUNDS_FLOATING, FADE_IN)
+                .expectStarted(!SCHEDULE_PIP_MODE_CHANGED)
+                .update(0f)
+                .update(0.5f)
+                .update(1f)
+                .end()
+                .expectEnded(SCHEDULE_PIP_MODE_CHANGED, !MOVE_TO_FULLSCREEN);
+    }
+
     /** MISC **/
 
     @UiThreadTest
@@ -570,7 +607,7 @@
     public void testBoundsAreCopied() {
         Rect from = new Rect(0, 0, 100, 100);
         Rect to = new Rect(25, 25, 75, 75);
-        mDriver.start(from, to)
+        mDriver.start(from, to, BOUNDS)
                 .update(0.25f)
                 .end();
         assertEquals(new Rect(0, 0, 100, 100), from);
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index e392353..0c2ce61 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -163,7 +163,7 @@
         // Assume IRecentsAnimationController#cleanupScreenshot called to finish screenshot
         // animation.
         mController.mRecentScreenshotAnimator.cancelAnimation();
-        verify(mAnimationCallbacks).onAnimationFinished(REORDER_KEEP_IN_PLACE, true);
+        verify(mAnimationCallbacks).onAnimationFinished(REORDER_KEEP_IN_PLACE, true, false);
     }
 
     private static void verifyNoMoreInteractionsExceptAsBinder(IInterface binder) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
index 5625ea4..f615823 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationTest.java
@@ -71,6 +71,7 @@
     @Test
     public void testCancelAnimationOnVisibleStackOrderChange() {
         ActivityDisplay display = mService.mRootActivityContainer.getDefaultDisplay();
+        display.mDisplayContent.mBoundsAnimationController = mock(BoundsAnimationController.class);
         ActivityStack fullscreenStack = display.createStack(WINDOWING_MODE_FULLSCREEN,
                 ACTIVITY_TYPE_STANDARD, true /* onTop */);
         new ActivityBuilder(mService)
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index 8d2cbca..ea52377 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -25,9 +25,6 @@
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
 import android.app.ActivityTaskManager;
-
-import com.android.internal.app.IVoiceActionCheckCallback;
-import com.android.server.wm.ActivityTaskManagerInternal;
 import android.app.IActivityManager;
 import android.app.IActivityTaskManager;
 import android.content.BroadcastReceiver;
@@ -51,15 +48,16 @@
 import android.util.Slog;
 import android.view.IWindowManager;
 
+import com.android.internal.app.IVoiceActionCheckCallback;
 import com.android.internal.app.IVoiceInteractionSessionShowCallback;
 import com.android.internal.app.IVoiceInteractor;
 import com.android.server.LocalServices;
+import com.android.server.wm.ActivityTaskManagerInternal;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.Set;
 
 class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConnection.Callback {
     final static String TAG = "VoiceInteractionServiceManager";
@@ -358,6 +356,7 @@
         intent.setComponent(mComponent);
         mBound = mContext.bindServiceAsUser(intent, mConnection,
                 Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE
+                | Context.BIND_INCLUDE_CAPABILITIES
                 | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS, new UserHandle(mUser));
         if (!mBound) {
             Slog.w(TAG, "Failed binding to voice interaction service " + mComponent);
diff --git a/telephony/java/android/telephony/CellSignalStrengthTdscdma.java b/telephony/java/android/telephony/CellSignalStrengthTdscdma.java
index ddbd851..b562f32 100644
--- a/telephony/java/android/telephony/CellSignalStrengthTdscdma.java
+++ b/telephony/java/android/telephony/CellSignalStrengthTdscdma.java
@@ -34,14 +34,14 @@
     private static final String LOG_TAG = "CellSignalStrengthTdscdma";
     private static final boolean DBG = false;
 
-    private static final int TDSCDMA_RSSI_MAX = -51;
-    private static final int TDSCDMA_RSSI_GREAT = -77;
-    private static final int TDSCDMA_RSSI_GOOD = -87;
-    private static final int TDSCDMA_RSSI_MODERATE = -97;
-    private static final int TDSCDMA_RSSI_POOR = -107;
-
-    private static final int TDSCDMA_RSCP_MIN = -120;
+    // These levels are arbitrary but carried over from SignalStrength.java for consistency.
     private static final int TDSCDMA_RSCP_MAX = -24;
+    private static final int TDSCDMA_RSCP_GREAT = -49;
+    private static final int TDSCDMA_RSCP_GOOD = -73;
+    private static final int TDSCDMA_RSCP_MODERATE = -97;
+    private static final int TDSCDMA_RSCP_POOR = -110;
+    private static final int TDSCDMA_RSCP_MIN = -120;
+
 
     private int mRssi; // in dBm [-113, -51], CellInfo.UNAVAILABLE
 
@@ -135,11 +135,11 @@
     /** @hide */
     @Override
     public void updateLevel(PersistableBundle cc, ServiceState ss) {
-        if (mRssi > TDSCDMA_RSSI_MAX) mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
-        else if (mRssi >= TDSCDMA_RSSI_GREAT) mLevel = SIGNAL_STRENGTH_GREAT;
-        else if (mRssi >= TDSCDMA_RSSI_GOOD)  mLevel = SIGNAL_STRENGTH_GOOD;
-        else if (mRssi >= TDSCDMA_RSSI_MODERATE)  mLevel = SIGNAL_STRENGTH_MODERATE;
-        else if (mRssi >= TDSCDMA_RSSI_POOR) mLevel = SIGNAL_STRENGTH_POOR;
+        if (mRscp > TDSCDMA_RSCP_MAX) mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+        else if (mRscp >= TDSCDMA_RSCP_GREAT) mLevel = SIGNAL_STRENGTH_GREAT;
+        else if (mRscp >= TDSCDMA_RSCP_GOOD)  mLevel = SIGNAL_STRENGTH_GOOD;
+        else if (mRscp >= TDSCDMA_RSCP_MODERATE)  mLevel = SIGNAL_STRENGTH_MODERATE;
+        else if (mRscp >= TDSCDMA_RSCP_POOR) mLevel = SIGNAL_STRENGTH_POOR;
         else mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
     }
 
@@ -159,6 +159,23 @@
     }
 
     /**
+     * Get the RSSI as dBm value -113..-51dBm or {@link CellInfo#UNAVAILABLE UNAVAILABLE}.
+     *
+     * @hide
+     */
+    public int getRssi() {
+        return mRssi;
+    }
+
+    /**
+     * Get the BER as an ASU value 0..7, 99, or {@link CellInfo#UNAVAILABLE UNAVAILABLE}.
+     * @hide
+     */
+    public int getBitErrorRate() {
+        return mBitErrorRate;
+    }
+
+    /**
      * Get the RSCP in ASU.
      *
      * Asu is calculated based on 3GPP RSRP. Refer to 3GPP 27.007 (Ver 10.3.0) Sec 8.69
diff --git a/telephony/java/android/telephony/CellSignalStrengthWcdma.java b/telephony/java/android/telephony/CellSignalStrengthWcdma.java
index d9fd7f3..8efc0f2 100644
--- a/telephony/java/android/telephony/CellSignalStrengthWcdma.java
+++ b/telephony/java/android/telephony/CellSignalStrengthWcdma.java
@@ -66,7 +66,7 @@
     public static final String LEVEL_CALCULATION_METHOD_RSCP = "rscp";
 
     // Default to RSSI for backwards compatibility with older devices
-    private static final String sLevelCalculationMethod = LEVEL_CALCULATION_METHOD_RSSI;
+    private static final String DEFAULT_LEVEL_CALCULATION_METHOD = LEVEL_CALCULATION_METHOD_RSSI;
 
     private int mRssi; // in dBm [-113, 51] or CellInfo.UNAVAILABLE if unknown
     private int mBitErrorRate; // bit error rate (0-7, 99) as defined in TS 27.007 8.5 or
@@ -161,14 +161,14 @@
         int[] rscpThresholds;
 
         if (cc == null) {
-            calcMethod = sLevelCalculationMethod;
+            calcMethod = DEFAULT_LEVEL_CALCULATION_METHOD;
             rscpThresholds = sRscpThresholds;
         } else {
             // TODO: abstract this entire thing into a series of functions
             calcMethod = cc.getString(
                     CarrierConfigManager.KEY_WCDMA_DEFAULT_SIGNAL_STRENGTH_MEASUREMENT_STRING,
-                    sLevelCalculationMethod);
-            if (TextUtils.isEmpty(calcMethod)) calcMethod = sLevelCalculationMethod;
+                    DEFAULT_LEVEL_CALCULATION_METHOD);
+            if (TextUtils.isEmpty(calcMethod)) calcMethod = DEFAULT_LEVEL_CALCULATION_METHOD;
             rscpThresholds = cc.getIntArray(
                     CarrierConfigManager.KEY_WCDMA_RSCP_THRESHOLDS_INT_ARRAY);
             if (rscpThresholds == null || rscpThresholds.length != NUM_SIGNAL_STRENGTH_THRESHOLDS) {
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index a933da7..57c84a6 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -2749,6 +2749,8 @@
      *
      * @throws SecurityException if the caller doesn't meet the requirements
      *             outlined above.
+     * @throws IllegalArgumentException if any of the subscriptions in the list doesn't exist.
+     * @throws IllegalStateException if Telephony service is in bad state.
      *
      * @param subIdList list of subId that will be in the same group
      * @return groupUUID a UUID assigned to the subscription group.
@@ -2797,6 +2799,7 @@
      *             outlined above.
      * @throws IllegalArgumentException if the some subscriptions in the list doesn't exist,
      *             or the groupUuid doesn't exist.
+     * @throws IllegalStateException if Telephony service is in bad state.
      *
      * @param subIdList list of subId that need adding into the group
      * @param groupUuid the groupUuid the subscriptions are being added to.
@@ -2849,6 +2852,7 @@
      *             outlined above.
      * @throws IllegalArgumentException if the some subscriptions in the list doesn't belong
      *             the specified group.
+     * @throws IllegalStateException if Telephony service is in bad state.
      *
      * @param subIdList list of subId that need removing from their groups.
      *
diff --git a/telephony/java/android/telephony/data/ApnSetting.java b/telephony/java/android/telephony/data/ApnSetting.java
index 7eea218..a86fda4 100644
--- a/telephony/java/android/telephony/data/ApnSetting.java
+++ b/telephony/java/android/telephony/data/ApnSetting.java
@@ -78,10 +78,11 @@
      */
     public static final int TYPE_NONE = ApnTypes.NONE;
     /**
-     * APN type for all APNs.
+     * APN type for all APNs (except wild-cardable types).
      * @hide
      */
-    public static final int TYPE_ALL = ApnTypes.ALL | ApnTypes.MCX;
+    public static final int TYPE_ALL = ApnTypes.DEFAULT | ApnTypes.HIPRI | ApnTypes.MMS
+            | ApnTypes.SUPL | ApnTypes.DUN | ApnTypes.FOTA | ApnTypes.IMS | ApnTypes.CBS;
     /** APN type for default data traffic. */
     public static final int TYPE_DEFAULT = ApnTypes.DEFAULT | ApnTypes.HIPRI;
     /** APN type for MMS traffic. */