Merge "Add ROLLBACK_FAILED apexd session to StagingManager" into qt-dev
diff --git a/Android.bp b/Android.bp
index 21054dd..6a85f62 100644
--- a/Android.bp
+++ b/Android.bp
@@ -161,6 +161,7 @@
         ":libcamera_client_framework_aidl",
         "core/java/android/hardware/IConsumerIrService.aidl",
         "core/java/android/hardware/ISerialManager.aidl",
+        "core/java/android/hardware/biometrics/IBiometricConfirmDeviceCredentialCallback.aidl",
         "core/java/android/hardware/biometrics/IBiometricEnabledOnKeyguardCallback.aidl",
         "core/java/android/hardware/biometrics/IBiometricService.aidl",
         "core/java/android/hardware/biometrics/IBiometricServiceReceiver.aidl",
diff --git a/api/current.txt b/api/current.txt
index 5997043..661b9c6 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5335,6 +5335,7 @@
     field public static final String EXTRA_TITLE = "android.title";
     field public static final String EXTRA_TITLE_BIG = "android.title.big";
     field public static final int FLAG_AUTO_CANCEL = 16; // 0x10
+    field public static final int FLAG_BUBBLE = 4096; // 0x1000
     field public static final int FLAG_FOREGROUND_SERVICE = 64; // 0x40
     field public static final int FLAG_GROUP_SUMMARY = 512; // 0x200
     field @Deprecated public static final int FLAG_HIGH_PRIORITY = 128; // 0x80
@@ -9515,7 +9516,7 @@
     method public static android.content.SyncAdapterType[] getSyncAdapterTypes();
     method public static boolean getSyncAutomatically(android.accounts.Account, String);
     method @Nullable public final String getType(@NonNull android.net.Uri);
-    method @NonNull public final android.content.ContentResolver.TypeInfo getTypeInfo(@NonNull String);
+    method @NonNull public final android.content.ContentResolver.MimeTypeInfo getTypeInfo(@NonNull String);
     method @Nullable public final android.net.Uri insert(@RequiresPermission.Write @NonNull android.net.Uri, @Nullable android.content.ContentValues);
     method public static boolean isSyncActive(android.accounts.Account, String);
     method public static boolean isSyncPending(android.accounts.Account, String);
@@ -9595,7 +9596,7 @@
     field public static final int SYNC_OBSERVER_TYPE_SETTINGS = 1; // 0x1
   }
 
-  public static final class ContentResolver.TypeInfo {
+  public static final class ContentResolver.MimeTypeInfo {
     method @NonNull public CharSequence getContentDescription();
     method @NonNull public android.graphics.drawable.Icon getIcon();
     method @NonNull public CharSequence getLabel();
@@ -10307,6 +10308,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";
@@ -38477,8 +38479,8 @@
 
   public final class MediaStore {
     ctor public MediaStore();
-    method @NonNull public static java.util.Set<java.lang.String> getAllVolumeNames(@NonNull android.content.Context);
     method @Nullable public static android.net.Uri getDocumentUri(@NonNull android.content.Context, @NonNull android.net.Uri);
+    method @NonNull public static java.util.Set<java.lang.String> getExternalVolumeNames(@NonNull android.content.Context);
     method public static android.net.Uri getMediaScannerUri();
     method @Nullable public static android.net.Uri getMediaUri(@NonNull android.content.Context, @NonNull android.net.Uri);
     method @NonNull public static String getVersion(@NonNull android.content.Context);
@@ -38522,6 +38524,7 @@
     field public static final String META_DATA_STILL_IMAGE_CAMERA_PREWARM_SERVICE = "android.media.still_image_camera_preview_service";
     field public static final String UNKNOWN_STRING = "<unknown>";
     field public static final String VOLUME_EXTERNAL = "external";
+    field public static final String VOLUME_EXTERNAL_PRIMARY = "external_primary";
     field public static final String VOLUME_INTERNAL = "internal";
   }
 
@@ -38536,6 +38539,7 @@
     field public static final String ALBUM_ID = "album_id";
     field public static final String ALBUM_KEY = "album_key";
     field public static final String ARTIST = "artist";
+    field public static final String ARTIST_ID = "artist_id";
     field public static final String FIRST_YEAR = "minyear";
     field public static final String LAST_YEAR = "maxyear";
     field public static final String NUMBER_OF_SONGS = "numsongs";
@@ -38769,6 +38773,7 @@
     field public static final String RELATIVE_PATH = "relative_path";
     field public static final String SIZE = "_size";
     field public static final String TITLE = "title";
+    field public static final String VOLUME_NAME = "volume_name";
     field public static final String WIDTH = "width";
   }
 
@@ -44380,9 +44385,9 @@
     method public int getCid();
     method public int getLac();
     method @Deprecated public int getMcc();
-    method public String getMccString();
+    method @Nullable public String getMccString();
     method @Deprecated public int getMnc();
-    method public String getMncString();
+    method @Nullable public String getMncString();
     method @Nullable public String getMobileNetworkOperator();
     method @Deprecated public int getPsc();
     method public void writeToParcel(android.os.Parcel, int);
@@ -44394,9 +44399,9 @@
     method public int getCi();
     method public int getEarfcn();
     method @Deprecated public int getMcc();
-    method public String getMccString();
+    method @Nullable public String getMccString();
     method @Deprecated public int getMnc();
-    method public String getMncString();
+    method @Nullable public String getMncString();
     method @Nullable public String getMobileNetworkOperator();
     method public int getPci();
     method public int getTac();
@@ -44419,8 +44424,8 @@
     method public int getCid();
     method public int getCpid();
     method public int getLac();
-    method public String getMccString();
-    method public String getMncString();
+    method @Nullable public String getMccString();
+    method @Nullable public String getMncString();
     method @Nullable public String getMobileNetworkOperator();
     method public int getUarfcn();
     method public void writeToParcel(android.os.Parcel, int);
@@ -44431,9 +44436,9 @@
     method public int getCid();
     method public int getLac();
     method @Deprecated public int getMcc();
-    method public String getMccString();
+    method @Nullable public String getMccString();
     method @Deprecated public int getMnc();
-    method public String getMncString();
+    method @Nullable public String getMncString();
     method @Nullable public String getMobileNetworkOperator();
     method public int getPsc();
     method public int getUarfcn();
@@ -44456,22 +44461,22 @@
   }
 
   public final class CellInfoCdma extends android.telephony.CellInfo implements android.os.Parcelable {
-    method public android.telephony.CellIdentityCdma getCellIdentity();
-    method public android.telephony.CellSignalStrengthCdma getCellSignalStrength();
+    method @NonNull public android.telephony.CellIdentityCdma getCellIdentity();
+    method @NonNull public android.telephony.CellSignalStrengthCdma getCellSignalStrength();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CellInfoCdma> CREATOR;
   }
 
   public final class CellInfoGsm extends android.telephony.CellInfo implements android.os.Parcelable {
-    method public android.telephony.CellIdentityGsm getCellIdentity();
-    method public android.telephony.CellSignalStrengthGsm getCellSignalStrength();
+    method @NonNull public android.telephony.CellIdentityGsm getCellIdentity();
+    method @NonNull public android.telephony.CellSignalStrengthGsm getCellSignalStrength();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CellInfoGsm> CREATOR;
   }
 
   public final class CellInfoLte extends android.telephony.CellInfo implements android.os.Parcelable {
-    method public android.telephony.CellIdentityLte getCellIdentity();
-    method public android.telephony.CellSignalStrengthLte getCellSignalStrength();
+    method @NonNull public android.telephony.CellIdentityLte getCellIdentity();
+    method @NonNull public android.telephony.CellSignalStrengthLte getCellSignalStrength();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CellInfoLte> CREATOR;
   }
@@ -44507,7 +44512,7 @@
     method public abstract boolean equals(Object);
     method public abstract int getAsuLevel();
     method public abstract int getDbm();
-    method public abstract int getLevel();
+    method @IntRange(from=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, to=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_GREAT) public abstract int getLevel();
     method public abstract int hashCode();
     field public static final int SIGNAL_STRENGTH_GOOD = 3; // 0x3
     field public static final int SIGNAL_STRENGTH_GREAT = 4; // 0x4
@@ -44527,7 +44532,7 @@
     method public int getEvdoEcio();
     method public int getEvdoLevel();
     method public int getEvdoSnr();
-    method public int getLevel();
+    method @IntRange(from=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, to=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_GREAT) public int getLevel();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CellSignalStrengthCdma> CREATOR;
   }
@@ -44537,7 +44542,7 @@
     method public int getAsuLevel();
     method public int getBitErrorRate();
     method public int getDbm();
-    method public int getLevel();
+    method @IntRange(from=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, to=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_GREAT) public int getLevel();
     method public int getTimingAdvance();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CellSignalStrengthGsm> CREATOR;
@@ -44548,7 +44553,7 @@
     method public int getAsuLevel();
     method public int getCqi();
     method public int getDbm();
-    method public int getLevel();
+    method @IntRange(from=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, to=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_GREAT) public int getLevel();
     method public int getRsrp();
     method public int getRsrq();
     method public int getRssi();
@@ -44565,7 +44570,7 @@
     method public int getCsiRsrq();
     method public int getCsiSinr();
     method public int getDbm();
-    method public int getLevel();
+    method @IntRange(from=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, to=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_GREAT) public int getLevel();
     method public int getSsRsrp();
     method public int getSsRsrq();
     method public int getSsSinr();
@@ -44577,7 +44582,7 @@
     method public int describeContents();
     method public int getAsuLevel();
     method public int getDbm();
-    method public int getLevel();
+    method @IntRange(from=0, to=4) public int getLevel();
     method public int getRscp();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CellSignalStrengthTdscdma> CREATOR;
@@ -44587,7 +44592,7 @@
     method public int describeContents();
     method public int getAsuLevel();
     method public int getDbm();
-    method public int getLevel();
+    method @IntRange(from=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN, to=android.telephony.CellSignalStrength.SIGNAL_STRENGTH_GREAT) public int getLevel();
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.telephony.CellSignalStrengthWcdma> CREATOR;
   }
diff --git a/api/removed.txt b/api/removed.txt
index fe3e866..70ff50e 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -514,6 +514,7 @@
 
   public final class MediaStore {
     method @Deprecated @NonNull public static android.net.Uri createPending(@NonNull android.content.Context, @NonNull android.provider.MediaStore.PendingParams);
+    method @Deprecated @NonNull public static java.util.Set<java.lang.String> getAllVolumeNames(@NonNull android.content.Context);
     method @Deprecated @NonNull public static android.provider.MediaStore.PendingSession openPending(@NonNull android.content.Context, @NonNull android.net.Uri);
     method @Deprecated @NonNull public static android.net.Uri setIncludeTrashed(@NonNull android.net.Uri);
     method @Deprecated public static void trash(@NonNull android.content.Context, @NonNull android.net.Uri);
diff --git a/api/system-current.txt b/api/system-current.txt
index db7521b..76b8f66 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -6062,11 +6062,6 @@
     field public static final String CAPTIVE_PORTAL_USE_HTTPS = "captive_portal_use_https";
     field public static final String CARRIER_APP_NAMES = "carrier_app_names";
     field public static final String CARRIER_APP_WHITELIST = "carrier_app_whitelist";
-    field public static final String DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD = "data_stall_consecutive_dns_timeout_threshold";
-    field public static final String DATA_STALL_EVALUATION_TYPE = "data_stall_evaluation_type";
-    field public static final int DATA_STALL_EVALUATION_TYPE_DNS = 1; // 0x1
-    field public static final String DATA_STALL_MIN_EVALUATE_INTERVAL = "data_stall_min_evaluate_interval";
-    field public static final String DATA_STALL_VALID_DNS_TIME_THRESHOLD = "data_stall_valid_dns_time_threshold";
     field public static final String DEFAULT_SM_DP_PLUS = "default_sm_dp_plus";
     field public static final String DEVICE_DEMO_MODE = "device_demo_mode";
     field public static final String DEVICE_PROVISIONING_MOBILE_DATA_ENABLED = "device_provisioning_mobile_data";
diff --git a/api/test-current.txt b/api/test-current.txt
index b35b90f..7121a54 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -328,8 +328,14 @@
   }
 
   public class NotificationManager {
+    method public void allowAssistantCapability(String);
+    method public void disallowAssistantCapability(String);
+    method @NonNull public java.util.List<java.lang.String> getAllowedAssistantCapabilities();
+    method @Nullable public android.content.ComponentName getAllowedNotificationAssistant();
     method public android.content.ComponentName getEffectsSuppressor();
+    method public boolean isNotificationAssistantAccessGranted(@NonNull android.content.ComponentName);
     method public boolean matchesCallFilter(android.os.Bundle);
+    method public void setNotificationAssistantAccessGranted(@Nullable android.content.ComponentName, boolean);
   }
 
   public final class PictureInPictureParams implements android.os.Parcelable {
@@ -2160,11 +2166,6 @@
     field public static final String CAPTIVE_PORTAL_OTHER_FALLBACK_URLS = "captive_portal_other_fallback_urls";
     field public static final String CAPTIVE_PORTAL_USER_AGENT = "captive_portal_user_agent";
     field public static final String CAPTIVE_PORTAL_USE_HTTPS = "captive_portal_use_https";
-    field public static final String DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD = "data_stall_consecutive_dns_timeout_threshold";
-    field public static final String DATA_STALL_EVALUATION_TYPE = "data_stall_evaluation_type";
-    field public static final int DATA_STALL_EVALUATION_TYPE_DNS = 1; // 0x1
-    field public static final String DATA_STALL_MIN_EVALUATE_INTERVAL = "data_stall_min_evaluate_interval";
-    field public static final String DATA_STALL_VALID_DNS_TIME_THRESHOLD = "data_stall_valid_dns_time_threshold";
     field public static final String DYNAMIC_POWER_SAVINGS_DISABLE_THRESHOLD = "dynamic_power_savings_disable_threshold";
     field public static final String DYNAMIC_POWER_SAVINGS_ENABLED = "dynamic_power_savings_enabled";
     field public static final String HIDDEN_API_BLACKLIST_EXEMPTIONS = "hidden_api_blacklist_exemptions";
@@ -2459,10 +2460,49 @@
 
 package android.service.notification {
 
+  public final class Adjustment implements android.os.Parcelable {
+    ctor public Adjustment(String, String, android.os.Bundle, CharSequence, int);
+    ctor public Adjustment(@NonNull String, @NonNull String, @NonNull android.os.Bundle, @NonNull CharSequence, @NonNull android.os.UserHandle);
+    method public int describeContents();
+    method @NonNull public CharSequence getExplanation();
+    method @NonNull public String getKey();
+    method @NonNull public String getPackage();
+    method @NonNull public android.os.Bundle getSignals();
+    method public int getUser();
+    method @NonNull public android.os.UserHandle getUserHandle();
+    method public void writeToParcel(android.os.Parcel, int);
+    field @NonNull public static final android.os.Parcelable.Creator<android.service.notification.Adjustment> CREATOR;
+    field public static final String KEY_CONTEXTUAL_ACTIONS = "key_contextual_actions";
+    field public static final String KEY_IMPORTANCE = "key_importance";
+    field public static final String KEY_SNOOZE_CRITERIA = "key_snooze_criteria";
+    field public static final String KEY_TEXT_REPLIES = "key_text_replies";
+    field public static final String KEY_USER_SENTIMENT = "key_user_sentiment";
+  }
+
   @Deprecated public abstract class ConditionProviderService extends android.app.Service {
     method @Deprecated public boolean isBound();
   }
 
+  public abstract class NotificationAssistantService extends android.service.notification.NotificationListenerService {
+    ctor public NotificationAssistantService();
+    method public final void adjustNotification(@NonNull android.service.notification.Adjustment);
+    method public final void adjustNotifications(@NonNull java.util.List<android.service.notification.Adjustment>);
+    method public void onActionInvoked(@NonNull String, @NonNull android.app.Notification.Action, int);
+    method @NonNull public final android.os.IBinder onBind(@Nullable android.content.Intent);
+    method public void onCapabilitiesChanged();
+    method public void onNotificationDirectReplied(@NonNull String);
+    method @Nullable public abstract android.service.notification.Adjustment onNotificationEnqueued(@NonNull android.service.notification.StatusBarNotification);
+    method @Nullable public android.service.notification.Adjustment onNotificationEnqueued(@NonNull android.service.notification.StatusBarNotification, @NonNull android.app.NotificationChannel);
+    method public void onNotificationExpansionChanged(@NonNull String, boolean, boolean);
+    method public abstract void onNotificationSnoozedUntilContext(@NonNull android.service.notification.StatusBarNotification, @NonNull String);
+    method public void onNotificationsSeen(@NonNull java.util.List<java.lang.String>);
+    method public void onSuggestedReplySent(@NonNull String, @NonNull CharSequence, int);
+    method public final void unsnoozeNotification(@NonNull String);
+    field public static final String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService";
+    field public static final int SOURCE_FROM_APP = 0; // 0x0
+    field public static final int SOURCE_FROM_ASSISTANT = 1; // 0x1
+  }
+
   public abstract class NotificationListenerService extends android.app.Service {
     method public void onNotificationRemoved(@NonNull android.service.notification.StatusBarNotification, @NonNull android.service.notification.NotificationListenerService.RankingMap, @NonNull android.service.notification.NotificationStats, int);
   }
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index e3c2f42..82d177a 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -3251,13 +3251,12 @@
         INSTALLER_ROLLBACK_BOOT_TRIGGERED_FAILURE = 14;
         INSTALLER_ROLLBACK_SUCCESS = 15;
         INSTALLER_ROLLBACK_FAILURE = 16;
-        INSTALLER_ROLLBACK_CANCEL_STAGED_REMOVE_FROM_QUEUE = 17;
-        INSTALLER_ROLLBACK_CANCEL_STAGED_DELETE_SESSION_INITIATED = 18;
-        INSTALLER_ROLLBACK_CANCEL_STAGED_DELETE_SESSION_SUCCESS = 19;
-        INSTALLER_ROLLBACK_CANCEL_STAGED_DELETE_SESSION_FAILURE = 20;
-        INSTALL_STAGED_CANCEL_REQUESTED = 21;
-        INSTALL_STAGED_CANCEL_SUCCESS = 22;
-        INSTALL_STAGED_CANCEL_FAILURE = 23;
+        INSTALLER_ROLLBACK_STAGED_CANCEL_REQUESTED = 17;
+        INSTALLER_ROLLBACK_STAGED_CANCEL_SUCCESS = 18;
+        INSTALLER_ROLLBACK_STAGED_CANCEL_FAILURE = 19;
+        INSTALL_STAGED_CANCEL_REQUESTED = 20;
+        INSTALL_STAGED_CANCEL_SUCCESS = 21;
+        INSTALL_STAGED_CANCEL_FAILURE = 22;
     }
     optional State state = 6;
     // Possible experiment ids for monitoring this push.
@@ -4919,6 +4918,8 @@
     UNKNOWN = 0;
     SOME = 1;
     FULL = 2;
+    PERSISTENT = 3;
+    BFGS = 4;
   }
   optional Action action = 3;
 
@@ -5746,13 +5747,12 @@
         INSTALLER_ROLLBACK_BOOT_TRIGGERED_FAILURE = 14;
         INSTALLER_ROLLBACK_SUCCESS = 15;
         INSTALLER_ROLLBACK_FAILURE = 16;
-        INSTALLER_ROLLBACK_CANCEL_STAGED_REMOVE_FROM_QUEUE = 17;
-        INSTALLER_ROLLBACK_CANCEL_STAGED_DELETE_SESSION_INITIATED = 18;
-        INSTALLER_ROLLBACK_CANCEL_STAGED_DELETE_SESSION_SUCCESS = 19;
-        INSTALLER_ROLLBACK_CANCEL_STAGED_DELETE_SESSION_FAILURE = 20;
-        INSTALL_STAGED_CANCEL_REQUESTED = 21;
-        INSTALL_STAGED_CANCEL_SUCCESS = 22;
-        INSTALL_STAGED_CANCEL_FAILURE = 23;
+        INSTALLER_ROLLBACK_STAGED_CANCEL_REQUESTED = 17;
+        INSTALLER_ROLLBACK_STAGED_CANCEL_SUCCESS = 18;
+        INSTALLER_ROLLBACK_STAGED_CANCEL_FAILURE = 19;
+        INSTALL_STAGED_CANCEL_REQUESTED = 20;
+        INSTALL_STAGED_CANCEL_SUCCESS = 21;
+        INSTALL_STAGED_CANCEL_FAILURE = 22;
     }
     optional Status status = 4;
 }
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/app/Notification.java b/core/java/android/app/Notification.java
index 0ab1a85..a90185c 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -618,9 +618,11 @@
     public static final int FLAG_CAN_COLORIZE = 0x00000800;
 
     /**
-     * Bit to be bitswised-ored into the {@link #flags} field that should be
-     * set if this notification can be shown as a bubble.
-     * @hide
+     * Bit to be bitswised-ored into the {@link #flags} field that should be set if this
+     * notification is showing as a bubble. This will be set by the system if it is determined
+     * that your notification is allowed to be a bubble.
+     *
+     * @see {@link Notification.Builder#setBubbleMetadata(BubbleMetadata)}
      */
     public static final int FLAG_BUBBLE = 0x00001000;
 
@@ -3578,9 +3580,9 @@
          * <p>This data will be ignored unless the notification is posted to a channel that
          * allows {@link NotificationChannel#canBubble() bubbles}.</p>
          *
-         * <b>Notifications with a valid and allowed bubble metadata will display in collapsed state
-         * outside of the notification shade on unlocked devices. When a user interacts with the
-         * collapsed state, the bubble intent will be invoked and displayed.</b>
+         * <p>Notifications allowed to bubble that have valid bubble metadata will display in
+         * collapsed state outside of the notification shade on unlocked devices. When a user
+         * interacts with the collapsed state, the bubble intent will be invoked and displayed.</p>
          */
         @NonNull
         public Builder setBubbleMetadata(@Nullable BubbleMetadata data) {
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 0bec21f..d54aca8 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -1169,6 +1169,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     public boolean isNotificationAssistantAccessGranted(@NonNull ComponentName assistant) {
         INotificationManager service = getService();
         try {
@@ -1204,6 +1205,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     public @NonNull @Adjustment.Keys List<String> getAllowedAssistantCapabilities() {
         INotificationManager service = getService();
         try {
@@ -1213,6 +1215,32 @@
         }
     }
 
+    /**
+     * @hide
+     */
+    @TestApi
+    public void allowAssistantCapability(String capability) {
+        INotificationManager service = getService();
+        try {
+            service.allowAssistantCapability(capability);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * @hide
+     */
+    @TestApi
+    public void disallowAssistantCapability(String capability) {
+        INotificationManager service = getService();
+        try {
+            service.disallowAssistantCapability(capability);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
     /** @hide */
     public boolean isNotificationPolicyAccessGrantedForPackage(String pkg) {
         INotificationManager service = getService();
@@ -1310,6 +1338,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     public void setNotificationAssistantAccessGranted(@Nullable ComponentName assistant,
             boolean granted) {
         INotificationManager service = getService();
@@ -1332,6 +1361,7 @@
 
     /** @hide */
     @SystemApi
+    @TestApi
     public @Nullable ComponentName getAllowedNotificationAssistant() {
         INotificationManager service = getService();
         try {
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 791c551..00f1e43 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -3398,7 +3398,7 @@
      *
      * @param mimeType Valid, concrete MIME type.
      */
-    public final @NonNull TypeInfo getTypeInfo(@NonNull String mimeType) {
+    public final @NonNull MimeTypeInfo getTypeInfo(@NonNull String mimeType) {
         Objects.requireNonNull(mimeType);
         return MimeIconUtils.getTypeInfo(mimeType);
     }
@@ -3407,13 +3407,13 @@
      * Detailed description of a specific MIME type, including an icon and label
      * that describe the type.
      */
-    public static final class TypeInfo {
+    public static final class MimeTypeInfo {
         private final Icon mIcon;
         private final CharSequence mLabel;
         private final CharSequence mContentDescription;
 
         /** {@hide} */
-        public TypeInfo(@NonNull Icon icon, @NonNull CharSequence label,
+        public MimeTypeInfo(@NonNull Icon icon, @NonNull CharSequence label,
                 @NonNull CharSequence contentDescription) {
             mIcon = Objects.requireNonNull(icon);
             mLabel = Objects.requireNonNull(label);
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/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 2b23e7a..270aea8 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -591,8 +591,6 @@
      */
     public interface Callback {
         boolean hasFeature(String feature);
-        String[] getOverlayPaths(String targetPackageName, String targetPath);
-        String[] getOverlayApks(String targetPackageName);
     }
 
     /**
@@ -609,14 +607,6 @@
         @Override public boolean hasFeature(String feature) {
             return mPm.hasSystemFeature(feature);
         }
-
-        @Override public String[] getOverlayPaths(String targetPackageName, String targetPath) {
-            return null;
-        }
-
-        @Override public String[] getOverlayApks(String targetPackageName) {
-            return null;
-        }
     }
 
     /**
@@ -1168,19 +1158,7 @@
             }
 
             final byte[] bytes = IoUtils.readFileAsByteArray(cacheFile.getAbsolutePath());
-            Package p = fromCacheEntry(bytes);
-            if (mCallback != null) {
-                String[] overlayApks = mCallback.getOverlayApks(p.packageName);
-                if (overlayApks != null && overlayApks.length > 0) {
-                    for (String overlayApk : overlayApks) {
-                        // If a static RRO is updated, return null.
-                        if (!isCacheUpToDate(new File(overlayApk), cacheFile)) {
-                            return null;
-                        }
-                    }
-                }
-            }
-            return p;
+            return fromCacheEntry(bytes);
         } catch (Throwable e) {
             Slog.w(TAG, "Error reading package cache: ", e);
 
@@ -1354,7 +1332,7 @@
             final Resources res = new Resources(assets, mMetrics, null);
 
             final String[] outError = new String[1];
-            final Package pkg = parseBaseApk(apkPath, res, parser, flags, outError);
+            final Package pkg = parseBaseApk(res, parser, flags, outError);
             if (pkg == null) {
                 throw new PackageParserException(mParseError,
                         apkPath + " (at " + parser.getPositionDescription() + "): " + outError[0]);
@@ -1911,7 +1889,6 @@
      * need to consider whether they should be supported by split APKs and child
      * packages.
      *
-     * @param apkPath The package apk file path
      * @param res The resources from which to resolve values
      * @param parser The manifest parser
      * @param flags Flags how to parse
@@ -1921,8 +1898,7 @@
      * @throws XmlPullParserException
      * @throws IOException
      */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
-    private Package parseBaseApk(String apkPath, Resources res, XmlResourceParser parser, int flags,
+    private Package parseBaseApk(Resources res, XmlResourceParser parser, int flags,
             String[] outError) throws XmlPullParserException, IOException {
         final String splitName;
         final String pkgName;
@@ -1942,15 +1918,6 @@
             return null;
         }
 
-        if (mCallback != null) {
-            String[] overlayPaths = mCallback.getOverlayPaths(pkgName, apkPath);
-            if (overlayPaths != null && overlayPaths.length > 0) {
-                for (String overlayPath : overlayPaths) {
-                    res.getAssets().addOverlayPath(overlayPath);
-                }
-            }
-        }
-
         final Package pkg = new Package(pkgName);
 
         TypedArray sa = res.obtainAttributes(parser,
diff --git a/core/java/android/hardware/biometrics/BiometricManager.java b/core/java/android/hardware/biometrics/BiometricManager.java
index a696eeb..6c497d4 100644
--- a/core/java/android/hardware/biometrics/BiometricManager.java
+++ b/core/java/android/hardware/biometrics/BiometricManager.java
@@ -207,5 +207,22 @@
             Slog.w(TAG, "onConfirmDeviceCredentialError(): Service not connected");
         }
     }
+
+    /**
+     * TODO(b/123378871): Remove when moved.
+     * @hide
+     */
+    @RequiresPermission(USE_BIOMETRIC_INTERNAL)
+    public void registerCancellationCallback(IBiometricConfirmDeviceCredentialCallback callback) {
+        if (mService != null) {
+            try {
+                mService.registerCancellationCallback(callback);
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
+        } else {
+            Slog.w(TAG, "registerCancellationCallback(): Service not connected");
+        }
+    }
 }
 
diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java
index 08035972..1142a07 100644
--- a/core/java/android/hardware/biometrics/BiometricPrompt.java
+++ b/core/java/android/hardware/biometrics/BiometricPrompt.java
@@ -82,6 +82,11 @@
      * @hide
      */
     public static final String KEY_ALLOW_DEVICE_CREDENTIAL = "allow_device_credential";
+    /**
+     * @hide
+     */
+    public static final String KEY_FROM_CONFIRM_DEVICE_CREDENTIAL
+            = "from_confirm_device_credential";
 
     /**
      * Error/help message will show for this amount of time.
@@ -271,6 +276,17 @@
         }
 
         /**
+         * TODO(123378871): Remove when moved.
+         * @return
+         * @hide
+         */
+        @RequiresPermission(USE_BIOMETRIC_INTERNAL)
+        @NonNull public Builder setFromConfirmDeviceCredential() {
+            mBundle.putBoolean(KEY_FROM_CONFIRM_DEVICE_CREDENTIAL, true);
+            return this;
+        }
+
+        /**
          * Creates a {@link BiometricPrompt}.
          * @return a {@link BiometricPrompt}
          * @throws IllegalArgumentException if any of the required fields are not set.
@@ -494,7 +510,8 @@
     public void authenticateUser(@NonNull CancellationSignal cancel,
             @NonNull @CallbackExecutor Executor executor,
             @NonNull AuthenticationCallback callback,
-            int userId) {
+            int userId,
+            IBiometricConfirmDeviceCredentialCallback confirmDeviceCredentialCallback) {
         if (cancel == null) {
             throw new IllegalArgumentException("Must supply a cancellation signal");
         }
@@ -504,7 +521,8 @@
         if (callback == null) {
             throw new IllegalArgumentException("Must supply a callback");
         }
-        authenticateInternal(null /* crypto */, cancel, executor, callback, userId);
+        authenticateInternal(null /* crypto */, cancel, executor, callback, userId,
+                confirmDeviceCredentialCallback);
     }
 
     /**
@@ -555,7 +573,8 @@
         if (mBundle.getBoolean(KEY_ALLOW_DEVICE_CREDENTIAL)) {
             throw new IllegalArgumentException("Device credential not supported with crypto");
         }
-        authenticateInternal(crypto, cancel, executor, callback, mContext.getUserId());
+        authenticateInternal(crypto, cancel, executor, callback, mContext.getUserId(),
+                null /* confirmDeviceCredentialCallback */);
     }
 
     /**
@@ -597,7 +616,8 @@
         if (callback == null) {
             throw new IllegalArgumentException("Must supply a callback");
         }
-        authenticateInternal(null /* crypto */, cancel, executor, callback, mContext.getUserId());
+        authenticateInternal(null /* crypto */, cancel, executor, callback, mContext.getUserId(),
+                null /* confirmDeviceCredentialCallback */);
     }
 
     private void cancelAuthentication() {
@@ -614,7 +634,8 @@
             @NonNull CancellationSignal cancel,
             @NonNull @CallbackExecutor Executor executor,
             @NonNull AuthenticationCallback callback,
-            int userId) {
+            int userId,
+            IBiometricConfirmDeviceCredentialCallback confirmDeviceCredentialCallback) {
         try {
             if (cancel.isCanceled()) {
                 Log.w(TAG, "Authentication already canceled");
@@ -629,7 +650,7 @@
             final long sessionId = crypto != null ? crypto.getOpId() : 0;
             if (BiometricManager.hasBiometrics(mContext)) {
                 mService.authenticate(mToken, sessionId, userId, mBiometricServiceReceiver,
-                        mContext.getOpPackageName(), mBundle);
+                        mContext.getOpPackageName(), mBundle, confirmDeviceCredentialCallback);
             } else {
                 mExecutor.execute(() -> {
                     callback.onAuthenticationError(BiometricPrompt.BIOMETRIC_ERROR_HW_NOT_PRESENT,
diff --git a/core/java/android/hardware/biometrics/IBiometricConfirmDeviceCredentialCallback.aidl b/core/java/android/hardware/biometrics/IBiometricConfirmDeviceCredentialCallback.aidl
new file mode 100644
index 0000000..8b35852
--- /dev/null
+++ b/core/java/android/hardware/biometrics/IBiometricConfirmDeviceCredentialCallback.aidl
@@ -0,0 +1,26 @@
+/*
+ * 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 android.hardware.biometrics;
+
+/**
+ * Communication channel between ConfirmDeviceCredential / ConfirmLock* and BiometricService.
+ * @hide
+ */
+interface IBiometricConfirmDeviceCredentialCallback {
+    // Invoked when authentication should be canceled.
+    oneway void cancel();
+}
\ No newline at end of file
diff --git a/core/java/android/hardware/biometrics/IBiometricService.aidl b/core/java/android/hardware/biometrics/IBiometricService.aidl
index 4971911..90d4921 100644
--- a/core/java/android/hardware/biometrics/IBiometricService.aidl
+++ b/core/java/android/hardware/biometrics/IBiometricService.aidl
@@ -17,6 +17,7 @@
 package android.hardware.biometrics;
 
 import android.os.Bundle;
+import android.hardware.biometrics.IBiometricConfirmDeviceCredentialCallback;
 import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
 import android.hardware.biometrics.IBiometricServiceReceiver;
 
@@ -30,8 +31,10 @@
 interface IBiometricService {
     // Requests authentication. The service choose the appropriate biometric to use, and show
     // the corresponding BiometricDialog.
+    // TODO(b/123378871): Remove callback when moved.
     void authenticate(IBinder token, long sessionId, int userId,
-            IBiometricServiceReceiver receiver, String opPackageName, in Bundle bundle);
+            IBiometricServiceReceiver receiver, String opPackageName, in Bundle bundle,
+            IBiometricConfirmDeviceCredentialCallback callback);
 
     // Cancel authentication for the given sessionId
     void cancelAuthentication(IBinder token, String opPackageName);
@@ -59,4 +62,8 @@
     void onConfirmDeviceCredentialSuccess();
     // TODO(b/123378871): Remove when moved.
     void onConfirmDeviceCredentialError(int error, String message);
+    // TODO(b/123378871): Remove when moved.
+    // When ConfirmLock* is invoked from BiometricPrompt, it needs to register a callback so that
+    // it can receive the cancellation signal.
+    void registerCancellationCallback(IBiometricConfirmDeviceCredentialCallback callback);
 }
diff --git a/core/java/android/net/NetworkStack.java b/core/java/android/net/NetworkStack.java
index dbb894f..a46c410 100644
--- a/core/java/android/net/NetworkStack.java
+++ b/core/java/android/net/NetworkStack.java
@@ -15,9 +15,16 @@
  */
 package android.net;
 
+import static android.Manifest.permission.NETWORK_STACK;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
+import android.content.Context;
 
+import java.util.ArrayList;
+import java.util.Arrays;
 /**
  *
  * Constants for client code communicating with the network stack service.
@@ -37,4 +44,52 @@
             "android.permission.MAINLINE_NETWORK_STACK";
 
     private NetworkStack() {}
+
+    /**
+     * If the NetworkStack, MAINLINE_NETWORK_STACK are not allowed for a particular process, throw a
+     * {@link SecurityException}.
+     *
+     * @param context {@link android.content.Context} for the process.
+     *
+     * @hide
+     */
+    public static void checkNetworkStackPermission(final @NonNull Context context) {
+        checkNetworkStackPermissionOr(context);
+    }
+
+    /**
+     * If the NetworkStack, MAINLINE_NETWORK_STACK or other specified permissions are not allowed
+     * for a particular process, throw a {@link SecurityException}.
+     *
+     * @param context {@link android.content.Context} for the process.
+     * @param otherPermissions The set of permissions that could be the candidate permissions , or
+     *                         empty string if none of other permissions needed.
+     * @hide
+     */
+    public static void checkNetworkStackPermissionOr(final @NonNull Context context,
+            final @NonNull String... otherPermissions) {
+        ArrayList<String> permissions = new ArrayList<String>(Arrays.asList(otherPermissions));
+        permissions.add(NETWORK_STACK);
+        permissions.add(PERMISSION_MAINLINE_NETWORK_STACK);
+        enforceAnyPermissionOf(context, permissions.toArray(new String[0]));
+    }
+
+    private static void enforceAnyPermissionOf(final @NonNull Context context,
+            final @NonNull String... permissions) {
+        if (!checkAnyPermissionOf(context, permissions)) {
+            throw new SecurityException("Requires one of the following permissions: "
+                + String.join(", ", permissions) + ".");
+        }
+    }
+
+    private static boolean checkAnyPermissionOf(final @NonNull Context context,
+            final @NonNull String... permissions) {
+        for (String permission : permissions) {
+            if (context.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED) {
+                return true;
+            }
+        }
+        return false;
+    }
+
 }
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/image/DynamicSystemClient.java b/core/java/android/os/image/DynamicSystemClient.java
index 8f68723..f1f24fb 100644
--- a/core/java/android/os/image/DynamicSystemClient.java
+++ b/core/java/android/os/image/DynamicSystemClient.java
@@ -211,7 +211,7 @@
      * Intent Keys
      */
     /**
-     * Intent key: Size of system image, in bytes.
+     * Intent key: Size of the system image, in bytes.
      * @hide
      */
     public static final String KEY_SYSTEM_SIZE = "KEY_SYSTEM_SIZE";
@@ -365,7 +365,7 @@
      *
      * This function doesn't require prior calling {@link #bind}.
      *
-     * @param systemUrl A network URL or a file URL to system image.
+     * @param systemUrl a network Uri, a file Uri or a content Uri pointing to a system image file.
      * @param systemSize size of system image.
      */
     @RequiresPermission(android.Manifest.permission.INSTALL_DYNAMIC_SYSTEM)
@@ -381,7 +381,7 @@
      *
      * This function doesn't require prior calling {@link #bind}.
      *
-     * @param systemUrl A network URL or a file URL to system image.
+     * @param systemUrl a network Uri, a file Uri or a content Uri pointing to a system image file.
      * @param systemSize size of system image.
      * @param userdataSize bytes reserved for userdata.
      */
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index c57bf91..080ff73 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -1130,7 +1130,7 @@
     public @NonNull StorageVolume getStorageVolume(@NonNull Uri uri) {
         final String volumeName = MediaStore.getVolumeName(uri);
         switch (volumeName) {
-            case MediaStore.VOLUME_EXTERNAL:
+            case MediaStore.VOLUME_EXTERNAL_PRIMARY:
                 return getPrimaryStorageVolume();
             default:
                 for (StorageVolume vol : getStorageVolumes()) {
@@ -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/os/storage/StorageVolume.java b/core/java/android/os/storage/StorageVolume.java
index 225ecfa..6280600 100644
--- a/core/java/android/os/storage/StorageVolume.java
+++ b/core/java/android/os/storage/StorageVolume.java
@@ -265,8 +265,13 @@
     }
 
     /** {@hide} */
+    public static @Nullable String normalizeUuid(@Nullable String fsUuid) {
+        return fsUuid != null ? fsUuid.toLowerCase(Locale.US) : null;
+    }
+
+    /** {@hide} */
     public @Nullable String getNormalizedUuid() {
-        return mFsUuid != null ? mFsUuid.toLowerCase(Locale.US) : null;
+        return normalizeUuid(mFsUuid);
     }
 
     /**
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index bda6ed1..da19d59 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -102,20 +102,40 @@
     public static final @NonNull Uri AUTHORITY_URI = Uri.parse("content://" + AUTHORITY);
 
     /**
-     * Volume name used for content on "internal" storage of device. This
-     * volume contains media distributed with the device, such as built-in
-     * ringtones and wallpapers.
+     * Synthetic volume name that provides a view of all content across the
+     * "internal" storage of the device.
+     * <p>
+     * This synthetic volume provides a merged view of all media distributed
+     * with the device, such as built-in ringtones and wallpapers.
+     * <p>
+     * Because this is a synthetic volume, you can't insert new content into
+     * this volume.
      */
     public static final String VOLUME_INTERNAL = "internal";
 
     /**
-     * Volume name used for content on "external" storage of device. This only
-     * includes media on the primary shared storage device; the contents of any
-     * secondary storage devices can be obtained using
-     * {@link #getAllVolumeNames(Context)}.
+     * Synthetic volume name that provides a view of all content across the
+     * "external" storage of the device.
+     * <p>
+     * This synthetic volume provides a merged view of all media across all
+     * currently attached external storage devices.
+     * <p>
+     * Because this is a synthetic volume, you can't insert new content into
+     * this volume. Instead, you can insert content into a specific storage
+     * volume obtained from {@link #getExternalVolumeNames(Context)}.
      */
     public static final String VOLUME_EXTERNAL = "external";
 
+    /**
+     * Specific volume name that represents the primary external storage device
+     * at {@link Environment#getExternalStorageDirectory()}.
+     * <p>
+     * This volume may not always be available, such as when the user has
+     * ejected the device. You can find a list of all specific volume names
+     * using {@link #getExternalVolumeNames(Context)}.
+     */
+    public static final String VOLUME_EXTERNAL_PRIMARY = "external_primary";
+
     /** {@hide} */
     public static final String SCAN_FILE_CALL = "scan_file";
     /** {@hide} */
@@ -1037,6 +1057,16 @@
         public static final String OWNER_PACKAGE_NAME = "owner_package_name";
 
         /**
+         * Volume name of the specific storage device where this media item is
+         * persisted. The value is typically one of the volume names returned
+         * from {@link MediaStore#getExternalVolumeNames(Context)}.
+         * <p>
+         * This is a read-only column that is automatically computed.
+         */
+        @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
+        public static final String VOLUME_NAME = "volume_name";
+
+        /**
          * Relative path of this media item within the storage device where it
          * is persisted. For example, an item stored at
          * {@code /storage/0000-0000/DCIM/Vacation/IMG1024.JPG} would have a
@@ -1408,7 +1438,7 @@
             final StorageVolume sv = sm.getStorageVolume(path);
             if (sv != null) {
                 if (sv.isPrimary()) {
-                    return VOLUME_EXTERNAL;
+                    return VOLUME_EXTERNAL_PRIMARY;
                 } else {
                     return checkArgumentVolumeName(sv.getNormalizedUuid());
                 }
@@ -1710,7 +1740,7 @@
                 String stringUrl = null;    /* value to be returned */
 
                 try {
-                    url = cr.insert(EXTERNAL_CONTENT_URI, values);
+                    url = cr.insert(getContentUri(VOLUME_EXTERNAL_PRIMARY), values);
 
                     if (source != null) {
                         try (OutputStream out = new ParcelFileDescriptor.AutoCloseOutputStream(
@@ -2676,7 +2706,13 @@
             public static final String ALBUM = "album";
 
             /**
-             * The artist whose songs appear on this album
+             * The ID of the artist whose songs appear on this album.
+             */
+            @Column(value = Cursor.FIELD_TYPE_INTEGER, readOnly = true)
+            public static final String ARTIST_ID = "artist_id";
+
+            /**
+             * The name of the artist whose songs appear on this album.
              */
             @Column(value = Cursor.FIELD_TYPE_STRING, readOnly = true)
             public static final String ARTIST = "artist";
@@ -3218,22 +3254,29 @@
         }
     }
 
-    /**
-     * Return list of all volume names currently available. This includes a
-     * unique name for each shared storage device that is currently mounted.
-     * <p>
-     * Each name can be passed to APIs like
-     * {@link MediaStore.Images.Media#getContentUri(String)} to query media at
-     * that location.
-     */
+    /** @removed */
+    @Deprecated
     public static @NonNull Set<String> getAllVolumeNames(@NonNull Context context) {
+        return getExternalVolumeNames(context);
+    }
+
+    /**
+     * Return list of all specific volume names that make up
+     * {@link #VOLUME_EXTERNAL}. This includes a unique volume name for each
+     * shared storage device that is currently attached, which typically
+     * includes {@link MediaStore#VOLUME_EXTERNAL_PRIMARY}.
+     * <p>
+     * Each specific volume name can be passed to APIs like
+     * {@link MediaStore.Images.Media#getContentUri(String)} to interact with
+     * media on that storage device.
+     */
+    public static @NonNull Set<String> getExternalVolumeNames(@NonNull Context context) {
         final StorageManager sm = context.getSystemService(StorageManager.class);
         final Set<String> volumeNames = new ArraySet<>();
-        volumeNames.add(VOLUME_INTERNAL);
         for (VolumeInfo vi : sm.getVolumes()) {
             if (vi.isVisibleForUser(UserHandle.myUserId()) && vi.isMountedReadable()) {
                 if (vi.isPrimary()) {
-                    volumeNames.add(VOLUME_EXTERNAL);
+                    volumeNames.add(VOLUME_EXTERNAL_PRIMARY);
                 } else {
                     volumeNames.add(vi.getNormalizedFsUuid());
                 }
@@ -3264,6 +3307,8 @@
             return volumeName;
         } else if (VOLUME_EXTERNAL.equals(volumeName)) {
             return volumeName;
+        } else if (VOLUME_EXTERNAL_PRIMARY.equals(volumeName)) {
+            return volumeName;
         }
 
         // When not one of the well-known values above, it must be a hex UUID
@@ -3279,8 +3324,9 @@
     }
 
     /**
-     * Return path where the given volume is mounted. Not valid for
-     * {@link #VOLUME_INTERNAL}.
+     * Return path where the given specific volume is mounted. Not valid for
+     * {@link #VOLUME_INTERNAL} or {@link #VOLUME_EXTERNAL}, since those are
+     * broad collections that cover many paths.
      *
      * @hide
      */
@@ -3291,8 +3337,12 @@
             throw new IllegalArgumentException();
         }
 
-        if (VOLUME_EXTERNAL.equals(volumeName)) {
-            return Environment.getExternalStorageDirectory();
+        switch (volumeName) {
+            case VOLUME_INTERNAL:
+            case VOLUME_EXTERNAL:
+                throw new FileNotFoundException(volumeName + " has no associated path");
+            case VOLUME_EXTERNAL_PRIMARY:
+                return Environment.getExternalStorageDirectory();
         }
 
         final StorageManager sm = AppGlobals.getInitialApplication()
@@ -3322,23 +3372,31 @@
             throw new IllegalArgumentException();
         }
 
+        final Context context = AppGlobals.getInitialApplication();
+        final UserManager um = context.getSystemService(UserManager.class);
+
         final ArrayList<File> res = new ArrayList<>();
         if (VOLUME_INTERNAL.equals(volumeName)) {
-            addCanoncialFile(res, new File(Environment.getRootDirectory(), "media"));
-            addCanoncialFile(res, new File(Environment.getOemDirectory(), "media"));
-            addCanoncialFile(res, new File(Environment.getProductDirectory(), "media"));
+            addCanonicalFile(res, new File(Environment.getRootDirectory(), "media"));
+            addCanonicalFile(res, new File(Environment.getOemDirectory(), "media"));
+            addCanonicalFile(res, new File(Environment.getProductDirectory(), "media"));
+        } else if (VOLUME_EXTERNAL.equals(volumeName)) {
+            for (String exactVolume : getExternalVolumeNames(context)) {
+                addCanonicalFile(res, getVolumePath(exactVolume));
+            }
+            if (um.isDemoUser()) {
+                addCanonicalFile(res, Environment.getDataPreloadsMediaDirectory());
+            }
         } else {
-            addCanoncialFile(res, getVolumePath(volumeName));
-            final UserManager um = AppGlobals.getInitialApplication()
-                    .getSystemService(UserManager.class);
-            if (VOLUME_EXTERNAL.equals(volumeName) && um.isDemoUser()) {
-                addCanoncialFile(res, Environment.getDataPreloadsMediaDirectory());
+            addCanonicalFile(res, getVolumePath(volumeName));
+            if (VOLUME_EXTERNAL_PRIMARY.equals(volumeName) && um.isDemoUser()) {
+                addCanonicalFile(res, Environment.getDataPreloadsMediaDirectory());
             }
         }
         return res;
     }
 
-    private static void addCanoncialFile(List<File> list, File file) {
+    private static void addCanonicalFile(List<File> list, File file) {
         try {
             list.add(file.getCanonicalFile());
         } catch (IOException e) {
@@ -3376,12 +3434,12 @@
      * <p>
      * No other assumptions should be made about the meaning of the version.
      * <p>
-     * This method returns the version for {@link MediaStore#VOLUME_EXTERNAL};
-     * to obtain a version for a different volume, use
-     * {@link #getVersion(Context, String)}.
+     * This method returns the version for
+     * {@link MediaStore#VOLUME_EXTERNAL_PRIMARY}; to obtain a version for a
+     * different volume, use {@link #getVersion(Context, String)}.
      */
     public static @NonNull String getVersion(@NonNull Context context) {
-        return getVersion(context, VOLUME_EXTERNAL);
+        return getVersion(context, VOLUME_EXTERNAL_PRIMARY);
     }
 
     /**
@@ -3395,7 +3453,7 @@
      *
      * @param volumeName specific volume to obtain an opaque version string for.
      *            Must be one of the values returned from
-     *            {@link #getAllVolumeNames(Context)}.
+     *            {@link #getExternalVolumeNames(Context)}.
      */
     public static @NonNull String getVersion(@NonNull Context context, @NonNull String volumeName) {
         final ContentResolver resolver = context.getContentResolver();
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 3db6b2b..6e89797 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -11199,62 +11199,6 @@
         public static final String CAPTIVE_PORTAL_USER_AGENT = "captive_portal_user_agent";
 
         /**
-         * The threshold value for the number of consecutive dns timeout events received to be a
-         * signal of data stall. The number of consecutive timeouts needs to be {@code >=} this
-         * threshold to be considered a data stall. Set the value to {@code <= 0} to disable. Note
-         * that the value should be {@code > 0} if the DNS data stall detection is enabled.
-         *
-         * @hide
-         */
-        @SystemApi
-        @TestApi
-        public static final String DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD =
-                "data_stall_consecutive_dns_timeout_threshold";
-
-        /**
-         * The minimal time interval in milliseconds for data stall reevaluation.
-         *
-         * @hide
-         */
-        @SystemApi
-        @TestApi
-        public static final String DATA_STALL_MIN_EVALUATE_INTERVAL =
-                "data_stall_min_evaluate_interval";
-
-        /**
-         * DNS timeouts older than this timeout (in milliseconds) are not considered for detecting
-         * a data stall.
-         *
-         * @hide
-         */
-        @SystemApi
-        @TestApi
-        public static final String DATA_STALL_VALID_DNS_TIME_THRESHOLD =
-                "data_stall_valid_dns_time_threshold";
-
-        /**
-         * Which data stall detection signal to use. This is a bitmask constructed by bitwise-or-ing
-         * (i.e. {@code |}) the DATA_STALL_EVALUATION_TYPE_* values.
-         *
-         * Type: int
-         * Valid values:
-         *   {@link #DATA_STALL_EVALUATION_TYPE_DNS} : Use dns as a signal.
-         * @hide
-         */
-        @SystemApi
-        @TestApi
-        public static final String DATA_STALL_EVALUATION_TYPE = "data_stall_evaluation_type";
-
-        /**
-         * Use dns timeout counts to detect data stall.
-         *
-         * @hide
-         */
-        @SystemApi
-        @TestApi
-        public static final int DATA_STALL_EVALUATION_TYPE_DNS = 1;
-
-        /**
          * Whether to try cellular data recovery when a bad network is reported.
          *
          * @hide
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/service/notification/Adjustment.java b/core/java/android/service/notification/Adjustment.java
index 8ba9a83..e81ce7f 100644
--- a/core/java/android/service/notification/Adjustment.java
+++ b/core/java/android/service/notification/Adjustment.java
@@ -18,6 +18,7 @@
 import android.annotation.NonNull;
 import android.annotation.StringDef;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.app.Notification;
 import android.os.Bundle;
 import android.os.Parcel;
@@ -40,6 +41,7 @@
  * @hide
  */
 @SystemApi
+@TestApi
 public final class Adjustment implements Parcelable {
     private final String mPackage;
     private final String mKey;
@@ -130,6 +132,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     public Adjustment(String pkg, String key, Bundle signals, CharSequence explanation, int user) {
         mPackage = pkg;
         mKey = key;
@@ -212,6 +215,7 @@
 
     /** @hide */
     @SystemApi
+    @TestApi
     public int getUser() {
         return mUser;
     }
diff --git a/core/java/android/service/notification/INotificationListener.aidl b/core/java/android/service/notification/INotificationListener.aidl
index 22104b5..8bb5f97 100644
--- a/core/java/android/service/notification/INotificationListener.aidl
+++ b/core/java/android/service/notification/INotificationListener.aidl
@@ -53,4 +53,5 @@
     void onNotificationDirectReply(String key);
     void onSuggestedReplySent(String key, in CharSequence reply, int source);
     void onActionClicked(String key, in Notification.Action action, int source);
+    void onCapabilitiesChanged();
 }
diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java
index b81725d..b4fd397 100644
--- a/core/java/android/service/notification/NotificationAssistantService.java
+++ b/core/java/android/service/notification/NotificationAssistantService.java
@@ -23,6 +23,7 @@
 import android.annotation.Nullable;
 import android.annotation.SdkConstant;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.app.Notification;
 import android.app.NotificationChannel;
 import android.app.NotificationManager;
@@ -65,6 +66,7 @@
  * @hide
  */
 @SystemApi
+@TestApi
 public abstract class NotificationAssistantService extends NotificationListenerService {
     private static final String TAG = "NotificationAssistants";
 
@@ -357,6 +359,11 @@
             args.argi2 = source;
             mHandler.obtainMessage(MyHandler.MSG_ON_ACTION_INVOKED, args).sendToTarget();
         }
+
+        @Override
+        public void onCapabilitiesChanged() {
+            mHandler.obtainMessage(MyHandler.MSG_ON_CAPABILITIES_CHANGED).sendToTarget();
+        }
     }
 
     private final class MyHandler extends Handler {
@@ -367,6 +374,7 @@
         public static final int MSG_ON_NOTIFICATION_DIRECT_REPLY_SENT = 5;
         public static final int MSG_ON_SUGGESTED_REPLY_SENT = 6;
         public static final int MSG_ON_ACTION_INVOKED = 7;
+        public static final int MSG_ON_CAPABILITIES_CHANGED = 8;
 
         public MyHandler(Looper looper) {
             super(looper, null, false);
@@ -448,6 +456,10 @@
                     onActionInvoked(key, action, source);
                     break;
                 }
+                case MSG_ON_CAPABILITIES_CHANGED: {
+                    onCapabilitiesChanged();
+                    break;
+                }
             }
         }
     }
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 333868a..016f4aa 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -1399,6 +1399,11 @@
         }
 
         @Override
+        public void onCapabilitiesChanged() {
+            // no-op in the listener
+        }
+
+        @Override
         public void onNotificationChannelModification(String pkgName, UserHandle user,
                 NotificationChannel channel,
                 @ChannelOrGroupModificationTypes int modificationType) {
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/android/view/contentcapture/ContentCaptureCondition.java b/core/java/android/view/contentcapture/ContentCaptureCondition.java
index cf171d7..6f9d4d3 100644
--- a/core/java/android/view/contentcapture/ContentCaptureCondition.java
+++ b/core/java/android/view/contentcapture/ContentCaptureCondition.java
@@ -54,7 +54,9 @@
      *
      * @param locusId id of the condition, as defined by
      * {@link ContentCaptureContext#getLocusId()}.
-     * @param flags either {@link ContentCaptureCondition#FLAG_IS_REGEX} or {@code 0}.
+     * @param flags either {@link ContentCaptureCondition#FLAG_IS_REGEX} (to use a regular
+     * expression match) or {@code 0} (in which case the {@code LocusId} must be an exact match of
+     * the {@code LocusId} used in the {@link ContentCaptureContext}).
      */
     public ContentCaptureCondition(@NonNull LocusId locusId, @Flags int flags) {
         this.mLocusId = Preconditions.checkNotNull(locusId);
diff --git a/core/java/android/view/textclassifier/ConversationAction.java b/core/java/android/view/textclassifier/ConversationAction.java
index f2d878a..b8cb7be 100644
--- a/core/java/android/view/textclassifier/ConversationAction.java
+++ b/core/java/android/view/textclassifier/ConversationAction.java
@@ -200,13 +200,11 @@
     /**
      * Returns the extended data related to this conversation action.
      *
-     * <p><b>NOTE: </b>Each call to this method returns a new bundle copy so clients should
-     * prefer to hold a reference to the returned bundle rather than frequently calling this
-     * method.
+     * <p><b>NOTE: </b>Do not modify this bundle.
      */
     @NonNull
     public Bundle getExtras() {
-        return mExtras.deepCopy();
+        return mExtras;
     }
 
     /** Builder class to construct {@link ConversationAction}. */
diff --git a/core/java/android/view/textclassifier/ConversationActions.java b/core/java/android/view/textclassifier/ConversationActions.java
index dc75212..eddc672 100644
--- a/core/java/android/view/textclassifier/ConversationActions.java
+++ b/core/java/android/view/textclassifier/ConversationActions.java
@@ -214,13 +214,11 @@
         /**
          * Returns the extended data related to this conversation action.
          *
-         * <p><b>NOTE: </b>Each call to this method returns a new bundle copy so clients should
-         * prefer to hold a reference to the returned bundle rather than frequently calling this
-         * method.
+         * <p><b>NOTE: </b>Do not modify this bundle.
          */
         @NonNull
         public Bundle getExtras() {
-            return mExtras.deepCopy();
+            return mExtras;
         }
 
         /** Builder class to construct a {@link Message} */
diff --git a/core/java/android/view/textclassifier/TextClassification.java b/core/java/android/view/textclassifier/TextClassification.java
index 9ede8fb..4c4cb55 100644
--- a/core/java/android/view/textclassifier/TextClassification.java
+++ b/core/java/android/view/textclassifier/TextClassification.java
@@ -265,13 +265,11 @@
     /**
      * Returns the extended data.
      *
-     * <p><b>NOTE: </b>Each call to this method returns a new bundle copy so clients should
-     * prefer to hold a reference to the returned bundle rather than frequently calling this
-     * method.
+     * <p><b>NOTE: </b>Do not modify this bundle.
      */
     @NonNull
     public Bundle getExtras() {
-        return mExtras.deepCopy();
+        return mExtras;
     }
 
     @Override
@@ -635,13 +633,11 @@
         /**
          * Returns the extended data.
          *
-         * <p><b>NOTE: </b>Each call to this method returns a new bundle copy so clients should
-         * prefer to hold a reference to the returned bundle rather than frequently calling this
-         * method.
+         * <p><b>NOTE: </b>Do not modify this bundle.
          */
         @NonNull
         public Bundle getExtras() {
-            return mExtras.deepCopy();
+            return mExtras;
         }
 
         /**
diff --git a/core/java/android/view/textclassifier/TextLinks.java b/core/java/android/view/textclassifier/TextLinks.java
index cde27a0..c815f63 100644
--- a/core/java/android/view/textclassifier/TextLinks.java
+++ b/core/java/android/view/textclassifier/TextLinks.java
@@ -125,13 +125,11 @@
     /**
      * Returns the extended data.
      *
-     * <p><b>NOTE: </b>Each call to this method returns a new bundle copy so clients should
-     * prefer to hold a reference to the returned bundle rather than frequently calling this
-     * method.
+     * <p><b>NOTE: </b>Do not modify this bundle.
      */
     @NonNull
     public Bundle getExtras() {
-        return mExtras.deepCopy();
+        return mExtras;
     }
 
     /**
@@ -413,13 +411,11 @@
         /**
          * Returns the extended data.
          *
-         * <p><b>NOTE: </b>Each call to this method returns a new bundle copy so clients should
-         * prefer to hold a reference to the returned bundle rather than frequently calling this
-         * method.
+         * <p><b>NOTE: </b>Do not modify this bundle.
          */
         @NonNull
         public Bundle getExtras() {
-            return mExtras.deepCopy();
+            return mExtras;
         }
 
         /**
diff --git a/core/java/android/view/textclassifier/TextSelection.java b/core/java/android/view/textclassifier/TextSelection.java
index 5298939..e378e65 100644
--- a/core/java/android/view/textclassifier/TextSelection.java
+++ b/core/java/android/view/textclassifier/TextSelection.java
@@ -112,13 +112,11 @@
     /**
      * Returns the extended data.
      *
-     * <p><b>NOTE: </b>Each call to this method returns a new bundle copy so clients should
-     * prefer to hold a reference to the returned bundle rather than frequently calling this
-     * method.
+     * <p><b>NOTE: </b>Do not modify this bundle.
      */
     @NonNull
     public Bundle getExtras() {
-        return mExtras.deepCopy();
+        return mExtras;
     }
 
     @Override
@@ -296,13 +294,11 @@
         /**
          * Returns the extended data.
          *
-         * <p><b>NOTE: </b>Each call to this method returns a new bundle copy so clients should
-         * prefer to hold a reference to the returned bundle rather than frequently calling this
-         * method.
+         * <p><b>NOTE: </b>Do not modify this bundle.
          */
         @NonNull
         public Bundle getExtras() {
-            return mExtras.deepCopy();
+            return mExtras;
         }
 
         /**
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 94be25f..51303f7 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -43,6 +43,7 @@
 import android.content.IntentSender.SendIntentException;
 import android.content.ServiceConnection;
 import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.LabeledIntent;
 import android.content.pm.LauncherApps;
 import android.content.pm.PackageManager;
@@ -117,12 +118,18 @@
 
 import java.io.IOException;
 import java.lang.annotation.Retention;
+import java.text.Collator;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
 
+/**
+ * The Chooser Activity handles intent resolution specifically for sharing intents -
+ * for example, those generated by @see android.content.Intent#createChooser(Intent, CharSequence).
+ *
+ */
 public class ChooserActivity extends ResolverActivity {
     private static final String TAG = "ChooserActivity";
 
@@ -200,6 +207,8 @@
     /** {@link ChooserActivity#getBaseScore} */
     private static final float SHORTCUT_TARGET_SCORE_BOOST = 10.f;
     private static final String TARGET_DETAILS_FRAGMENT_TAG = "targetDetailsFragment";
+    // TODO: Update to handle landscape instead of using static value
+    private static final int MAX_RANKED_TARGETS = 4;
 
     private final List<ChooserTargetServiceConnection> mServiceConnections = new ArrayList<>();
 
@@ -216,6 +225,7 @@
 
     private boolean mListViewDataChanged = false;
 
+
     @Retention(SOURCE)
     @IntDef({CONTENT_PREVIEW_FILE, CONTENT_PREVIEW_IMAGE, CONTENT_PREVIEW_TEXT})
     private @interface ContentPreviewType {
@@ -228,6 +238,9 @@
     private static final int CONTENT_PREVIEW_TEXT = 3;
     protected MetricsLogger mMetricsLogger;
 
+    // Sorted list of DisplayResolveInfos for the alphabetical app section.
+    private List<ResolverActivity.DisplayResolveInfo> mSortedList = new ArrayList<>();
+
     private final Handler mChooserHandler = new Handler() {
         @Override
         public void handleMessage(Message msg) {
@@ -935,8 +948,11 @@
         // Note that this is only safe because the Intent handled by the ChooserActivity is
         // guaranteed to contain no extras unknown to the local ClassLoader. That is why this
         // method can not be replaced in the ResolverActivity whole hog.
-        return getIntent().getBooleanExtra(Intent.EXTRA_AUTO_LAUNCH_SINGLE_CHOICE,
-                super.shouldAutoLaunchSingleChoice(target));
+        if (!super.shouldAutoLaunchSingleChoice(target)) {
+            return false;
+        }
+
+        return getIntent().getBooleanExtra(Intent.EXTRA_AUTO_LAUNCH_SINGLE_CHOICE, true);
     }
 
     @Override
@@ -961,10 +977,6 @@
 
     @Override
     protected boolean onTargetSelected(TargetInfo target, boolean alwaysCheck) {
-        if (target instanceof NotSelectableTargetInfo) {
-            return false;
-        }
-
         if (mRefinementIntentSender != null) {
             final Intent fillIn = new Intent();
             final List<Intent> sourceIntents = target.getAllSourceIntents();
@@ -997,6 +1009,11 @@
 
     @Override
     public void startSelected(int which, boolean always, boolean filtered) {
+        TargetInfo targetInfo = mChooserListAdapter.targetInfoForPosition(which, filtered);
+        if (targetInfo != null && targetInfo instanceof NotSelectableTargetInfo) {
+            return;
+        }
+
         final long selectionCost = System.currentTimeMillis() - mChooserShownTime;
         super.startSelected(which, always, filtered);
 
@@ -1405,6 +1422,30 @@
         }
     }
 
+    private void updateAlphabeticalList() {
+        if (getDisplayList().size() > MAX_RANKED_TARGETS) {
+            mSortedList.clear();
+            mSortedList.addAll(getDisplayList());
+            Collections.sort(mSortedList, new AzInfoComparator(ChooserActivity.this));
+        }
+    }
+
+    /**
+     * Sort intents alphabetically based on display label.
+     */
+    class AzInfoComparator implements Comparator<ResolverActivity.DisplayResolveInfo> {
+        Collator mCollator;
+        AzInfoComparator(Context context) {
+            mCollator = Collator.getInstance(context.getResources().getConfiguration().locale);
+        }
+
+        @Override
+        public int compare(ResolverActivity.DisplayResolveInfo lhsp,
+                ResolverActivity.DisplayResolveInfo rhsp) {
+            return mCollator.compare(lhsp.getDisplayLabel(), rhsp.getDisplayLabel());
+        }
+    }
+
     protected MetricsLogger getMetricsLogger() {
         if (mMetricsLogger == null) {
             mMetricsLogger = new MetricsLogger();
@@ -1451,7 +1492,8 @@
                 mPm,
                 getTargetIntent(),
                 getReferrerPackageName(),
-                mLaunchedFromUid);
+                mLaunchedFromUid
+                );
     }
 
     @VisibleForTesting
@@ -1527,6 +1569,10 @@
         public ChooserTarget getChooserTarget() {
             return null;
         }
+
+        public boolean isSuspended() {
+            return false;
+        }
     }
 
     final class PlaceHolderTargetInfo extends NotSelectableTargetInfo {
@@ -1552,6 +1598,7 @@
         private final Intent mFillInIntent;
         private final int mFillInFlags;
         private final float mModifiedScore;
+        private boolean mIsSuspended;
 
         SelectableTargetInfo(DisplayResolveInfo sourceInfo, ChooserTarget chooserTarget,
                 float modifiedScore) {
@@ -1580,6 +1627,8 @@
 
             mFillInIntent = null;
             mFillInFlags = 0;
+            ApplicationInfo ai = sourceInfo.getResolveInfo().activityInfo.applicationInfo;
+            mIsSuspended = (ai.flags & ApplicationInfo.FLAG_SUSPENDED) != 0;
         }
 
         private SelectableTargetInfo(SelectableTargetInfo other, Intent fillInIntent, int flags) {
@@ -1594,6 +1643,10 @@
             mModifiedScore = other.mModifiedScore;
         }
 
+        public boolean isSuspended() {
+            return mIsSuspended;
+        }
+
         /**
          * Since ShortcutInfos are returned by ShortcutManager, we can cache the shortcuts and skip
          * the call to LauncherApps#getShortcuts(ShortcutQuery).
@@ -1974,6 +2027,7 @@
 
                 queryTargetServices(this);
             }
+            updateAlphabeticalList();
         }
 
         @Override
@@ -1983,13 +2037,17 @@
 
         @Override
         public int getCount() {
-            return super.getCount() + getSelectableServiceTargetCount() + getCallerTargetCount();
+            return getStandardTargetCount() + getAlphaTargetCount()
+                    + getSelectableServiceTargetCount() + getCallerTargetCount();
         }
 
         @Override
         public int getUnfilteredCount() {
-            return super.getUnfilteredCount() + getSelectableServiceTargetCount()
-                    + getCallerTargetCount();
+            int appTargets = super.getUnfilteredCount();
+            if (appTargets > MAX_RANKED_TARGETS) {
+                appTargets = appTargets + MAX_RANKED_TARGETS;
+            }
+            return appTargets + getSelectableServiceTargetCount() + getCallerTargetCount();
         }
 
         public int getCallerTargetCount() {
@@ -2018,7 +2076,13 @@
         }
 
         public int getStandardTargetCount() {
-            return super.getCount();
+            int standardCount = super.getCount();
+            return standardCount > MAX_RANKED_TARGETS ? MAX_RANKED_TARGETS : standardCount;
+        }
+
+        int getAlphaTargetCount() {
+            int standardCount = super.getCount();
+            return standardCount > MAX_RANKED_TARGETS ? standardCount : 0;
         }
 
         public int getPositionTargetType(int position) {
@@ -2036,7 +2100,7 @@
             }
             offset += callerTargetCount;
 
-            final int standardTargetCount = super.getCount();
+            final int standardTargetCount = getStandardTargetCount();
             if (position - offset < standardTargetCount) {
                 return TARGET_STANDARD;
             }
@@ -2049,10 +2113,17 @@
             return targetInfoForPosition(position, true);
         }
 
+
+        /**
+         * Find target info for a given position.
+         * Since ChooserActivity displays several sections of content, determine which
+         * section provides this item.
+         */
         @Override
         public TargetInfo targetInfoForPosition(int position, boolean filtered) {
             int offset = 0;
 
+            // Direct share targets
             final int serviceTargetCount = filtered ? getServiceTargetCount() :
                                                getSelectableServiceTargetCount();
             if (position < serviceTargetCount) {
@@ -2060,16 +2131,32 @@
             }
             offset += serviceTargetCount;
 
+            // Targets provided by calling app
             final int callerTargetCount = getCallerTargetCount();
             if (position - offset < callerTargetCount) {
                 return mCallerTargets.get(position - offset);
             }
             offset += callerTargetCount;
 
-            return filtered ? super.getItem(position - offset)
-                    : getDisplayResolveInfo(position - offset);
+            // Ranked app targets
+            if (position - offset < MAX_RANKED_TARGETS) {
+                return filtered ? super.getItem(position - offset)
+                        : getDisplayResolveInfo(position - offset);
+            }
+            offset += MAX_RANKED_TARGETS;
+
+            // Alphabetical complete app target list.
+            Log.e(TAG, mSortedList.toString());
+            if (position - offset < mSortedList.size()) {
+                return mSortedList.get(position - offset);
+            }
+
+            return null;
+
         }
 
+
+
         /**
          * Evaluate targets for inclusion in the direct share area. May not be included
          * if score is too low.
@@ -2100,6 +2187,9 @@
 
             final float baseScore = getBaseScore(origTarget, isShortcutResult);
             Collections.sort(targets, mBaseTargetComparator);
+
+
+
             float lastScore = 0;
             boolean shouldNotify = false;
             for (int i = 0, N = Math.min(targets.size(), MAX_TARGETS_PER_SERVICE); i < N; i++) {
@@ -2204,6 +2294,7 @@
         }
     }
 
+
     private boolean isSendAction(Intent targetIntent) {
         if (targetIntent == null) {
             return false;
@@ -2299,6 +2390,9 @@
                             + Math.ceil(
                             (float) mChooserListAdapter.getStandardTargetCount()
                                     / getMaxTargetsPerRow())
+                            + Math.ceil(
+                            (float) mChooserListAdapter.getAlphaTargetCount()
+                                    / getMaxTargetsPerRow())
             );
         }
 
@@ -2961,6 +3055,7 @@
         private int mRadius = 0;
         private Path mPath = new Path();
         private Paint mOverlayPaint = new Paint(0);
+        private Paint mRoundRectPaint = new Paint(0);
         private Paint mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
         private String mExtraImageCount = null;
 
@@ -2984,6 +3079,11 @@
             mOverlayPaint.setColor(0x99000000);
             mOverlayPaint.setStyle(Paint.Style.FILL);
 
+            mRoundRectPaint.setColor(context.getResources().getColor(R.color.chooser_row_divider));
+            mRoundRectPaint.setStyle(Paint.Style.STROKE);
+            mRoundRectPaint.setStrokeWidth(context.getResources()
+                    .getDimensionPixelSize(R.dimen.chooser_preview_image_border));
+
             mTextPaint.setColor(Color.WHITE);
             mTextPaint.setTextSize(context.getResources()
                     .getDimensionPixelSize(R.dimen.chooser_preview_image_font_size));
@@ -2993,8 +3093,8 @@
         private void updatePath(int width, int height) {
             mPath.reset();
 
-            int imageWidth = width - getPaddingRight();
-            int imageHeight = height - getPaddingBottom();
+            int imageWidth = width - getPaddingRight() - getPaddingLeft();
+            int imageHeight = height - getPaddingBottom() - getPaddingTop();
             mPath.addRoundRect(getPaddingLeft(), getPaddingTop(), imageWidth, imageHeight, mRadius,
                     mRadius, Path.Direction.CW);
         }
@@ -3026,7 +3126,6 @@
             updatePath(width, height);
         }
 
-
         @Override
         protected void onDraw(Canvas canvas) {
             if (mRadius != 0) {
@@ -3035,8 +3134,12 @@
 
             super.onDraw(canvas);
 
+            int x = getPaddingLeft();
+            int y = getPaddingRight();
+            int width = getWidth() - getPaddingRight() - getPaddingLeft();
+            int height = getHeight() - getPaddingBottom() - getPaddingTop();
             if (mExtraImageCount != null) {
-                canvas.drawRect(0, 0, canvas.getWidth(), canvas.getHeight(), mOverlayPaint);
+                canvas.drawRect(x, y, width, height, mOverlayPaint);
 
                 int xPos = canvas.getWidth() / 2;
                 int yPos = (int) ((canvas.getHeight() / 2.0f)
@@ -3044,6 +3147,8 @@
 
                 canvas.drawText(mExtraImageCount, xPos, yPos, mTextPaint);
             }
+
+            canvas.drawRoundRect(x, y, width, height, mRadius, mRadius, mRoundRectPaint);
         }
     }
 }
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index f671a75..ad1e767 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -44,6 +44,8 @@
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
+import android.graphics.ColorMatrix;
+import android.graphics.ColorMatrixColorFilter;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
@@ -132,6 +134,8 @@
 
     private boolean mRegistered;
 
+    private ColorMatrixColorFilter mSuspendedMatrixColorFilter;
+
     /** See {@link #setRetainInOnStop}. */
     private boolean mRetainInOnStop;
 
@@ -350,6 +354,8 @@
             bindProfileView();
         }
 
+        initSuspendedColorMatrix();
+
         if (isVoiceInteraction()) {
             onSetupVoiceInteraction();
         }
@@ -367,6 +373,25 @@
         mAdapter.handlePackagesChanged();
     }
 
+    private void initSuspendedColorMatrix() {
+        int grayValue = 127;
+        float scale = 0.5f; // half bright
+
+        ColorMatrix tempBrightnessMatrix = new ColorMatrix();
+        float[] mat = tempBrightnessMatrix.getArray();
+        mat[0] = scale;
+        mat[6] = scale;
+        mat[12] = scale;
+        mat[4] = grayValue;
+        mat[9] = grayValue;
+        mat[14] = grayValue;
+
+        ColorMatrix matrix = new ColorMatrix();
+        matrix.setSaturation(0.0f);
+        matrix.preConcat(tempBrightnessMatrix);
+        mSuspendedMatrixColorFilter = new ColorMatrixColorFilter(matrix);
+    }
+
     /**
      * Perform any initialization needed for voice interaction.
      */
@@ -1019,7 +1044,14 @@
 
         if (target != null) {
             safelyStartActivity(target);
+
+            // Rely on the ActivityManager to pop up a dialog regarding app suspension
+            // and return false
+            if (target.isSuspended()) {
+                return false;
+            }
         }
+
         return true;
     }
 
@@ -1106,7 +1138,7 @@
     }
 
     public boolean shouldAutoLaunchSingleChoice(TargetInfo target) {
-        return true;
+        return !target.isSuspended();
     }
 
     public void showTargetDetails(ResolveInfo ri) {
@@ -1326,6 +1358,7 @@
         private final CharSequence mExtendedInfo;
         private final Intent mResolvedIntent;
         private final List<Intent> mSourceIntents = new ArrayList<>();
+        private boolean mIsSuspended;
 
         public DisplayResolveInfo(Intent originalIntent, ResolveInfo pri, CharSequence pLabel,
                 CharSequence pInfo, Intent pOrigIntent) {
@@ -1341,6 +1374,8 @@
             final ActivityInfo ai = mResolveInfo.activityInfo;
             intent.setComponent(new ComponentName(ai.applicationInfo.packageName, ai.name));
 
+            mIsSuspended = (ai.applicationInfo.flags & ApplicationInfo.FLAG_SUSPENDED) != 0;
+
             mResolvedIntent = intent;
         }
 
@@ -1410,7 +1445,6 @@
 
         @Override
         public boolean startAsCaller(ResolverActivity activity, Bundle options, int userId) {
-
             if (mEnableChooserDelegate) {
                 return activity.startAsCallerImpl(mResolvedIntent, options, false, userId);
             } else {
@@ -1424,6 +1458,14 @@
             activity.startActivityAsUser(mResolvedIntent, options, user);
             return false;
         }
+
+        public boolean isSuspended() {
+            return mIsSuspended;
+        }
+    }
+
+    List<DisplayResolveInfo> getDisplayList() {
+        return mAdapter.mDisplayList;
     }
 
     /**
@@ -1515,6 +1557,11 @@
          * @return the list of supported source intents deduped against this single target
          */
         List<Intent> getAllSourceIntents();
+
+        /**
+          * @return true if this target can be selected by the user
+          */
+        boolean isSuspended();
     }
 
     public class ResolveListAdapter extends BaseAdapter {
@@ -1523,12 +1570,12 @@
         private final List<ResolveInfo> mBaseResolveList;
         protected ResolveInfo mLastChosen;
         private DisplayResolveInfo mOtherProfile;
-        private boolean mHasExtendedInfo;
         private ResolverListController mResolverListController;
         private int mPlaceholderCount;
 
         protected final LayoutInflater mInflater;
 
+        // This one is the list that the Adapter will actually present.
         List<DisplayResolveInfo> mDisplayList;
         List<ResolvedComponentInfo> mUnfilteredResolveList;
 
@@ -1709,6 +1756,7 @@
             }
         }
 
+
         private void processSortedList(List<ResolvedComponentInfo> sortedComponents) {
             int N;
             if (sortedComponents != null && (N = sortedComponents.size()) != 0) {
@@ -1746,6 +1794,7 @@
                     }
                 }
 
+
                 for (ResolvedComponentInfo rci : sortedComponents) {
                     final ResolveInfo ri = rci.getResolveInfoAt(0);
                     if (ri != null) {
@@ -1755,9 +1804,12 @@
                 }
             }
 
+
             postListReadyRunnable();
         }
 
+
+
         /**
          * Some necessary methods for creating the list are initiated in onCreate and will also
          * determine the layout known. We therefore can't update the UI inline and post to the
@@ -1891,19 +1943,6 @@
             return position;
         }
 
-        public boolean hasExtendedInfo() {
-            return mHasExtendedInfo;
-        }
-
-        public boolean hasResolvedTarget(ResolveInfo info) {
-            for (int i = 0, N = mDisplayList.size(); i < N; i++) {
-                if (resolveInfoMatch(info, mDisplayList.get(i).getResolveInfo())) {
-                    return true;
-                }
-            }
-            return false;
-        }
-
         public int getDisplayResolveInfoCount() {
             return mDisplayList.size();
         }
@@ -1960,6 +1999,12 @@
                 holder.text2.setText(subLabel);
             }
 
+            if (info.isSuspended()) {
+                holder.icon.setColorFilter(mSuspendedMatrixColorFilter);
+            } else {
+                holder.icon.setColorFilter(null);
+            }
+
             if (info instanceof DisplayResolveInfo
                     && !((DisplayResolveInfo) info).hasDisplayIcon()) {
                 new LoadIconTask((DisplayResolveInfo) info, holder.icon).execute();
@@ -1969,6 +2014,7 @@
         }
     }
 
+
     @VisibleForTesting
     public static final class ResolvedComponentInfo {
         public final ComponentName name;
diff --git a/core/java/com/android/internal/app/ResolverListController.java b/core/java/com/android/internal/app/ResolverListController.java
index 156baf0..a3cfa87 100644
--- a/core/java/com/android/internal/app/ResolverListController.java
+++ b/core/java/com/android/internal/app/ResolverListController.java
@@ -25,7 +25,6 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.os.RemoteException;
@@ -153,11 +152,6 @@
     }
 
     // Filter out any activities that the launched uid does not have permission for.
-    //
-    // Also filter out those that are suspended because they couldn't be started. We don't do this
-    // when we have an explicit list of resolved activities, because that only happens when
-    // we are being subclassed, so we can safely launch whatever they gave us.
-    //
     // To preserve the inputList, optionally will return the original list if any modification has
     // been made.
     @VisibleForTesting
@@ -171,9 +165,8 @@
             int granted = ActivityManager.checkComponentPermission(
                     ai.permission, mLaunchedFromUid,
                     ai.applicationInfo.uid, ai.exported);
-            boolean suspended = (ai.applicationInfo.flags
-                    & ApplicationInfo.FLAG_SUSPENDED) != 0;
-            if (granted != PackageManager.PERMISSION_GRANTED || suspended
+
+            if (granted != PackageManager.PERMISSION_GRANTED
                     || isComponentFiltered(ai.getComponentName())) {
                 // Access not allowed! We're about to filter an item,
                 // so modify the unfiltered version if it hasn't already been modified.
@@ -253,6 +246,7 @@
                 isComputed = true;
             }
             Collections.sort(inputList, mResolverComparator);
+
             long afterRank = System.currentTimeMillis();
             if (DEBUG) {
                 Log.d(TAG, "Time Cost: " + Long.toString(afterRank - beforeRank));
@@ -262,6 +256,7 @@
         }
     }
 
+
     private static boolean isSameResolvedComponent(ResolveInfo a,
             ResolverActivity.ResolvedComponentInfo b) {
         final ActivityInfo ai = a.activityInfo;
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/java/com/android/internal/util/MimeIconUtils.java b/core/java/com/android/internal/util/MimeIconUtils.java
index 0b5fa6d..8523b4e 100644
--- a/core/java/com/android/internal/util/MimeIconUtils.java
+++ b/core/java/com/android/internal/util/MimeIconUtils.java
@@ -18,7 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.content.ContentResolver.TypeInfo;
+import android.content.ContentResolver.MimeTypeInfo;
 import android.content.res.Resources;
 import android.graphics.drawable.Icon;
 import android.text.TextUtils;
@@ -34,9 +34,9 @@
 
 public class MimeIconUtils {
     @GuardedBy("sCache")
-    private static final ArrayMap<String, TypeInfo> sCache = new ArrayMap<>();
+    private static final ArrayMap<String, MimeTypeInfo> sCache = new ArrayMap<>();
 
-    private static TypeInfo buildTypeInfo(String mimeType, int iconId,
+    private static MimeTypeInfo buildTypeInfo(String mimeType, int iconId,
             int labelId, int extLabelId) {
         final Resources res = Resources.getSystem();
 
@@ -49,10 +49,10 @@
             label = res.getString(labelId);
         }
 
-        return new TypeInfo(Icon.createWithResource(res, iconId), label, label);
+        return new MimeTypeInfo(Icon.createWithResource(res, iconId), label, label);
     }
 
-    private static @Nullable TypeInfo buildTypeInfo(@NonNull String mimeType) {
+    private static @Nullable MimeTypeInfo buildTypeInfo(@NonNull String mimeType) {
         switch (mimeType) {
             case "inode/directory":
             case "vnd.android.document/directory":
@@ -222,7 +222,7 @@
         }
     }
 
-    private static @Nullable TypeInfo buildGenericTypeInfo(@NonNull String mimeType) {
+    private static @Nullable MimeTypeInfo buildGenericTypeInfo(@NonNull String mimeType) {
         // Look for partial matches
         if (mimeType.startsWith("audio/")) {
             return buildTypeInfo(mimeType, R.drawable.ic_doc_audio,
@@ -252,12 +252,12 @@
                 R.string.mime_type_generic, R.string.mime_type_generic_ext);
     }
 
-    public static @NonNull TypeInfo getTypeInfo(@NonNull String mimeType) {
+    public static @NonNull MimeTypeInfo getTypeInfo(@NonNull String mimeType) {
         // Normalize MIME type
         mimeType = mimeType.toLowerCase(Locale.US);
 
         synchronized (sCache) {
-            TypeInfo res = sCache.get(mimeType);
+            MimeTypeInfo res = sCache.get(mimeType);
             if (res == null) {
                 res = buildTypeInfo(mimeType);
                 sCache.put(mimeType, res);
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/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index c646fef..02cbc2e 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -724,6 +724,7 @@
     <dimen name="chooser_edge_margin_thin">16dp</dimen>
     <dimen name="chooser_edge_margin_normal">24dp</dimen>
     <dimen name="chooser_preview_image_font_size">20sp</dimen>
+    <dimen name="chooser_preview_image_border">1dp</dimen>
     <dimen name="chooser_preview_width">-1px</dimen>
     <dimen name="resolver_icon_size">42dp</dimen>
     <dimen name="resolver_badge_size">18dp</dimen>
diff --git a/core/res/res/values/dimens_car.xml b/core/res/res/values/dimens_car.xml
index a43f752..f22a91f 100644
--- a/core/res/res/values/dimens_car.xml
+++ b/core/res/res/values/dimens_car.xml
@@ -66,9 +66,10 @@
     <dimen name="car_padding_0">4dp</dimen>
     <dimen name="car_padding_1">8dp</dimen>
     <dimen name="car_padding_2">16dp</dimen>
-    <dimen name="car_padding_3">28dp</dimen>
+    <dimen name="car_padding_3">24dp</dimen>
     <dimen name="car_padding_4">32dp</dimen>
     <dimen name="car_padding_5">64dp</dimen>
+    <dimen name="car_padding_6">96dp</dimen>
 
     <!-- Radius -->
     <dimen name="car_radius_1">4dp</dimen>
@@ -121,6 +122,9 @@
     <!-- Dialog button end margin -->
     <dimen name="button_end_margin">@*android:dimen/car_padding_4</dimen>
 
+    <!-- Dialog top padding when there is no title -->
+    <dimen name="dialog_no_title_padding_top">@*android:dimen/car_padding_4</dimen>
+
     <!-- Dialog start margin for text view -->
     <dimen name="text_view_start_margin">@*android:dimen/car_keyline_1</dimen>
 
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 256072a..f8a2ac9 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -525,7 +525,7 @@
     <!-- label for screenshot item in power menu -->
     <string name="global_action_screenshot">Screenshot</string>
 
-    <!-- Take bug report menu title [CHAR LIMIT=20] -->
+    <!-- Take bug report menu title [CHAR LIMIT=30] -->
     <string name="bugreport_title">Bug report</string>
     <!-- Message in bugreport dialog describing what it does [CHAR LIMIT=NONE] -->
     <!-- TODO: remove if not used anymore -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index b873813..fb72da5 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2777,6 +2777,7 @@
   <java-symbol type="dimen" name="chooser_edge_margin_normal" />
   <java-symbol type="dimen" name="chooser_preview_image_font_size"/>
   <java-symbol type="dimen" name="chooser_preview_width" />
+  <java-symbol type="dimen" name="chooser_preview_image_border"/>
   <java-symbol type="dimen" name="chooser_max_collapsed_height" />
   <java-symbol type="layout" name="chooser_grid" />
   <java-symbol type="layout" name="chooser_grid_preview_text" />
@@ -2790,6 +2791,7 @@
   <java-symbol type="drawable" name="scroll_indicator_material" />
 
   <java-symbol type="layout" name="chooser_row" />
+  <java-symbol type="color" name="chooser_row_divider" />
   <java-symbol type="layout" name="chooser_row_direct_share" />
   <java-symbol type="bool" name="config_supportDoubleTapWake" />
   <java-symbol type="drawable" name="ic_perm_device_info" />
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 8cc6e37..6550707 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -203,11 +203,7 @@
                     Settings.Global.DATA_ROAMING,
                     Settings.Global.DATA_STALL_ALARM_AGGRESSIVE_DELAY_IN_MS,
                     Settings.Global.DATA_STALL_ALARM_NON_AGGRESSIVE_DELAY_IN_MS,
-                    Settings.Global.DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD,
-                    Settings.Global.DATA_STALL_EVALUATION_TYPE,
-                    Settings.Global.DATA_STALL_MIN_EVALUATE_INTERVAL,
                     Settings.Global.DATA_STALL_RECOVERY_ON_BAD_NETWORK,
-                    Settings.Global.DATA_STALL_VALID_DNS_TIME_THRESHOLD,
                     Settings.Global.DEBUG_APP,
                     Settings.Global.DEBUG_VIEW_ATTRIBUTES,
                     Settings.Global.DEBUG_VIEW_ATTRIBUTES_APPLICATION_PACKAGE,
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index ed198e6..e4a93e7 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -309,6 +309,7 @@
         <permission name="android.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS"/>
         <permission name="android.permission.SET_WALLPAPER" />
         <permission name="android.permission.SET_WALLPAPER_COMPONENT" />
+        <permission name="android.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE" />
     </privapp-permissions>
 
     <privapp-permissions package="com.android.statementservice">
diff --git a/libs/hwui/tests/unit/CommonPoolTests.cpp b/libs/hwui/tests/unit/CommonPoolTests.cpp
index c564ed6..70a5f5a 100644
--- a/libs/hwui/tests/unit/CommonPoolTests.cpp
+++ b/libs/hwui/tests/unit/CommonPoolTests.cpp
@@ -135,4 +135,48 @@
     for (auto& f : futures) {
         f.get();
     }
+}
+
+class ObjectTracker {
+    static std::atomic_int sGlobalCount;
+
+public:
+    ObjectTracker() {
+        sGlobalCount++;
+    }
+    ObjectTracker(const ObjectTracker&) {
+        sGlobalCount++;
+    }
+    ObjectTracker(ObjectTracker&&) {
+        sGlobalCount++;
+    }
+    ~ObjectTracker() {
+        sGlobalCount--;
+    }
+
+    static int count() { return sGlobalCount.load(); }
+};
+
+std::atomic_int ObjectTracker::sGlobalCount{0};
+
+TEST(CommonPool, asyncLifecycleCheck) {
+    ASSERT_EQ(0, ObjectTracker::count());
+    {
+        ObjectTracker obj;
+        ASSERT_EQ(1, ObjectTracker::count());
+        EXPECT_LT(1, CommonPool::async([obj] { return ObjectTracker::count(); }).get());
+    }
+    CommonPool::waitForIdle();
+    ASSERT_EQ(0, ObjectTracker::count());
+}
+
+TEST(CommonPool, syncLifecycleCheck) {
+    ASSERT_EQ(0, ObjectTracker::count());
+    {
+        ObjectTracker obj;
+        ASSERT_EQ(1, ObjectTracker::count());
+        EXPECT_LT(1, CommonPool::runSync([obj] { return ObjectTracker::count(); }));
+    }
+    CommonPool::waitForIdle();
+    ASSERT_EQ(0, ObjectTracker::count());
 }
\ No newline at end of file
diff --git a/libs/hwui/thread/CommonPool.cpp b/libs/hwui/thread/CommonPool.cpp
index 7f94a15..d011bdf 100644
--- a/libs/hwui/thread/CommonPool.cpp
+++ b/libs/hwui/thread/CommonPool.cpp
@@ -49,9 +49,13 @@
     }
 }
 
-void CommonPool::post(Task&& task) {
+CommonPool& CommonPool::instance() {
     static CommonPool pool;
-    pool.enqueue(std::move(task));
+    return pool;
+}
+
+void CommonPool::post(Task&& task) {
+    instance().enqueue(std::move(task));
 }
 
 void CommonPool::enqueue(Task&& task) {
@@ -86,5 +90,18 @@
     }
 }
 
+void CommonPool::waitForIdle() {
+    instance().doWaitForIdle();
+}
+
+void CommonPool::doWaitForIdle() {
+    std::unique_lock lock(mLock);
+    while (mWaitingThreads != THREAD_COUNT) {
+        lock.unlock();
+        usleep(100);
+        lock.lock();
+    }
+}
+
 }  // namespace uirenderer
 }  // namespace android
\ No newline at end of file
diff --git a/libs/hwui/thread/CommonPool.h b/libs/hwui/thread/CommonPool.h
index aef2990..7603eee 100644
--- a/libs/hwui/thread/CommonPool.h
+++ b/libs/hwui/thread/CommonPool.h
@@ -57,11 +57,13 @@
         mHead = newHead;
     }
 
-    constexpr T&& pop() {
+    constexpr T pop() {
         LOG_ALWAYS_FATAL_IF(mTail == mHead, "empty");
         int index = mTail;
         mTail = (mTail + 1) % SIZE;
-        return std::move(mBuffer[index]);
+        T ret = std::move(mBuffer[index]);
+        mBuffer[index] = nullptr;
+        return ret;
     }
 
 private:
@@ -95,11 +97,17 @@
         return task.get_future().get();
     };
 
+    // For testing purposes only, blocks until all worker threads are parked.
+    static void waitForIdle();
+
 private:
+    static CommonPool& instance();
+
     CommonPool();
     ~CommonPool() {}
 
     void enqueue(Task&&);
+    void doWaitForIdle();
 
     void workerLoop();
 
diff --git a/libs/hwui/utils/Color.cpp b/libs/hwui/utils/Color.cpp
index d14116f..39740bd 100644
--- a/libs/hwui/utils/Color.cpp
+++ b/libs/hwui/utils/Color.cpp
@@ -60,6 +60,9 @@
 }
 
 sk_sp<SkColorSpace> DataSpaceToColorSpace(android_dataspace dataspace) {
+    if (dataspace == HAL_DATASPACE_UNKNOWN) {
+        return SkColorSpace::MakeSRGB();
+    }
 
     skcms_Matrix3x3 gamut;
     switch (dataspace & HAL_DATASPACE_STANDARD_MASK) {
diff --git a/media/Android.bp b/media/Android.bp
index 3480181..8746046 100644
--- a/media/Android.bp
+++ b/media/Android.bp
@@ -24,6 +24,10 @@
         "mediaplayer2-protos",
     ],
 
+    permitted_packages: [
+        "android.media",
+    ],
+
     installable: true,
 
     // Make sure that the implementaion only relies on SDK or system APIs.
diff --git a/media/apex/java/android/media/MediaPlayer2.java b/media/apex/java/android/media/MediaPlayer2.java
index 87035da..db33e82 100644
--- a/media/apex/java/android/media/MediaPlayer2.java
+++ b/media/apex/java/android/media/MediaPlayer2.java
@@ -31,6 +31,7 @@
 import android.media.MediaPlayer2.DrmInfo;
 import android.media.MediaPlayer2Proto.PlayerMessage;
 import android.media.MediaPlayer2Proto.Value;
+import android.media.protobuf.InvalidProtocolBufferException;
 import android.net.Uri;
 import android.os.Handler;
 import android.os.HandlerThread;
@@ -46,7 +47,6 @@
 import android.view.SurfaceHolder;
 
 import com.android.internal.annotations.GuardedBy;
-import com.android.media.protobuf.InvalidProtocolBufferException;
 
 import java.io.ByteArrayOutputStream;
 import java.io.File;
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index 325e227..790e189 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -25,7 +25,6 @@
 import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
 import android.os.Binder;
-import android.os.Build;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Looper;
@@ -1662,7 +1661,7 @@
      * a better solution.
      * @hide
      */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 112561552)
+    @UnsupportedAppUsage(trackingBug = 130237544)
     public int getLatency() {
         return native_get_latency();
     }
diff --git a/media/proto/jarjar-rules.txt b/media/proto/jarjar-rules.txt
index bfb0b27..e73f86d 100644
--- a/media/proto/jarjar-rules.txt
+++ b/media/proto/jarjar-rules.txt
@@ -1,2 +1,2 @@
-rule com.google.protobuf.** com.android.media.protobuf.@1
+rule com.google.protobuf.** android.media.protobuf.@1
 
diff --git a/packages/CaptivePortalLogin/AndroidManifest.xml b/packages/CaptivePortalLogin/AndroidManifest.xml
index a528636..355bdd8 100644
--- a/packages/CaptivePortalLogin/AndroidManifest.xml
+++ b/packages/CaptivePortalLogin/AndroidManifest.xml
@@ -18,7 +18,7 @@
 -->
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.android.captiveportallogin"
-    android:versionCode="200000000"
+    android:versionCode="210000000"
     android:versionName="Q-initial">
 
     <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="28" />
diff --git a/packages/DynamicSystemInstallationService/res/values/strings.xml b/packages/DynamicSystemInstallationService/res/values/strings.xml
index a72e4e2..2a66db1 100644
--- a/packages/DynamicSystemInstallationService/res/values/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values/strings.xml
@@ -13,11 +13,11 @@
     <string name="keyguard_description">Please enter your password and continue to AndroidOnTap installation</string>
 
     <!-- Displayed on notification: AndroidOnTap installation is completed [CHAR LIMIT=128] -->
-    <string name="notification_install_completed">New system is ready, you can reboot into it or discard it.</string>
+    <string name="notification_install_completed">System update is ready. To finish installing, restart your device.</string>
     <!-- Displayed on notification: AndroidOnTap installation is in progress [CHAR LIMIT=128] -->
-    <string name="notification_install_inprogress">Installation is in progress.</string>
+    <string name="notification_install_inprogress">Install in progress</string>
     <!-- Displayed on notification: AndroidOnTap installation is in progress [CHAR LIMIT=128] -->
-    <string name="notification_install_failed">Installation Failed.</string>
+    <string name="notification_install_failed">Install Failed</string>
     <!-- Displayed on notification: We are running in AndroidOnTap [CHAR LIMIT=128] -->
     <string name="notification_dynsystem_in_use">We are running in AndroidOnTap.</string>
 
@@ -27,12 +27,12 @@
     <string name="notification_action_discard">Discard</string>
     <!-- Action on notification: Uninstall AndroidOnTap [CHAR LIMIT=16] -->
     <string name="notification_action_uninstall">Uninstall</string>
-    <!-- Action on notification: Reboot to AndroidOnTap [CHAR LIMIT=16] -->
-    <string name="notification_action_reboot_to_dynsystem">Reboot</string>
+    <!-- Action on notification: Restart to AndroidOnTap [CHAR LIMIT=16] -->
+    <string name="notification_action_reboot_to_dynsystem">Restart</string>
 
     <!-- Toast when installed AndroidOnTap is discarded [CHAR LIMIT=64] -->
     <string name="toast_dynsystem_discarded">Installed AndroidOnTap is discarded.</string>
     <!-- Toast when we fail to launch into AndroidOnTap [CHAR LIMIT=64] -->
-    <string name="toast_failed_to_reboot_to_dynsystem">Failed to reboot into AndroidOnTap.</string>
+    <string name="toast_failed_to_reboot_to_dynsystem">Failed to restart to AndroidOnTap.</string>
 
 </resources>
diff --git a/packages/DynamicSystemInstallationService/src/com/android/dynandroid/DynamicSystemInstallationService.java b/packages/DynamicSystemInstallationService/src/com/android/dynandroid/DynamicSystemInstallationService.java
index 5c6885a..fcbda1d 100644
--- a/packages/DynamicSystemInstallationService/src/com/android/dynandroid/DynamicSystemInstallationService.java
+++ b/packages/DynamicSystemInstallationService/src/com/android/dynandroid/DynamicSystemInstallationService.java
@@ -380,13 +380,13 @@
                 builder.setContentText(getString(R.string.notification_install_completed));
 
                 builder.addAction(new Notification.Action.Builder(
-                        null, getString(R.string.notification_action_reboot_to_dynsystem),
-                        createPendingIntent(ACTION_REBOOT_TO_DYN_SYSTEM)).build());
-
-                builder.addAction(new Notification.Action.Builder(
                         null, getString(R.string.notification_action_discard),
                         createPendingIntent(ACTION_DISCARD_INSTALL)).build());
 
+                builder.addAction(new Notification.Action.Builder(
+                        null, getString(R.string.notification_action_reboot_to_dynsystem),
+                        createPendingIntent(ACTION_REBOOT_TO_DYN_SYSTEM)).build());
+
                 break;
 
             case STATUS_IN_USE:
diff --git a/packages/ExtServices/AndroidManifest.xml b/packages/ExtServices/AndroidManifest.xml
index 45a59a3..73bfd30 100644
--- a/packages/ExtServices/AndroidManifest.xml
+++ b/packages/ExtServices/AndroidManifest.xml
@@ -17,7 +17,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
     package="android.ext.services"
-    android:versionCode="200000000"
+    android:versionCode="210000000"
     android:versionName="1"
     coreApp="true">
 
diff --git a/packages/NetworkStack/AndroidManifest.xml b/packages/NetworkStack/AndroidManifest.xml
index b4588e0..ac05c44 100644
--- a/packages/NetworkStack/AndroidManifest.xml
+++ b/packages/NetworkStack/AndroidManifest.xml
@@ -19,7 +19,7 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
   package="com.android.networkstack"
   android:sharedUserId="android.uid.networkstack"
-  android:versionCode="200000000"
+  android:versionCode="210000000"
   android:versionName="29 system image"
 >
 
diff --git a/packages/NetworkStack/src/android/net/ip/IpClient.java b/packages/NetworkStack/src/android/net/ip/IpClient.java
index c1f178a..80d139c 100644
--- a/packages/NetworkStack/src/android/net/ip/IpClient.java
+++ b/packages/NetworkStack/src/android/net/ip/IpClient.java
@@ -51,6 +51,7 @@
 import android.text.TextUtils;
 import android.util.LocalLog;
 import android.util.Log;
+import android.util.Pair;
 import android.util.SparseArray;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -298,6 +299,7 @@
     private static final int EVENT_READ_PACKET_FILTER_COMPLETE    = 12;
     private static final int CMD_ADD_KEEPALIVE_PACKET_FILTER_TO_APF = 13;
     private static final int CMD_REMOVE_KEEPALIVE_PACKET_FILTER_FROM_APF = 14;
+    private static final int CMD_UPDATE_L2KEY_GROUPHINT = 15;
 
     // Internal commands to use instead of trying to call transitionTo() inside
     // a given State's enter() method. Calling transitionTo() from enter/exit
@@ -364,6 +366,8 @@
     private String mTcpBufferSizes;
     private ProxyInfo mHttpProxy;
     private ApfFilter mApfFilter;
+    private String mL2Key; // The L2 key for this network, for writing into the memory store
+    private String mGroupHint; // The group hint for this network, for writing into the memory store
     private boolean mMulticastFiltering;
     private long mStartTimeMillis;
 
@@ -524,6 +528,11 @@
             IpClient.this.stop();
         }
         @Override
+        public void setL2KeyAndGroupHint(String l2Key, String groupHint) {
+            checkNetworkStackCallingPermission();
+            IpClient.this.setL2KeyAndGroupHint(l2Key, groupHint);
+        }
+        @Override
         public void setTcpBufferSizes(String tcpBufferSizes) {
             checkNetworkStackCallingPermission();
             IpClient.this.setTcpBufferSizes(tcpBufferSizes);
@@ -652,6 +661,13 @@
     }
 
     /**
+     * Set the L2 key and group hint for storing info into the memory store.
+     */
+    public void setL2KeyAndGroupHint(String l2Key, String groupHint) {
+        sendMessage(CMD_UPDATE_L2KEY_GROUPHINT, new Pair<>(l2Key, groupHint));
+    }
+
+    /**
      * Set the HTTP Proxy configuration to use.
      *
      * This may be called, repeatedly, at any time before or after a call to
@@ -1068,6 +1084,10 @@
             return true;
         }
         final int delta = setLinkProperties(newLp);
+        // Most of the attributes stored in the memory store are deduced from
+        // the link properties, therefore when the properties update the memory
+        // store record should be updated too.
+        maybeSaveNetworkToIpMemoryStore();
         if (sendCallbacks) {
             dispatchCallback(delta, newLp);
         }
@@ -1083,6 +1103,7 @@
             Log.d(mTag, "onNewDhcpResults(" + Objects.toString(dhcpResults) + ")");
         }
         mCallback.onNewDhcpResults(dhcpResults);
+        maybeSaveNetworkToIpMemoryStore();
         dispatchCallback(delta, newLp);
     }
 
@@ -1213,6 +1234,10 @@
         mInterfaceCtrl.clearAllAddresses();
     }
 
+    private void maybeSaveNetworkToIpMemoryStore() {
+        // TODO : implement this
+    }
+
     class StoppedState extends State {
         @Override
         public void enter() {
@@ -1258,6 +1283,13 @@
                     handleLinkPropertiesUpdate(NO_CALLBACKS);
                     break;
 
+                case CMD_UPDATE_L2KEY_GROUPHINT: {
+                    final Pair<String, String> args = (Pair<String, String>) msg.obj;
+                    mL2Key = args.first;
+                    mGroupHint = args.second;
+                    break;
+                }
+
                 case CMD_SET_MULTICAST_FILTER:
                     mMulticastFiltering = (boolean) msg.obj;
                     break;
@@ -1357,6 +1389,20 @@
                     }
                     break;
 
+                case CMD_UPDATE_L2KEY_GROUPHINT: {
+                    final Pair<String, String> args = (Pair<String, String>) msg.obj;
+                    mL2Key = args.first;
+                    mGroupHint = args.second;
+                    // TODO : attributes should be saved to the memory store with
+                    // these new values if they differ from the previous ones.
+                    // If the state machine is in pure StartedState, then the values to input
+                    // are not known yet and should be updated when the LinkProperties are updated.
+                    // If the state machine is in RunningState (which is a child of StartedState)
+                    // then the next NUD check should be used to store the new values to avoid
+                    // inputting current values for what may be a different L3 network.
+                    break;
+                }
+
                 case EVENT_PROVISIONING_TIMEOUT:
                     handleProvisioningFailure();
                     break;
diff --git a/packages/NetworkStack/src/android/net/util/DataStallUtils.java b/packages/NetworkStack/src/android/net/util/DataStallUtils.java
new file mode 100644
index 0000000..b6dbeb1
--- /dev/null
+++ b/packages/NetworkStack/src/android/net/util/DataStallUtils.java
@@ -0,0 +1,72 @@
+/*
+ * 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 android.net.util;
+
+/**
+ * Collection of utilities for data stall.
+ */
+public class DataStallUtils {
+    /**
+     * Detect data stall via using dns timeout counts.
+     */
+    public static final int DATA_STALL_EVALUATION_TYPE_DNS = 1;
+    // Default configuration values for data stall detection.
+    public static final int DEFAULT_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD = 5;
+    public static final int DEFAULT_DATA_STALL_MIN_EVALUATE_TIME_MS = 60 * 1000;
+    public static final int DEFAULT_DATA_STALL_VALID_DNS_TIME_THRESHOLD_MS = 30 * 60 * 1000;
+    /**
+     * The threshold value for the number of consecutive dns timeout events received to be a
+     * signal of data stall. The number of consecutive timeouts needs to be {@code >=} this
+     * threshold to be considered a data stall. Set the value to {@code <= 0} to disable. Note
+     * that the value should be {@code > 0} if the DNS data stall detection is enabled.
+     *
+     */
+    public static final String CONFIG_DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD =
+            "data_stall_consecutive_dns_timeout_threshold";
+
+    /**
+     * The minimal time interval in milliseconds for data stall reevaluation.
+     *
+     */
+    public static final String CONFIG_DATA_STALL_MIN_EVALUATE_INTERVAL =
+            "data_stall_min_evaluate_interval";
+
+    /**
+     * DNS timeouts older than this timeout (in milliseconds) are not considered for detecting
+     * a data stall.
+     *
+     */
+    public static final String CONFIG_DATA_STALL_VALID_DNS_TIME_THRESHOLD =
+            "data_stall_valid_dns_time_threshold";
+
+    /**
+     * Which data stall detection signal to use. This is a bitmask constructed by bitwise-or-ing
+     * (i.e. {@code |}) the DATA_STALL_EVALUATION_TYPE_* values.
+     *
+     * Type: int
+     * Valid values:
+     *   {@link #DATA_STALL_EVALUATION_TYPE_DNS} : Use dns as a signal.
+     */
+    public static final String CONFIG_DATA_STALL_EVALUATION_TYPE = "data_stall_evaluation_type";
+    public static final int DEFAULT_DATA_STALL_EVALUATION_TYPES = DATA_STALL_EVALUATION_TYPE_DNS;
+    // The default number of DNS events kept of the log kept for dns signal evaluation. Each event
+    // is represented by a {@link com.android.server.connectivity.NetworkMonitor#DnsResult} objects.
+    // It's also the size of array of {@link com.android.server.connectivity.nano.DnsEvent} kept in
+    // metrics. Note that increasing the size may cause statsd log buffer bust. Need to check the
+    // design in statsd when you try to increase the size.
+    public static final int DEFAULT_DNS_LOG_SIZE = 20;
+}
diff --git a/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java b/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java
index dada61c..e7a607b 100644
--- a/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java
+++ b/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java
@@ -32,6 +32,9 @@
  * Collection of utilities for the network stack.
  */
 public class NetworkStackUtils {
+    // TODO: Refer to DeviceConfig definition.
+    public static final String NAMESPACE_CONNECTIVITY = "connectivity";
+
     static {
         System.loadLibrary("networkstackutilsjni");
     }
@@ -104,6 +107,24 @@
     }
 
     /**
+     * Look up the value of a property for a particular namespace from {@link DeviceConfig}.
+     * @param namespace The namespace containing the property to look up.
+     * @param name The name of the property to look up.
+     * @param defaultValue The value to return if the property does not exist or has no non-null
+     *                     value.
+     * @return the corresponding value, or defaultValue if none exists.
+     */
+    public static int getDeviceConfigPropertyInt(@NonNull String namespace, @NonNull String name,
+            int defaultValue) {
+        String value = getDeviceConfigProperty(namespace, name, null /* defaultValue */);
+        try {
+            return (value != null) ? Integer.parseInt(value) : defaultValue;
+        } catch (NumberFormatException e) {
+            return defaultValue;
+        }
+    }
+
+    /**
      * Attaches a socket filter that accepts DHCP packets to the given socket.
      */
     public static native void attachDhcpFilter(FileDescriptor fd) throws SocketException;
diff --git a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
index 8fbbccb..7b77d66 100644
--- a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
+++ b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
@@ -32,8 +32,18 @@
 import static android.net.metrics.ValidationProbeEvent.DNS_SUCCESS;
 import static android.net.metrics.ValidationProbeEvent.PROBE_FALLBACK;
 import static android.net.metrics.ValidationProbeEvent.PROBE_PRIVDNS;
+import static android.net.util.DataStallUtils.CONFIG_DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD;
+import static android.net.util.DataStallUtils.CONFIG_DATA_STALL_EVALUATION_TYPE;
+import static android.net.util.DataStallUtils.CONFIG_DATA_STALL_MIN_EVALUATE_INTERVAL;
+import static android.net.util.DataStallUtils.CONFIG_DATA_STALL_VALID_DNS_TIME_THRESHOLD;
+import static android.net.util.DataStallUtils.DATA_STALL_EVALUATION_TYPE_DNS;
+import static android.net.util.DataStallUtils.DEFAULT_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD;
+import static android.net.util.DataStallUtils.DEFAULT_DATA_STALL_EVALUATION_TYPES;
+import static android.net.util.DataStallUtils.DEFAULT_DATA_STALL_MIN_EVALUATE_TIME_MS;
+import static android.net.util.DataStallUtils.DEFAULT_DATA_STALL_VALID_DNS_TIME_THRESHOLD_MS;
+import static android.net.util.DataStallUtils.DEFAULT_DNS_LOG_SIZE;
+import static android.net.util.NetworkStackUtils.NAMESPACE_CONNECTIVITY;
 import static android.net.util.NetworkStackUtils.isEmpty;
-import static android.provider.Settings.Global.DATA_STALL_EVALUATION_TYPE_DNS;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -60,6 +70,7 @@
 import android.net.metrics.ValidationProbeEvent;
 import android.net.shared.NetworkMonitorUtils;
 import android.net.shared.PrivateDnsConfig;
+import android.net.util.NetworkStackUtils;
 import android.net.util.SharedLog;
 import android.net.util.Stopwatch;
 import android.net.wifi.WifiInfo;
@@ -126,18 +137,6 @@
 
     private static final int SOCKET_TIMEOUT_MS = 10000;
     private static final int PROBE_TIMEOUT_MS  = 3000;
-
-    // Default configuration values for data stall detection.
-    private static final int DEFAULT_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD = 5;
-    private static final int DEFAULT_DATA_STALL_MIN_EVALUATE_TIME_MS = 60 * 1000;
-    private static final int DEFAULT_DATA_STALL_VALID_DNS_TIME_THRESHOLD_MS = 30 * 60 * 1000;
-
-    private static final int DEFAULT_DATA_STALL_EVALUATION_TYPES =
-            DATA_STALL_EVALUATION_TYPE_DNS;
-    // Reevaluate it as intending to increase the number. Larger log size may cause statsd
-    // log buffer bust and have stats log lost.
-    private static final int DEFAULT_DNS_LOG_SIZE = 20;
-
     enum EvaluationResult {
         VALIDATED(true),
         CAPTIVE_PORTAL(false);
@@ -388,7 +387,7 @@
         mDnsStallDetector = new DnsStallDetector(mConsecutiveDnsTimeoutThreshold);
         mDataStallMinEvaluateTime = getDataStallMinEvaluateTime();
         mDataStallValidDnsTimeThreshold = getDataStallValidDnsTimeThreshold();
-        mDataStallEvaluationType = getDataStallEvalutionType();
+        mDataStallEvaluationType = getDataStallEvaluationType();
 
         // Provide empty LinkProperties and NetworkCapabilities to make sure they are never null,
         // even before notifyNetworkConnected.
@@ -1184,25 +1183,26 @@
     }
 
     private int getConsecutiveDnsTimeoutThreshold() {
-        return mDependencies.getSetting(mContext,
-                Settings.Global.DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD,
+        return mDependencies.getDeviceConfigPropertyInt(NAMESPACE_CONNECTIVITY,
+                CONFIG_DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD,
                 DEFAULT_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD);
     }
 
     private int getDataStallMinEvaluateTime() {
-        return mDependencies.getSetting(mContext,
-                Settings.Global.DATA_STALL_MIN_EVALUATE_INTERVAL,
+        return mDependencies.getDeviceConfigPropertyInt(NAMESPACE_CONNECTIVITY,
+                CONFIG_DATA_STALL_MIN_EVALUATE_INTERVAL,
                 DEFAULT_DATA_STALL_MIN_EVALUATE_TIME_MS);
     }
 
     private int getDataStallValidDnsTimeThreshold() {
-        return mDependencies.getSetting(mContext,
-                Settings.Global.DATA_STALL_VALID_DNS_TIME_THRESHOLD,
+        return mDependencies.getDeviceConfigPropertyInt(NAMESPACE_CONNECTIVITY,
+                CONFIG_DATA_STALL_VALID_DNS_TIME_THRESHOLD,
                 DEFAULT_DATA_STALL_VALID_DNS_TIME_THRESHOLD_MS);
     }
 
-    private int getDataStallEvalutionType() {
-        return mDependencies.getSetting(mContext, Settings.Global.DATA_STALL_EVALUATION_TYPE,
+    private int getDataStallEvaluationType() {
+        return mDependencies.getDeviceConfigPropertyInt(NAMESPACE_CONNECTIVITY,
+                CONFIG_DATA_STALL_EVALUATION_TYPE,
                 DEFAULT_DATA_STALL_EVALUATION_TYPES);
     }
 
@@ -1725,6 +1725,33 @@
             return value != null ? value : defaultValue;
         }
 
+        /**
+         * Look up the value of a property in DeviceConfig.
+         * @param namespace The namespace containing the property to look up.
+         * @param name The name of the property to look up.
+         * @param defaultValue The value to return if the property does not exist or has no non-null
+         *                     value.
+         * @return the corresponding value, or defaultValue if none exists.
+         */
+        @Nullable
+        public String getDeviceConfigProperty(@NonNull String namespace, @NonNull String name,
+                @Nullable String defaultValue) {
+            return NetworkStackUtils.getDeviceConfigProperty(namespace, name, defaultValue);
+        }
+
+        /**
+         * Look up the value of a property in DeviceConfig.
+         * @param namespace The namespace containing the property to look up.
+         * @param name The name of the property to look up.
+         * @param defaultValue The value to return if the property does not exist or has no non-null
+         *                     value.
+         * @return the corresponding value, or defaultValue if none exists.
+         */
+        public int getDeviceConfigPropertyInt(@NonNull String namespace, @NonNull String name,
+                int defaultValue) {
+            return NetworkStackUtils.getDeviceConfigPropertyInt(namespace, name, defaultValue);
+        }
+
         public static final Dependencies DEFAULT = new Dependencies();
     }
 
diff --git a/packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java b/packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java
index eee12d6..5f80006 100644
--- a/packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java
+++ b/packages/NetworkStack/tests/src/android/net/ip/IpClientTest.java
@@ -28,6 +28,7 @@
 import static org.mockito.Mockito.timeout;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
 import android.app.AlarmManager;
@@ -40,7 +41,9 @@
 import android.net.LinkAddress;
 import android.net.LinkProperties;
 import android.net.MacAddress;
+import android.net.NetworkStackIpMemoryStore;
 import android.net.RouteInfo;
+import android.net.ipmemorystore.NetworkAttributes;
 import android.net.shared.InitialConfiguration;
 import android.net.shared.ProvisioningConfiguration;
 import android.net.util.InterfaceParams;
@@ -81,6 +84,8 @@
     // See RFC 7042#section-2.1.2 for EUI-48 documentation values.
     private static final MacAddress TEST_MAC = MacAddress.fromString("00:00:5E:00:53:01");
     private static final int TEST_TIMEOUT_MS = 400;
+    private static final String TEST_L2KEY = "some l2key";
+    private static final String TEST_GROUPHINT = "some grouphint";
 
     @Mock private Context mContext;
     @Mock private ConnectivityManager mCm;
@@ -92,6 +97,7 @@
     @Mock private IpClient.Dependencies mDependencies;
     @Mock private ContentResolver mContentResolver;
     @Mock private NetworkStackService.NetworkStackServiceManager mNetworkStackServiceManager;
+    @Mock private NetworkStackIpMemoryStore mIpMemoryStore;
 
     private NetworkObserver mObserver;
     private InterfaceParams mIfParams;
@@ -141,6 +147,12 @@
         return empty;
     }
 
+    private void verifyNetworkAttributesStored(final String l2Key,
+            final NetworkAttributes attributes) {
+        // TODO : when storing is implemented, turn this on
+        // verify(mIpMemoryStore).storeNetworkAttributes(eq(l2Key), eq(attributes), any());
+    }
+
     @Test
     public void testNullInterfaceNameMostDefinitelyThrows() throws Exception {
         setTestInterfaceParams(null);
@@ -173,6 +185,7 @@
         setTestInterfaceParams(TEST_IFNAME);
         final IpClient ipc = new IpClient(mContext, TEST_IFNAME, mCb, mObserverRegistry,
                 mNetworkStackServiceManager, mDependencies);
+        verifyNoMoreInteractions(mIpMemoryStore);
         ipc.shutdown();
     }
 
@@ -183,6 +196,7 @@
                 mNetworkStackServiceManager, mDependencies);
         ipc.startProvisioning(new ProvisioningConfiguration());
         verify(mCb, times(1)).onProvisioningFailure(any());
+        verify(mIpMemoryStore, never()).storeNetworkAttributes(any(), any(), any());
         ipc.shutdown();
     }
 
@@ -202,6 +216,7 @@
         verify(mCb, times(1)).setNeighborDiscoveryOffload(true);
         verify(mCb, timeout(TEST_TIMEOUT_MS).times(1)).setFallbackMulticastFilter(false);
         verify(mCb, never()).onProvisioningFailure(any());
+        verify(mIpMemoryStore, never()).storeNetworkAttributes(any(), any(), any());
 
         ipc.shutdown();
         verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceSetEnableIPv6(iface, false);
@@ -214,6 +229,8 @@
     public void testProvisioningWithInitialConfiguration() throws Exception {
         final String iface = TEST_IFNAME;
         final IpClient ipc = makeIpClient(iface);
+        final String l2Key = TEST_L2KEY;
+        final String groupHint = TEST_GROUPHINT;
 
         String[] addresses = {
             "fe80::a4be:f92:e1f7:22d1/64",
@@ -232,6 +249,7 @@
         verify(mCb, times(1)).setNeighborDiscoveryOffload(true);
         verify(mCb, timeout(TEST_TIMEOUT_MS).times(1)).setFallbackMulticastFilter(false);
         verify(mCb, never()).onProvisioningFailure(any());
+        ipc.setL2KeyAndGroupHint(l2Key, groupHint);
 
         for (String addr : addresses) {
             String[] parts = addr.split("/");
@@ -253,12 +271,16 @@
         LinkProperties want = linkproperties(links(addresses), routes(prefixes));
         want.setInterfaceName(iface);
         verify(mCb, timeout(TEST_TIMEOUT_MS).times(1)).onProvisioningSuccess(want);
+        verifyNetworkAttributesStored(l2Key, new NetworkAttributes.Builder()
+                .setGroupHint(groupHint)
+                .build());
 
         ipc.shutdown();
         verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceSetEnableIPv6(iface, false);
         verify(mNetd, timeout(TEST_TIMEOUT_MS).times(1)).interfaceClearAddrs(iface);
         verify(mCb, timeout(TEST_TIMEOUT_MS).times(1))
                 .onLinkPropertiesChange(makeEmptyLinkProperties(iface));
+        verifyNoMoreInteractions(mIpMemoryStore);
     }
 
     @Test
diff --git a/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java b/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java
index 6665aae..9f6c7f8 100644
--- a/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java
+++ b/packages/NetworkStack/tests/src/com/android/server/connectivity/NetworkMonitorTest.java
@@ -21,7 +21,11 @@
 import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_PARTIAL_CONNECTIVITY;
 import static android.net.INetworkMonitor.NETWORK_TEST_RESULT_VALID;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
-import static android.provider.Settings.Global.DATA_STALL_EVALUATION_TYPE_DNS;
+import static android.net.util.DataStallUtils.CONFIG_DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD;
+import static android.net.util.DataStallUtils.CONFIG_DATA_STALL_EVALUATION_TYPE;
+import static android.net.util.DataStallUtils.CONFIG_DATA_STALL_MIN_EVALUATE_INTERVAL;
+import static android.net.util.DataStallUtils.CONFIG_DATA_STALL_VALID_DNS_TIME_THRESHOLD;
+import static android.net.util.DataStallUtils.DATA_STALL_EVALUATION_TYPE_DNS;
 
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
@@ -114,7 +118,6 @@
     private @Captor ArgumentCaptor<String> mNetworkTestedRedirectUrlCaptor;
 
     private static final int TEST_NETID = 4242;
-
     private static final String TEST_HTTP_URL = "http://www.google.com/gen_204";
     private static final String TEST_HTTPS_URL = "https://www.google.com/gen_204";
     private static final String TEST_FALLBACK_URL = "http://fallback.google.com/gen_204";
@@ -593,24 +596,23 @@
     }
 
     private void setDataStallEvaluationType(int type) {
-        when(mDependencies.getSetting(any(),
-            eq(Settings.Global.DATA_STALL_EVALUATION_TYPE), anyInt())).thenReturn(type);
+        when(mDependencies.getDeviceConfigPropertyInt(any(),
+            eq(CONFIG_DATA_STALL_EVALUATION_TYPE), anyInt())).thenReturn(type);
     }
 
     private void setMinDataStallEvaluateInterval(int time) {
-        when(mDependencies.getSetting(any(),
-            eq(Settings.Global.DATA_STALL_MIN_EVALUATE_INTERVAL), anyInt())).thenReturn(time);
+        when(mDependencies.getDeviceConfigPropertyInt(any(),
+            eq(CONFIG_DATA_STALL_MIN_EVALUATE_INTERVAL), anyInt())).thenReturn(time);
     }
 
     private void setValidDataStallDnsTimeThreshold(int time) {
-        when(mDependencies.getSetting(any(),
-            eq(Settings.Global.DATA_STALL_VALID_DNS_TIME_THRESHOLD), anyInt())).thenReturn(time);
+        when(mDependencies.getDeviceConfigPropertyInt(any(),
+            eq(CONFIG_DATA_STALL_VALID_DNS_TIME_THRESHOLD), anyInt())).thenReturn(time);
     }
 
     private void setConsecutiveDnsTimeoutThreshold(int num) {
-        when(mDependencies.getSetting(any(),
-            eq(Settings.Global.DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD), anyInt()))
-            .thenReturn(num);
+        when(mDependencies.getDeviceConfigPropertyInt(any(),
+            eq(CONFIG_DATA_STALL_CONSECUTIVE_DNS_TIMEOUT_THRESHOLD), anyInt())).thenReturn(num);
     }
 
     private void setFallbackUrl(String url) {
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
index bde1b25..55ff591 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
@@ -43,7 +43,6 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.Process;
-import android.os.RemoteException;
 import android.os.UserManager;
 import android.provider.Settings;
 import android.util.Log;
@@ -472,16 +471,6 @@
                 mOriginatingUid, mOriginatingPackage);
         switch (appOpMode) {
             case AppOpsManager.MODE_DEFAULT:
-                try {
-                    int result = mIpm.checkUidPermission(
-                            Manifest.permission.REQUEST_INSTALL_PACKAGES, mOriginatingUid);
-                    if (result == PackageManager.PERMISSION_GRANTED) {
-                        initiateInstall();
-                        break;
-                    }
-                } catch (RemoteException exc) {
-                    Log.e(TAG, "Unable to talk to package manager");
-                }
                 mAppOpsManager.setMode(appOpCode, mOriginatingUid,
                         mOriginatingPackage, AppOpsManager.MODE_ERRORED);
                 // fall through
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/location/SettingsInjector.java b/packages/SettingsLib/src/com/android/settingslib/location/SettingsInjector.java
index 74057be..ff40d8e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/location/SettingsInjector.java
+++ b/packages/SettingsLib/src/com/android/settingslib/location/SettingsInjector.java
@@ -20,14 +20,12 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageItemInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
-import android.graphics.drawable.Drawable;
 import android.location.SettingInjectorService;
 import android.os.Bundle;
 import android.os.Handler;
@@ -37,9 +35,9 @@
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.AttributeSet;
-import android.util.IconDrawableFactory;
 import android.util.Log;
 import android.util.Xml;
 
@@ -56,8 +54,8 @@
 import java.util.ArrayList;
 import java.util.Deque;
 import java.util.HashSet;
-import java.util.Iterator;
 import java.util.List;
+import java.util.Map;
 import java.util.Set;
 
 /**
@@ -157,22 +155,8 @@
      * Adds the InjectedSetting information to a Preference object
      */
     private void populatePreference(Preference preference, InjectedSetting setting) {
-        final PackageManager pm = mContext.getPackageManager();
-        Drawable appIcon = null;
-        try {
-            final PackageItemInfo itemInfo = new PackageItemInfo();
-            itemInfo.icon = setting.iconId;
-            itemInfo.packageName = setting.packageName;
-            final ApplicationInfo appInfo = pm.getApplicationInfo(setting.packageName,
-                    PackageManager.GET_META_DATA);
-            appIcon = IconDrawableFactory.newInstance(mContext)
-                    .getBadgedIcon(itemInfo, appInfo, setting.mUserHandle.getIdentifier());
-        } catch (PackageManager.NameNotFoundException e) {
-            Log.e(TAG, "Can't get ApplicationInfo for " + setting.packageName, e);
-        }
         preference.setTitle(setting.title);
         preference.setSummary(R.string.loading_injected_setting_summary);
-        preference.setIcon(appIcon);
         preference.setOnPreferenceClickListener(new ServiceSettingClickedListener(setting));
     }
 
@@ -182,13 +166,15 @@
      * @param profileId Identifier of the user/profile to obtain the injected settings for or
      *                  UserHandle.USER_CURRENT for all profiles associated with current user.
      */
-    public List<Preference> getInjectedSettings(Context prefContext, final int profileId) {
+    public Map<Integer, List<Preference>> getInjectedSettings(Context prefContext,
+            final int profileId) {
         final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
         final List<UserHandle> profiles = um.getUserProfiles();
-        ArrayList<Preference> prefs = new ArrayList<>();
+        final ArrayMap<Integer, List<Preference>> result = new ArrayMap<>();
         mSettings.clear();
         for (UserHandle userHandle : profiles) {
             if (profileId == UserHandle.USER_CURRENT || profileId == userHandle.getIdentifier()) {
+                final List<Preference> prefs = new ArrayList<>();
                 Iterable<InjectedSetting> settings = getSettings(userHandle);
                 for (InjectedSetting setting : settings) {
                     Preference preference = createPreference(prefContext, setting);
@@ -196,12 +182,14 @@
                     prefs.add(preference);
                     mSettings.add(new Setting(setting, preference));
                 }
+                if (!prefs.isEmpty()) {
+                    result.put(userHandle.getIdentifier(), prefs);
+                }
             }
         }
 
         reloadStatusMessages();
-
-        return prefs;
+        return result;
     }
 
     /**
@@ -303,28 +291,6 @@
     }
 
     /**
-     * Checks wheteher there is any preference that other apps have injected.
-     *
-     * @param profileId Identifier of the user/profile to obtain the injected settings for or
-     *                  UserHandle.USER_CURRENT for all profiles associated with current user.
-     */
-    public boolean hasInjectedSettings(final int profileId) {
-        final UserManager um = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
-        final List<UserHandle> profiles = um.getUserProfiles();
-        final int profileCount = profiles.size();
-        for (int i = 0; i < profileCount; ++i) {
-            final UserHandle userHandle = profiles.get(i);
-            if (profileId == UserHandle.USER_CURRENT || profileId == userHandle.getIdentifier()) {
-                Iterable<InjectedSetting> settings = getSettings(userHandle);
-                for (InjectedSetting setting : settings) {
-                    return true;
-                }
-            }
-        }
-        return false;
-    }
-
-    /**
      * Reloads the status messages for all the preference items.
      */
     public void reloadStatusMessages() {
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/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index d1b7c75..314b74a 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -154,6 +154,7 @@
     <uses-permission android:name="android.permission.STATUS_BAR_SERVICE" />
     <!-- Permission needed to rename bugreport notifications (so they're not shown as Shell) -->
     <uses-permission android:name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME" />
+    <uses-permission android:name="android.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE" />
     <!-- Permission needed to hold a wakelock in dumpstate.cpp (drop_root_user()) -->
     <uses-permission android:name="android.permission.WAKE_LOCK" />
     <!-- Permission needed to enable/disable overlays -->
@@ -194,6 +195,9 @@
     <uses-permission android:name="android.permission.SET_WALLPAPER" />
     <uses-permission android:name="android.permission.SET_WALLPAPER_COMPONENT" />
 
+    <!-- Permission required to test ContentResolver caching. -->
+    <uses-permission android:name="android.permission.CACHE_CONTENT" />
+
     <application android:label="@string/app_label"
                  android:defaultToDeviceProtectedStorage="true"
                  android:directBootAware="true">
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
index 42600c1..834f4fc 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/qs/QSTile.java
@@ -117,6 +117,7 @@
         public String expandedAccessibilityClassName;
         public SlashState slash;
         public boolean handlesLongClick = true;
+        public boolean showRippleEffect = true;
 
         public boolean copyTo(State other) {
             if (other == null) throw new IllegalArgumentException();
@@ -135,7 +136,8 @@
                     || !Objects.equals(other.isTransient, isTransient)
                     || !Objects.equals(other.dualTarget, dualTarget)
                     || !Objects.equals(other.slash, slash)
-                    || !Objects.equals(other.handlesLongClick, handlesLongClick);
+                    || !Objects.equals(other.handlesLongClick, handlesLongClick)
+                    || !Objects.equals(other.showRippleEffect, showRippleEffect);
             other.icon = icon;
             other.iconSupplier = iconSupplier;
             other.label = label;
@@ -149,6 +151,7 @@
             other.isTransient = isTransient;
             other.slash = slash != null ? slash.copy() : null;
             other.handlesLongClick = handlesLongClick;
+            other.showRippleEffect = showRippleEffect;
             return changed;
         }
 
diff --git a/packages/SystemUI/res/drawable/ic_5g_e_mobiledata.xml b/packages/SystemUI/res/drawable/ic_5g_e_mobiledata.xml
new file mode 100644
index 0000000..fe1bb26
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_5g_e_mobiledata.xml
@@ -0,0 +1,31 @@
+<!--
+     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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:viewportWidth="22"
+    android:viewportHeight="17"
+    android:width="22dp"
+    android:height="17dp">
+  <path
+      android:fillColor="#FFFFFFFF"
+      android:pathData="M1.22,8.49l0.43-4.96h4.33v1.17H2.67L2.44,7.41c0.41-0.29,0.85-0.43,1.33-0.43c0.77,0,1.38,0.3,1.83,0.9 s0.66,1.41,0.66,2.43c0,1.03-0.24,1.84-0.72,2.43s-1.14,0.88-1.98,0.88c-0.75,0-1.36-0.24-1.83-0.73s-0.74-1.16-0.81-2.02h1.13 c0.07,0.57,0.23,1,0.49,1.29c0.26,0.29,0.59,0.43,1.01,0.43c0.47,0,0.84-0.2,1.1-0.61c0.26-0.41,0.4-0.96,0.4-1.65 c0-0.65-0.14-1.18-0.43-1.59S3.96,8.11,3.47,8.11c-0.4,0-0.72,0.1-0.96,0.31L2.19,8.75L1.22,8.49z" />
+  <path
+      android:fillColor="#FFFFFFFF"
+      android:pathData="M14.14,12.24l-0.22,0.27c-0.63,0.73-1.55,1.1-2.76,1.1c-1.08,0-1.92-0.36-2.53-1.07c-0.61-0.71-0.93-1.72-0.94-3.02V7.56 c0-1.39,0.28-2.44,0.84-3.13c0.56-0.7,1.39-1.04,2.51-1.04c0.95,0,1.69,0.26,2.23,0.79c0.54,0.53,0.83,1.28,0.89,2.26h-1.25 c-0.05-0.62-0.22-1.1-0.52-1.45c-0.29-0.35-0.74-0.52-1.34-0.52c-0.72,0-1.24,0.23-1.57,0.7C9.14,5.63,8.96,6.37,8.95,7.4v2.03 c0,1,0.19,1.77,0.57,2.31c0.38,0.54,0.93,0.8,1.65,0.8c0.67,0,1.19-0.16,1.54-0.49l0.18-0.17V9.59h-1.82V8.52h3.07V12.24z" />
+  <path
+      android:fillColor="#FFFFFFFF"
+      android:pathData="M20.96,8.88h-3.52v3.53h4.1v1.07h-5.35V3.52h5.28V4.6h-4.03V7.8h3.52V8.88z" />
+
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_sysbar_back.xml b/packages/SystemUI/res/drawable/ic_sysbar_back.xml
index 1448843..ee40262 100644
--- a/packages/SystemUI/res/drawable/ic_sysbar_back.xml
+++ b/packages/SystemUI/res/drawable/ic_sysbar_back.xml
@@ -17,6 +17,7 @@
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:width="28dp"
     android:height="28dp"
+    android:autoMirrored="true"
     android:viewportWidth="28"
     android:viewportHeight="28">
 
diff --git a/packages/SystemUI/res/drawable/ic_sysbar_back_quick_step.xml b/packages/SystemUI/res/drawable/ic_sysbar_back_quick_step.xml
index 93b2f9c8..442fafc 100644
--- a/packages/SystemUI/res/drawable/ic_sysbar_back_quick_step.xml
+++ b/packages/SystemUI/res/drawable/ic_sysbar_back_quick_step.xml
@@ -17,6 +17,7 @@
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:width="28dp"
     android:height="28dp"
+    android:autoMirrored="true"
     android:viewportWidth="28"
     android:viewportHeight="28">
     <path
diff --git a/packages/SystemUI/res/values-mcc310-mnc030/config.xml b/packages/SystemUI/res/values-mcc310-mnc030/config.xml
new file mode 100644
index 0000000..26b9192
--- /dev/null
+++ b/packages/SystemUI/res/values-mcc310-mnc030/config.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources>
+    <!-- Enable 5 bar signal strength icon -->
+    <bool name="config_inflateSignalStrength">true</bool>
+</resources>
+
diff --git a/packages/SystemUI/res/values-mcc310-mnc070/config.xml b/packages/SystemUI/res/values-mcc310-mnc070/config.xml
new file mode 100644
index 0000000..26b9192
--- /dev/null
+++ b/packages/SystemUI/res/values-mcc310-mnc070/config.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources>
+    <!-- Enable 5 bar signal strength icon -->
+    <bool name="config_inflateSignalStrength">true</bool>
+</resources>
+
diff --git a/packages/SystemUI/res/values-mcc310-mnc170/config.xml b/packages/SystemUI/res/values-mcc310-mnc170/config.xml
new file mode 100644
index 0000000..26b9192
--- /dev/null
+++ b/packages/SystemUI/res/values-mcc310-mnc170/config.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources>
+    <!-- Enable 5 bar signal strength icon -->
+    <bool name="config_inflateSignalStrength">true</bool>
+</resources>
+
diff --git a/packages/SystemUI/res/values-mcc310-mnc280/config.xml b/packages/SystemUI/res/values-mcc310-mnc280/config.xml
new file mode 100644
index 0000000..26b9192
--- /dev/null
+++ b/packages/SystemUI/res/values-mcc310-mnc280/config.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources>
+    <!-- Enable 5 bar signal strength icon -->
+    <bool name="config_inflateSignalStrength">true</bool>
+</resources>
+
diff --git a/packages/SystemUI/res/values-mcc310-mnc380/config.xml b/packages/SystemUI/res/values-mcc310-mnc380/config.xml
new file mode 100644
index 0000000..26b9192
--- /dev/null
+++ b/packages/SystemUI/res/values-mcc310-mnc380/config.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources>
+    <!-- Enable 5 bar signal strength icon -->
+    <bool name="config_inflateSignalStrength">true</bool>
+</resources>
+
diff --git a/packages/SystemUI/res/values-mcc310-mnc410/config.xml b/packages/SystemUI/res/values-mcc310-mnc410/config.xml
new file mode 100644
index 0000000..26b9192
--- /dev/null
+++ b/packages/SystemUI/res/values-mcc310-mnc410/config.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources>
+    <!-- Enable 5 bar signal strength icon -->
+    <bool name="config_inflateSignalStrength">true</bool>
+</resources>
+
diff --git a/packages/SystemUI/res/values-mcc310-mnc560/config.xml b/packages/SystemUI/res/values-mcc310-mnc560/config.xml
new file mode 100644
index 0000000..26b9192
--- /dev/null
+++ b/packages/SystemUI/res/values-mcc310-mnc560/config.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources>
+    <!-- Enable 5 bar signal strength icon -->
+    <bool name="config_inflateSignalStrength">true</bool>
+</resources>
+
diff --git a/packages/SystemUI/res/values-mcc310-mnc950/config.xml b/packages/SystemUI/res/values-mcc310-mnc950/config.xml
new file mode 100644
index 0000000..26b9192
--- /dev/null
+++ b/packages/SystemUI/res/values-mcc310-mnc950/config.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources>
+    <!-- Enable 5 bar signal strength icon -->
+    <bool name="config_inflateSignalStrength">true</bool>
+</resources>
+
diff --git a/packages/SystemUI/res/values-mcc311-mnc180/config.xml b/packages/SystemUI/res/values-mcc311-mnc180/config.xml
new file mode 100644
index 0000000..26b9192
--- /dev/null
+++ b/packages/SystemUI/res/values-mcc311-mnc180/config.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+     for different hardware and product builds. -->
+<resources>
+    <!-- Enable 5 bar signal strength icon -->
+    <bool name="config_inflateSignalStrength">true</bool>
+</resources>
+
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index f47d4b5..e098bc5 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -424,6 +424,9 @@
     <!-- Content description of the data connection type LTE+. [CHAR LIMIT=NONE] -->
     <string name="data_connection_lte_plus">LTE+</string>
 
+    <!-- Content description of the data connection type 5Ge. [CHAR LIMIT=NONE] -->
+    <string name="data_connection_5ge" translate="false">5Ge</string>
+
     <!-- Content description of the data connection type 5G. [CHAR LIMIT=NONE] -->
     <string name="data_connection_5g" translate="false">5G</string>
 
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/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
index 4fe09a9..665df77 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
@@ -26,16 +26,41 @@
  */
 class Bubble {
 
+    private final String mKey;
+    private final BubbleExpandedView.OnBubbleBlockedListener mListener;
+
+    private boolean mInflated;
+
     public BubbleView iconView;
     public BubbleExpandedView expandedView;
-    public String key;
     public NotificationEntry entry;
 
+    Bubble(NotificationEntry e, BubbleExpandedView.OnBubbleBlockedListener listener) {
+        entry = e;
+        mKey = e.key;
+        mListener = listener;
+    }
+
+    /** @deprecated use the other constructor to defer View creation. */
+    @Deprecated
     Bubble(NotificationEntry e, LayoutInflater inflater, BubbleStackView stackView,
             BubbleExpandedView.OnBubbleBlockedListener listener) {
-        entry = e;
-        key = entry.key;
+        this(e, listener);
+        inflate(inflater, stackView);
+    }
 
+    public String getKey() {
+        return mKey;
+    }
+
+    boolean isInflated() {
+        return mInflated;
+    }
+
+    void inflate(LayoutInflater inflater, BubbleStackView stackView) {
+        if (mInflated) {
+            return;
+        }
         iconView = (BubbleView) inflater.inflate(
                 R.layout.bubble_view, stackView, false /* attachToRoot */);
         iconView.setNotif(entry);
@@ -44,12 +69,14 @@
                 R.layout.bubble_expanded_view, stackView, false /* attachToRoot */);
         expandedView.setEntry(entry, stackView);
 
-        expandedView.setOnBlockedListener(listener);
+        expandedView.setOnBlockedListener(mListener);
+        mInflated = true;
     }
 
-    public void setEntry(NotificationEntry entry) {
-        key = entry.key;
-        iconView.update(entry);
-        expandedView.update(entry);
+    void setEntry(NotificationEntry entry) {
+        if (mInflated) {
+            iconView.update(entry);
+            expandedView.update(entry);
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index 5acf3c2..418d052 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -220,6 +220,26 @@
         mSurfaceSynchronizer = synchronizer;
     }
 
+    /**
+     * BubbleStackView is lazily created by this method the first time a Bubble is added. This
+     * method initializes the stack view and adds it to the StatusBar just above the scrim.
+     */
+    private void ensureStackViewCreated() {
+        if (mStackView == null) {
+            mStackView = new BubbleStackView(mContext, mBubbleData, mSurfaceSynchronizer);
+            ViewGroup sbv = mStatusBarWindowController.getStatusBarView();
+            // TODO(b/130237686): When you expand the shade on top of expanded bubble, there is no
+            //  scrim between bubble and the shade
+            int bubblePosition = sbv.indexOfChild(sbv.findViewById(R.id.scrim_behind)) + 1;
+            sbv.addView(mStackView, bubblePosition,
+                    new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
+            if (mExpandListener != null) {
+                mStackView.setExpandListener(mExpandListener);
+            }
+            mStackView.setOnBlockedListener(this);
+        }
+    }
+
     @Override
     public void onUiModeChanged() {
         if (mStackView != null) {
@@ -325,27 +345,15 @@
     /**
      * Adds or updates a bubble associated with the provided notification entry.
      *
-     * @param notif          the notification associated with this bubble.
+     * @param notif the notification associated with this bubble.
      */
     void updateBubble(NotificationEntry notif) {
         if (mStackView != null && mBubbleData.getBubble(notif.key) != null) {
             // It's an update
             mStackView.updateBubble(notif);
         } else {
-            if (mStackView == null) {
-                mStackView = new BubbleStackView(mContext, mBubbleData, mSurfaceSynchronizer);
-                ViewGroup sbv = mStatusBarWindowController.getStatusBarView();
-                // XXX: Bug when you expand the shade on top of expanded bubble, there is no scrim
-                // between bubble and the shade
-                int bubblePosition = sbv.indexOfChild(sbv.findViewById(R.id.scrim_behind)) + 1;
-                sbv.addView(mStackView, bubblePosition,
-                        new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
-                if (mExpandListener != null) {
-                    mStackView.setExpandListener(mExpandListener);
-                }
-                mStackView.setOnBlockedListener(this);
-            }
             // It's new
+            ensureStackViewCreated();
             mStackView.addBubble(notif);
         }
         if (shouldAutoExpand(notif)) {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
index cf70287..fe3f9d1 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
@@ -106,7 +106,7 @@
     }
 
     public void addBubble(Bubble b) {
-        mBubbles.put(b.key, b);
+        mBubbles.put(b.getKey(), b);
     }
 
     @Nullable
diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageProcessHelper.java b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageProcessHelper.java
index d1939d0..477e7d7e 100644
--- a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageProcessHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageProcessHelper.java
@@ -85,9 +85,7 @@
             Bitmap bitmap = bitmaps[0];
             if (bitmap != null) {
                 int[] histogram = processHistogram(bitmap);
-                Float val = computePercentile85(bitmap, histogram);
-                bitmaps[0] = null;
-                return val;
+                return computePercentile85(bitmap, histogram);
             }
             Log.e(TAG, "Per85ComputeTask: Can't get bitmap");
             return DEFAULT_PER85;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
index d40973b..a732a25 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileBaseView.java
@@ -40,7 +40,6 @@
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
-import android.widget.ImageView.ScaleType;
 import android.widget.Switch;
 
 import com.android.settingslib.Utils;
@@ -63,6 +62,7 @@
     private boolean mTileState;
     private boolean mCollapsedView;
     private boolean mClicked;
+    private boolean mShowRippleEffect = true;
 
     private final ImageView mBg;
     private final int mColorActive;
@@ -209,6 +209,7 @@
             mCircleColor = circleColor;
         }
 
+        mShowRippleEffect = state.showRippleEffect;
         setClickable(state.state != Tile.STATE_UNAVAILABLE);
         setLongClickable(state.handlesLongClick);
         mIcon.setIcon(state, allowAnimations);
@@ -254,7 +255,7 @@
     @Override
     public void setClickable(boolean clickable) {
         super.setClickable(clickable);
-        setBackground(clickable ? mRipple : null);
+        setBackground(clickable && mShowRippleEffect ? mRipple : null);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
index c664a20..d62f10d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
@@ -16,6 +16,7 @@
 package com.android.systemui.qs.tiles;
 
 import android.content.Intent;
+import android.provider.Settings.Secure;
 import android.service.quicksettings.Tile;
 import android.widget.Switch;
 
@@ -23,6 +24,7 @@
 import com.android.systemui.R;
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
 import com.android.systemui.qs.QSHost;
+import com.android.systemui.qs.SecureSetting;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 import com.android.systemui.statusbar.policy.BatteryController;
 
@@ -32,6 +34,7 @@
         BatteryController.BatteryStateChangeCallback {
 
     private final BatteryController mBatteryController;
+    private final SecureSetting mSetting;
 
     private int mLevel;
     private boolean mPowerSave;
@@ -45,6 +48,12 @@
         super(host);
         mBatteryController = batteryController;
         mBatteryController.observe(getLifecycle(), this);
+        mSetting = new SecureSetting(mContext, mHandler, Secure.LOW_POWER_WARNING_ACKNOWLEDGED) {
+            @Override
+            protected void handleValueChanged(int value, boolean observedChange) {
+                handleRefreshState(null);
+            }
+        };
     }
 
     @Override
@@ -53,12 +62,19 @@
     }
 
     @Override
+    protected void handleDestroy() {
+        super.handleDestroy();
+        mSetting.setListening(false);
+    }
+
+    @Override
     public int getMetricsCategory() {
         return MetricsEvent.QS_BATTERY_TILE;
     }
 
     @Override
     public void handleSetListening(boolean listening) {
+        mSetting.setListening(listening);
     }
 
     @Override
@@ -88,6 +104,7 @@
         state.contentDescription = state.label;
         state.value = mPowerSave;
         state.expandedAccessibilityClassName = Switch.class.getName();
+        state.showRippleEffect = mSetting.getValue() == 0;
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
index 34f3c60..33a2acf 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
@@ -64,6 +64,7 @@
 import com.android.systemui.R;
 import com.android.systemui.shared.recents.IOverviewProxy;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.QuickStepContract;
 import com.android.systemui.shared.system.TaskStackChangeListener;
 
 import java.io.PrintWriter;
@@ -339,7 +340,7 @@
     }
 
     public void onConnectedToLauncher() {
-        if (!ONBOARDING_ENABLED) {
+        if (!ONBOARDING_ENABLED || QuickStepContract.isGesturalMode(mContext)) {
             return;
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index a87e50c..3441591 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -83,7 +83,7 @@
 
     private final int mSlowThreshold;
     private final int mFastThreshold;
-    private LockIcon mLockIcon;
+    private final LockIcon mLockIcon;
     private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
 
     private String mRestingIndication;
@@ -539,7 +539,6 @@
 
     protected class BaseKeyguardCallback extends KeyguardUpdateMonitorCallback {
         public static final int HIDE_DELAY_MS = 5000;
-        private int mLastSuccessiveErrorMessage = -1;
 
         @Override
         public void onRefreshBatteryInfo(KeyguardUpdateMonitor.BatteryStatus status) {
@@ -577,20 +576,14 @@
             if (!updateMonitor.isUnlockingWithBiometricAllowed()) {
                 return;
             }
+            animatePadlockError();
             if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
                 mStatusBarKeyguardViewManager.showBouncerMessage(helpString,
                         mInitialTextColorState);
             } else if (updateMonitor.isScreenOn()) {
-                mLockIcon.setTransientBiometricsError(true);
                 showTransientIndication(helpString);
                 hideTransientIndicationDelayed(TRANSIENT_BIOMETRIC_ERROR_TIMEOUT);
-                mHandler.removeMessages(MSG_CLEAR_BIOMETRIC_MSG);
-                mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_CLEAR_BIOMETRIC_MSG),
-                        TRANSIENT_BIOMETRIC_ERROR_TIMEOUT);
             }
-            // Help messages indicate that there was actually a try since the last error, so those
-            // are not two successive error messages anymore.
-            mLastSuccessiveErrorMessage = -1;
         }
 
         @Override
@@ -600,15 +593,9 @@
             if (shouldSuppressBiometricError(msgId, biometricSourceType, updateMonitor)) {
                 return;
             }
+            animatePadlockError();
             if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
-                // When swiping up right after receiving a biometric error, the bouncer calls
-                // authenticate leading to the same message being shown again on the bouncer.
-                // We want to avoid this, as it may confuse the user when the message is too
-                // generic.
-                if (mLastSuccessiveErrorMessage != msgId) {
-                    mStatusBarKeyguardViewManager.showBouncerMessage(errString,
-                            mInitialTextColorState);
-                }
+                mStatusBarKeyguardViewManager.showBouncerMessage(errString, mInitialTextColorState);
             } else if (updateMonitor.isScreenOn()) {
                 showTransientIndication(errString);
                 // We want to keep this message around in case the screen was off
@@ -616,7 +603,13 @@
             } else {
                 mMessageToShowOnScreenOn = errString;
             }
-            mLastSuccessiveErrorMessage = msgId;
+        }
+
+        private void animatePadlockError() {
+            mLockIcon.setTransientBiometricsError(true);
+            mHandler.removeMessages(MSG_CLEAR_BIOMETRIC_MSG);
+            mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_CLEAR_BIOMETRIC_MSG),
+                    TRANSIENT_BIOMETRIC_ERROR_TIMEOUT);
         }
 
         private boolean shouldSuppressBiometricError(int msgId,
@@ -670,21 +663,19 @@
         @Override
         public void onBiometricAuthenticated(int userId, BiometricSourceType biometricSourceType) {
             super.onBiometricAuthenticated(userId, biometricSourceType);
-            mLastSuccessiveErrorMessage = -1;
             mHandler.sendEmptyMessage(MSG_HIDE_TRANSIENT);
         }
 
         @Override
-        public void onBiometricAuthFailed(BiometricSourceType biometricSourceType) {
-            super.onBiometricAuthFailed(biometricSourceType);
-            mLastSuccessiveErrorMessage = -1;
-        }
-
-        @Override
         public void onUserUnlocked() {
             if (mVisible) {
                 updateIndication(false);
             }
         }
+
+        @Override
+        public void onKeyguardBouncerChanged(boolean bouncer) {
+            mLockIcon.setBouncerVisible(bouncer);
+        }
     };
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index d11eab7..562e535 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -401,7 +401,11 @@
         @Override
         public void getOutline(View view, Outline outline) {
             if (mAmbientState.isDarkAtAll() || !mShowDarkShelf) {
-                outline.setRoundRect(mBackgroundAnimationRect, mCornerRadius);
+                float xProgress = mDarkXInterpolator.getInterpolation(
+                        (1 - mLinearDarkAmount) * mBackgroundXFactor);
+                outline.setRoundRect(mBackgroundAnimationRect,
+                        MathUtils.lerp(mCornerRadius / 2.0f, mCornerRadius,
+                                xProgress));
             } else {
                 ViewOutlineProvider.BACKGROUND.getOutline(view, outline);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
index 6ebd6b3..3cc4a7b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockIcon.java
@@ -57,8 +57,10 @@
     private int mDensity;
     private boolean mPulsing;
     private boolean mDozing;
+    private boolean mBouncerVisible;
     private boolean mLastDozing;
     private boolean mLastPulsing;
+    private boolean mLastBouncerVisible;
 
     private final Runnable mDrawOffTimeout = () -> update(true /* forceUpdate */);
     private float mDarkAmount;
@@ -109,9 +111,9 @@
         int state = getState();
         mIsFaceUnlockState = state == STATE_SCANNING_FACE;
         if (state != mLastState || mLastDozing != mDozing || mLastPulsing != mPulsing
-                || mLastScreenOn != mScreenOn || force) {
+                || mLastScreenOn != mScreenOn || mLastBouncerVisible != mBouncerVisible || force) {
             int iconAnimRes = getAnimationResForTransition(mLastState, state, mLastPulsing,
-                    mPulsing, mLastDozing, mDozing);
+                    mPulsing, mLastDozing, mDozing, mBouncerVisible);
             boolean isAnim = iconAnimRes != -1;
 
             Drawable icon;
@@ -159,6 +161,7 @@
             mLastScreenOn = mScreenOn;
             mLastDozing = mDozing;
             mLastPulsing = mPulsing;
+            mLastBouncerVisible = mBouncerVisible;
         }
 
         setVisibility(mDozing && !mPulsing ? GONE : VISIBLE);
@@ -231,8 +234,8 @@
     }
 
     private static int getAnimationResForTransition(int oldState, int newState,
-            boolean wasPulsing, boolean pulsing,
-            boolean wasDozing, boolean dozing) {
+            boolean wasPulsing, boolean pulsing, boolean wasDozing, boolean dozing,
+            boolean bouncerVisible) {
 
         // Never animate when screen is off
         if (dozing && !pulsing) {
@@ -249,7 +252,7 @@
             return com.android.internal.R.anim.lock_unlock;
         } else if (justLocked) {
             return com.android.internal.R.anim.lock_lock;
-        } else if (newState == STATE_SCANNING_FACE) {
+        } else if (newState == STATE_SCANNING_FACE && bouncerVisible) {
             return com.android.internal.R.anim.lock_scanning;
         } else if (!wasPulsing && pulsing && newState != STATE_LOCK_OPEN) {
             return com.android.internal.R.anim.lock_in;
@@ -298,4 +301,15 @@
         int color = ColorUtils.blendARGB(Color.TRANSPARENT, Color.WHITE, mDarkAmount);
         drawable.setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
     }
+
+    /**
+     * If bouncer is visible or not.
+     */
+    public void setBouncerVisible(boolean bouncerVisible) {
+        if (mBouncerVisible == bouncerVisible) {
+            return;
+        }
+        mBouncerVisible = bouncerVisible;
+        update();
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
index 1d87a8b..443cc43 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
@@ -98,8 +98,10 @@
         // Short-circuiting from UserManager. Needs to be extracted because of SystemUI boolean flag
         // qs_show_user_switcher_for_single_user
 
+        // The default in UserManager is to show the switcher. We want to not show it unless the
+        // user explicitly requests it in Settings
         final boolean userSwitcherEnabled = Settings.Global.getInt(mContext.getContentResolver(),
-                Settings.Global.USER_SWITCHER_ENABLED, 1) != 0;
+                Settings.Global.USER_SWITCHER_ENABLED, 0) != 0;
 
         if (!UserManager.supportsMultipleUsers()
                 || mUserManager.hasUserRestriction(UserManager.DISALLOW_USER_SWITCH)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index e2a63cc..835db6f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -34,7 +34,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.pm.ParceledListSlice;
 import android.content.res.Configuration;
 import android.graphics.Canvas;
 import android.graphics.Point;
@@ -48,8 +47,6 @@
 import android.util.Slog;
 import android.util.SparseArray;
 import android.view.Display;
-import android.view.IPinnedStackController;
-import android.view.IPinnedStackListener;
 import android.view.MotionEvent;
 import android.view.Surface;
 import android.view.View;
@@ -237,45 +234,6 @@
         }
     };
 
-    private final IPinnedStackListener.Stub mImeChangedListener = new IPinnedStackListener.Stub() {
-        @Override
-        public void onListenerRegistered(IPinnedStackController controller) {
-        }
-
-        @Override
-        public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {
-            post(() -> {
-                // TODO remove this and do below when mNavigationIconHints changes
-                if (imeVisible) {
-                    getBackButton().setVisibility(VISIBLE);
-                    reloadNavIcons();
-                } else {
-                    getImeSwitchButton().setVisibility(GONE);
-                }
-                mImeVisible = imeVisible;
-                updateWindowTouchable();
-            });
-        }
-
-        @Override
-        public void onShelfVisibilityChanged(boolean shelfVisible, int shelfHeight) {
-        }
-
-        @Override
-        public void onMinimizedStateChanged(boolean isMinimized) {
-        }
-
-        @Override
-        public void onMovementBoundsChanged(Rect insetBounds, Rect normalBounds,
-                Rect animatingBounds, boolean fromImeAdjustment, boolean fromShelfAdjustment,
-                int displayRotation) {
-        }
-
-        @Override
-        public void onActionsChanged(ParceledListSlice actions) {
-        }
-    };
-
     private BroadcastReceiver mOverlaysChangedReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -507,9 +465,7 @@
         final boolean useAltBack =
                 (mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0;
         final boolean isRtl = mConfiguration.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
-        float degrees = useAltBack
-                ? (isRtl ? 270 : -90)
-                : (isRtl ? 180 : 0);
+        float degrees = useAltBack ? (isRtl ? 90 : -90) : 0;
         if (drawable.getRotation() == degrees) {
             return;
         }
@@ -559,10 +515,13 @@
 
     public void setNavigationIconHints(int hints) {
         if (hints == mNavigationIconHints) return;
-        final boolean backAlt = (hints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0;
-        if ((mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0 && !backAlt) {
-            mTransitionListener.onBackAltCleared();
+        final boolean newBackAlt = (hints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0;
+        final boolean oldBackAlt =
+                (mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0;
+        if (newBackAlt != oldBackAlt) {
+            onImeVisibilityChanged(newBackAlt);
         }
+
         if (DEBUG) {
             android.widget.Toast.makeText(getContext(),
                 "Navigation icon hints = " + hints,
@@ -572,6 +531,14 @@
         updateNavButtonIcons();
     }
 
+    private void onImeVisibilityChanged(boolean visible) {
+        if (!visible) {
+            mTransitionListener.onBackAltCleared();
+        }
+        mImeVisible = visible;
+        updateWindowTouchable();
+    }
+
     public void setDisabledFlags(int disabledFlags) {
         if (mDisabledFlags == disabledFlags) return;
 
@@ -1114,14 +1081,6 @@
         filter.addDataScheme("package");
         getContext().registerReceiver(mOverlaysChangedReceiver, filter);
         mEdgeBackGestureHandler.onNavBarAttached();
-
-        if (QuickStepContract.isGesturalMode(getContext())) {
-            try {
-                WindowManagerWrapper.getInstance().addPinnedStackListener(mImeChangedListener);
-            } catch (RemoteException e) {
-                Log.e(TAG, "Failed to register pinned stack listener", e);
-            }
-        }
         updateWindowTouchable();
     }
 
@@ -1139,8 +1098,6 @@
 
         getContext().unregisterReceiver(mOverlaysChangedReceiver);
         mEdgeBackGestureHandler.onNavBarDetached();
-
-        WindowManagerWrapper.getInstance().removePinnedStackListener(mImeChangedListener);
     }
 
     private void setUpSwipeUpOnboarding(boolean connectedToOverviewProxy) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonDrawable.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonDrawable.java
index 03c89c6..dd0c344 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonDrawable.java
@@ -37,6 +37,7 @@
 import android.graphics.drawable.Drawable;
 import android.util.FloatProperty;
 import android.view.ContextThemeWrapper;
+import android.view.View;
 
 import com.android.settingslib.Utils;
 import com.android.systemui.R;
@@ -79,9 +80,10 @@
     private final ShadowDrawableState mState;
     private AnimatedVectorDrawable mAnimatedDrawable;
 
-    public KeyButtonDrawable(Drawable d, @ColorInt int lightColor, @ColorInt int darkColor) {
+    public KeyButtonDrawable(Drawable d, @ColorInt int lightColor, @ColorInt int darkColor,
+            boolean horizontalFlip) {
         this(d, new ShadowDrawableState(lightColor, darkColor,
-                d instanceof AnimatedVectorDrawable));
+                d instanceof AnimatedVectorDrawable, horizontalFlip));
     }
 
     private KeyButtonDrawable(Drawable d, ShadowDrawableState state) {
@@ -282,7 +284,12 @@
         // Call mutate, so that the pixel allocation by the underlying vector drawable is cleared.
         final Drawable d = mState.mChildState.newDrawable().mutate();
         setDrawableBounds(d);
+        canvas.save();
+        if (mState.mHorizontalFlip) {
+            canvas.scale(-1f, 1f, width * 0.5f, height * 0.5f);
+        }
         d.draw(canvas);
+        canvas.restore();
 
         if (mState.mIsHardwareBitmap) {
             bitmap = bitmap.copy(Bitmap.Config.HARDWARE, false);
@@ -305,7 +312,12 @@
         // Call mutate, so that the pixel allocation by the underlying vector drawable is cleared.
         final Drawable d = mState.mChildState.newDrawable().mutate();
         setDrawableBounds(d);
+        canvas.save();
+        if (mState.mHorizontalFlip) {
+            canvas.scale(-1f, 1f, width * 0.5f, height * 0.5f);
+        }
         d.draw(canvas);
+        canvas.restore();
 
         // Draws the shadow from original drawable
         Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
@@ -357,6 +369,7 @@
         int mShadowColor;
         float mDarkIntensity;
         int mAlpha;
+        boolean mHorizontalFlip;
 
         boolean mIsHardwareBitmap;
         Bitmap mLastDrawnIcon;
@@ -368,11 +381,12 @@
         final boolean mSupportsAnimation;
 
         public ShadowDrawableState(@ColorInt int lightColor, @ColorInt int darkColor,
-                boolean animated) {
+                boolean animated, boolean horizontalFlip) {
             mLightColor = lightColor;
             mDarkColor = darkColor;
             mSupportsAnimation = animated;
             mAlpha = 255;
+            mHorizontalFlip = horizontalFlip;
         }
 
         @Override
@@ -400,7 +414,7 @@
      * @return KeyButtonDrawable
      */
     public static KeyButtonDrawable create(@NonNull Context ctx, @DrawableRes int icon,
-        boolean hasShadow) {
+            boolean hasShadow) {
         final int dualToneDarkTheme = Utils.getThemeAttr(ctx, R.attr.darkIconTheme);
         final int dualToneLightTheme = Utils.getThemeAttr(ctx, R.attr.lightIconTheme);
         Context lightContext = new ContextThemeWrapper(ctx, dualToneLightTheme);
@@ -409,7 +423,7 @@
     }
 
     public static KeyButtonDrawable create(Context lightContext, Context darkContext,
-        @DrawableRes int iconResId, boolean hasShadow) {
+            @DrawableRes int iconResId, boolean hasShadow) {
         return create(lightContext,
             Utils.getColorAttrDefaultColor(lightContext, R.attr.singleToneColor),
             Utils.getColorAttrDefaultColor(darkContext, R.attr.singleToneColor),
@@ -418,10 +432,12 @@
 
     public static KeyButtonDrawable create(Context context, @ColorInt int lightColor,
         @ColorInt int darkColor, @DrawableRes int iconResId, boolean hasShadow) {
-        final KeyButtonDrawable drawable = new KeyButtonDrawable(context.getDrawable(iconResId),
-            lightColor, darkColor);
+        final Resources res = context.getResources();
+        boolean isRtl = res.getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_RTL;
+        Drawable d = context.getDrawable(iconResId);
+        final KeyButtonDrawable drawable = new KeyButtonDrawable(d, lightColor, darkColor,
+                isRtl && d.isAutoMirrored());
         if (hasShadow) {
-            final Resources res = context.getResources();
             int offsetX = res.getDimensionPixelSize(R.dimen.nav_key_button_shadow_offset_x);
             int offsetY = res.getDimensionPixelSize(R.dimen.nav_key_button_shadow_offset_y);
             int radius = res.getDimensionPixelSize(R.dimen.nav_key_button_shadow_radius);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
index c5996a1..8f135c8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
@@ -47,6 +47,8 @@
 import java.io.PrintWriter;
 import java.util.BitSet;
 import java.util.Objects;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 
 public class MobileSignalController extends SignalController<
@@ -73,6 +75,9 @@
     private SignalStrength mSignalStrength;
     private MobileIconGroup mDefaultIcons;
     private Config mConfig;
+    private boolean mInflateSignalStrengths = false;
+    // Some specific carriers have 5GE network which is special LTE CA network.
+    private static final int NETWORK_TYPE_LTE_CA_5GE = TelephonyManager.MAX_NETWORK_TYPE + 1;
 
     // TODO: Reduce number of vars passed in, if we have the NetworkController, probably don't
     // need listener lists anymore.
@@ -114,6 +119,7 @@
 
     public void setConfiguration(Config config) {
         mConfig = config;
+        updateInflateSignalStrength();
         mapIconSets();
         updateTelephony();
     }
@@ -236,11 +242,19 @@
                         TelephonyIcons.LTE_PLUS);
             }
         }
+        mNetworkToIconLookup.put(NETWORK_TYPE_LTE_CA_5GE,
+                TelephonyIcons.LTE_CA_5G_E);
         mNetworkToIconLookup.put(TelephonyManager.NETWORK_TYPE_IWLAN, TelephonyIcons.WFC);
     }
 
+    private void updateInflateSignalStrength() {
+        mInflateSignalStrengths = SubscriptionManager.getResourcesForSubId(mContext,
+               mSubscriptionInfo.getSubscriptionId())
+               .getBoolean(R.bool.config_inflateSignalStrength);
+    }
+
     private int getNumLevels() {
-        if (mConfig.inflateSignalStrengths) {
+        if (mInflateSignalStrengths) {
             return SignalStrength.NUM_SIGNAL_STRENGTH_BINS + 1;
         }
         return SignalStrength.NUM_SIGNAL_STRENGTH_BINS;
@@ -252,7 +266,7 @@
             return SignalDrawable.getCarrierChangeState(getNumLevels());
         } else if (mCurrentState.connected) {
             int level = mCurrentState.level;
-            if (mConfig.inflateSignalStrengths) {
+            if (mInflateSignalStrengths) {
                 level++;
             }
             boolean dataDisabled = mCurrentState.userSetup
@@ -381,6 +395,26 @@
         }
     }
 
+    private boolean isCarrierSpecificDataIcon() {
+        if (mConfig.patternOfCarrierSpecificDataIcon == null
+                || mConfig.patternOfCarrierSpecificDataIcon.length() == 0) {
+            return false;
+        }
+
+        Pattern stringPattern = Pattern.compile(mConfig.patternOfCarrierSpecificDataIcon);
+        String[] operatorNames = new String[]{mServiceState.getOperatorAlphaLongRaw(),
+                mServiceState.getOperatorAlphaShortRaw()};
+        for (String opName : operatorNames) {
+            if (!TextUtils.isEmpty(opName)) {
+                Matcher matcher = stringPattern.matcher(opName);
+                if (matcher.find()) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
     /**
      * Updates the network's name based on incoming spn and plmn.
      */
@@ -535,6 +569,7 @@
         pw.println("  mSignalStrength=" + mSignalStrength + ",");
         pw.println("  mDataState=" + mDataState + ",");
         pw.println("  mDataNetType=" + mDataNetType + ",");
+        pw.println("  mInflateSignalStrengths=" + mInflateSignalStrengths + ",");
     }
 
     class MobilePhoneStateListener extends PhoneStateListener {
@@ -559,12 +594,8 @@
                         + " dataState=" + state.getDataRegState());
             }
             mServiceState = state;
-            if (state != null) {
-                mDataNetType = state.getDataNetworkType();
-                if (mDataNetType == TelephonyManager.NETWORK_TYPE_LTE && mServiceState != null &&
-                        mServiceState.isUsingCarrierAggregation()) {
-                    mDataNetType = TelephonyManager.NETWORK_TYPE_LTE_CA;
-                }
+            if (mServiceState != null) {
+                updateDataNetType(mServiceState.getDataNetworkType());
             }
             updateTelephony();
         }
@@ -576,14 +607,21 @@
                         + " type=" + networkType);
             }
             mDataState = state;
-            mDataNetType = networkType;
-            if (mDataNetType == TelephonyManager.NETWORK_TYPE_LTE && mServiceState != null &&
-                    mServiceState.isUsingCarrierAggregation()) {
-                mDataNetType = TelephonyManager.NETWORK_TYPE_LTE_CA;
-            }
+            updateDataNetType(networkType);
             updateTelephony();
         }
 
+        private void updateDataNetType(int networkType) {
+            mDataNetType = networkType;
+            if (mDataNetType == TelephonyManager.NETWORK_TYPE_LTE) {
+                if (isCarrierSpecificDataIcon()) {
+                    mDataNetType = NETWORK_TYPE_LTE_CA_5GE;
+                } else if (mServiceState != null && mServiceState.isUsingCarrierAggregation()) {
+                    mDataNetType = TelephonyManager.NETWORK_TYPE_LTE_CA;
+                }
+            }
+        }
+
         @Override
         public void onDataActivity(int direction) {
             if (DEBUG) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index d01430a..faf63c8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -55,6 +55,7 @@
 import android.util.MathUtils;
 import android.util.SparseArray;
 
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.TelephonyIntents;
@@ -108,16 +109,10 @@
     private final SubscriptionDefaults mSubDefaults;
     private final DataSaverController mDataSaverController;
     private final CurrentUserTracker mUserTracker;
+    private final Object mLock = new Object();
     private Config mConfig;
 
-    private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
-        @Override
-        public void onActiveDataSubscriptionIdChanged(int subId) {
-            mActiveMobileDataSubscription = subId;
-            doUpdateMobileControllers();
-        }
-    };
-
+    private PhoneStateListener mPhoneStateListener;
     private int mActiveMobileDataSubscription = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
 
     // Subcontrollers.
@@ -279,6 +274,14 @@
         // TODO: Move off of the deprecated CONNECTIVITY_ACTION broadcast and rely on callbacks
         // exclusively for status bar icons.
         mConnectivityManager.registerDefaultNetworkCallback(callback, mReceiverHandler);
+        // Register the listener on our bg looper
+        mPhoneStateListener = new PhoneStateListener(bgLooper) {
+            @Override
+            public void onActiveDataSubscriptionIdChanged(int subId) {
+                mActiveMobileDataSubscription = subId;
+                doUpdateMobileControllers();
+            }
+        };
     }
 
     public DataSaverController getDataSaverController() {
@@ -600,7 +603,9 @@
             updateNoSims();
             return;
         }
-        setCurrentSubscriptions(subscriptions);
+        synchronized (mLock) {
+            setCurrentSubscriptionsLocked(subscriptions);
+        }
         updateNoSims();
         recalculateEmergency();
     }
@@ -628,8 +633,9 @@
         return false;
     }
 
+    @GuardedBy("mLock")
     @VisibleForTesting
-    void setCurrentSubscriptions(List<SubscriptionInfo> subscriptions) {
+    public void setCurrentSubscriptionsLocked(List<SubscriptionInfo> subscriptions) {
         Collections.sort(subscriptions, new Comparator<SubscriptionInfo>() {
             @Override
             public int compare(SubscriptionInfo lhs, SubscriptionInfo rhs) {
@@ -1102,6 +1108,7 @@
         boolean hspaDataDistinguishable;
         boolean inflateSignalStrengths = false;
         boolean alwaysShowDataRatIcon = false;
+        public String patternOfCarrierSpecificDataIcon = "";
 
         /**
          * Mapping from NR 5G status string to an integer. The NR 5G status string should match
@@ -1140,6 +1147,8 @@
                         CarrierConfigManager.KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL);
                 config.hideLtePlus = b.getBoolean(
                         CarrierConfigManager.KEY_HIDE_LTE_PLUS_DATA_ICON_BOOL);
+                config.patternOfCarrierSpecificDataIcon = b.getString(
+                        CarrierConfigManager.KEY_SHOW_CARRIER_DATA_ICON_PATTERN_STRING);
                 String nr5GIconConfiguration =
                         b.getString(CarrierConfigManager.KEY_5G_ICON_CONFIGURATION_STRING);
                 if (!TextUtils.isEmpty(nr5GIconConfiguration)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
index e151ca3..c22ff8b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TelephonyIcons.java
@@ -35,6 +35,7 @@
     static final int ICON_3G = R.drawable.ic_3g_mobiledata;
     static final int ICON_4G = R.drawable.ic_4g_mobiledata;
     static final int ICON_4G_PLUS = R.drawable.ic_4g_plus_mobiledata;
+    static final int ICON_5G_E = R.drawable.ic_5g_e_mobiledata;
     static final int ICON_1X = R.drawable.ic_1x_mobiledata;
     static final int ICON_5G = R.drawable.ic_5g_mobiledata;
     static final int ICON_5G_PLUS = R.drawable.ic_5g_plus_mobiledata;
@@ -204,6 +205,19 @@
             TelephonyIcons.ICON_LTE_PLUS,
             true);
 
+    static final MobileIconGroup LTE_CA_5G_E = new MobileIconGroup(
+            "5Ge",
+            null,
+            null,
+            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH,
+            0, 0,
+            0,
+            0,
+            AccessibilityContentDescriptions.PHONE_SIGNAL_STRENGTH[0],
+            R.string.data_connection_5ge,
+            TelephonyIcons.ICON_5G_E,
+            true);
+
     static final MobileIconGroup NR_5G = new MobileIconGroup(
             "5G",
             null,
@@ -276,6 +290,7 @@
         ICON_NAME_TO_ICON.put("h+", H_PLUS);
         ICON_NAME_TO_ICON.put("4g", FOUR_G);
         ICON_NAME_TO_ICON.put("4g+", FOUR_G_PLUS);
+        ICON_NAME_TO_ICON.put("5ge", LTE_CA_5G_E);
         ICON_NAME_TO_ICON.put("lte", LTE);
         ICON_NAME_TO_ICON.put("lte+", LTE_PLUS);
         ICON_NAME_TO_ICON.put("5g", NR_5G);
diff --git a/packages/SystemUI/src/com/android/systemui/volume/Events.java b/packages/SystemUI/src/com/android/systemui/volume/Events.java
index 2a84c5d..9bbfd22 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/Events.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/Events.java
@@ -94,7 +94,6 @@
     public static final int DISMISS_STREAM_GONE = 7;
     public static final int DISMISS_REASON_OUTPUT_CHOOSER = 8;
     public static final int DISMISS_REASON_USB_OVERHEAD_ALARM_CHANGED = 9;
-    public static final int DISMISS_REASON_ODI_CAPTIONS_CLICKED = 10;
     public static final String[] DISMISS_REASONS = {
             "unknown",
             "touch_outside",
@@ -105,8 +104,7 @@
             "done_clicked",
             "a11y_stream_changed",
             "output_chooser",
-            "usb_temperature_below_threshold",
-            "odi_captions_clicked"
+            "usb_temperature_below_threshold"
     };
 
     public static final int SHOW_REASON_UNKNOWN = 0;
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 2094b36..5095370 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -30,7 +30,6 @@
 import static android.view.View.VISIBLE;
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
 
-import static com.android.systemui.volume.Events.DISMISS_REASON_ODI_CAPTIONS_CLICKED;
 import static com.android.systemui.volume.Events.DISMISS_REASON_SETTINGS_CLICKED;
 
 import android.animation.ObjectAnimator;
@@ -519,7 +518,6 @@
             mODICaptionsIcon.setOnConfirmedTapListener(() -> {
                 onCaptionIconClicked();
                 Events.writeEvent(mContext, Events.EVENT_ODI_CAPTIONS_CLICK);
-                dismissH(DISMISS_REASON_ODI_CAPTIONS_CLICKED);
             }, mHandler);
         }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarContextTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarContextTest.java
index e3c081e..c837c9c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarContextTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarContextTest.java
@@ -179,8 +179,10 @@
         final int unusedColor = 0;
         final Drawable d = mock(Drawable.class);
         final ContextualButton button = spy(mBtn0);
-        final KeyButtonDrawable kbd1 = spy(new KeyButtonDrawable(d, unusedColor, unusedColor));
-        final KeyButtonDrawable kbd2 = spy(new KeyButtonDrawable(d, unusedColor, unusedColor));
+        final KeyButtonDrawable kbd1 = spy(new KeyButtonDrawable(d, unusedColor, unusedColor,
+                false /* horizontalFlip */));
+        final KeyButtonDrawable kbd2 = spy(new KeyButtonDrawable(d, unusedColor, unusedColor,
+                false /* horizontalFlip */));
         kbd1.setDarkIntensity(TEST_DARK_INTENSITY);
         kbd2.setDarkIntensity(0f);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
index ac6544e..0b53c48 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
@@ -300,7 +300,7 @@
         // We can only test whether unregister gets called if it thinks its in a listening
         // state.
         mNetworkController.mListening = true;
-        mNetworkController.setCurrentSubscriptions(subscriptions);
+        mNetworkController.setCurrentSubscriptionsLocked(subscriptions);
 
         for (int i = 0; i < testSubscriptions.length; i++) {
             if (i == indexToSkipController) {
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index a3e7d36..54a3ecb 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -166,6 +166,9 @@
     @Override
     public void onUnlockUser(int userHandle) {
         Set<Association> associations = readAllAssociations(userHandle);
+        if (associations == null || associations.isEmpty()) {
+            return;
+        }
         Set<String> companionAppPackages = new HashSet<>();
         for (Association association : associations) {
             companionAppPackages.add(association.companionAppPackage);
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 7a5e1b5..57de67e 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1771,11 +1771,8 @@
             // caller type. Need to re-factor NetdEventListenerService to allow multiple
             // NetworkMonitor registrants.
             if (nai != null && nai.satisfies(mDefaultRequest)) {
-                try {
-                    nai.networkMonitor().notifyDnsResponse(returnCode);
-                } catch (RemoteException e) {
-                    e.rethrowFromSystemServer();
-                }
+                Binder.withCleanCallingIdentity(() ->
+                        nai.networkMonitor().notifyDnsResponse(returnCode));
             }
         }
 
diff --git a/services/core/java/com/android/server/IpSecService.java b/services/core/java/com/android/server/IpSecService.java
index 126bf65..2055b64 100644
--- a/services/core/java/com/android/server/IpSecService.java
+++ b/services/core/java/com/android/server/IpSecService.java
@@ -96,9 +96,10 @@
             new int[] {OsConstants.AF_INET, OsConstants.AF_INET6};
 
     private static final int NETD_FETCH_TIMEOUT_MS = 5000; // ms
-    private static final int MAX_PORT_BIND_ATTEMPTS = 10;
     private static final InetAddress INADDR_ANY;
 
+    @VisibleForTesting static final int MAX_PORT_BIND_ATTEMPTS = 10;
+
     static {
         try {
             INADDR_ANY = InetAddress.getByAddress(new byte[] {0, 0, 0, 0});
@@ -207,6 +208,7 @@
                     mBinder.linkToDeath(this, 0);
                 } catch (RemoteException e) {
                     binderDied();
+                    e.rethrowFromSystemServer();
                 }
             }
         }
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/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index d073bc6..4c3bb8c 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -1840,11 +1840,14 @@
     }
 
     private boolean isPackageSuspendedForUser(String pkg, int uid) {
+        final long identity = Binder.clearCallingIdentity();
         try {
             return AppGlobals.getPackageManager().isPackageSuspendedForUser(
                     pkg, UserHandle.getUserId(uid));
         } catch (RemoteException re) {
             throw new SecurityException("Could not talk to package manager service");
+        } finally {
+            Binder.restoreCallingIdentity(identity);
         }
     }
 
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..39dae0b 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.
@@ -3361,8 +3368,14 @@
                 .append(Binder.getCallingPid()).toString();
         final boolean stateChanged = mDeviceBroker.setSpeakerphoneOn(on, eventSource);
         if (stateChanged) {
-            mContext.sendBroadcast(new Intent(AudioManager.ACTION_SPEAKERPHONE_STATE_CHANGED)
-                    .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY));
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                mContext.sendBroadcastAsUser(
+                        new Intent(AudioManager.ACTION_SPEAKERPHONE_STATE_CHANGED)
+                                .setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY), UserHandle.ALL);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/biometrics/AuthenticationClient.java b/services/core/java/com/android/server/biometrics/AuthenticationClient.java
index 7d4ac59..f7278d2 100644
--- a/services/core/java/com/android/server/biometrics/AuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/AuthenticationClient.java
@@ -129,13 +129,16 @@
         boolean result = false;
 
         try {
+            if (DEBUG) Slog.v(getLogTag(), "onAuthenticated(" + authenticated + ")"
+                    + ", ID:" + identifier.getBiometricId()
+                    + ", Owner: " + getOwnerString()
+                    + ", isBP: " + isBiometricPrompt()
+                    + ", listener: " + listener
+                    + ", requireConfirmation: " + mRequireConfirmation);
+
             if (authenticated) {
                 mAlreadyDone = true;
-                if (DEBUG) Slog.v(getLogTag(), "onAuthenticated(" + getOwnerString()
-                        + ", ID:" + identifier.getBiometricId()
-                        + ", isBP: " + isBiometricPrompt()
-                        + ", listener: " + listener
-                        + ", requireConfirmation: " + mRequireConfirmation);
+
                 if (listener != null) {
                     vibrateSuccess();
                 }
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index 843ecac..153133a 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -41,6 +41,7 @@
 import android.hardware.biometrics.BiometricPrompt;
 import android.hardware.biometrics.BiometricSourceType;
 import android.hardware.biometrics.BiometricsProtoEnums;
+import android.hardware.biometrics.IBiometricConfirmDeviceCredentialCallback;
 import android.hardware.biometrics.IBiometricEnabledOnKeyguardCallback;
 import android.hardware.biometrics.IBiometricService;
 import android.hardware.biometrics.IBiometricServiceReceiver;
@@ -85,6 +86,7 @@
 public class BiometricService extends SystemService {
 
     private static final String TAG = "BiometricService";
+    private static final boolean DEBUG = true;
 
     private static final int MSG_ON_TASK_STACK_CHANGED = 1;
     private static final int MSG_ON_AUTHENTICATION_SUCCEEDED = 2;
@@ -96,6 +98,9 @@
     private static final int MSG_ON_READY_FOR_AUTHENTICATION = 8;
     private static final int MSG_AUTHENTICATE = 9;
     private static final int MSG_CANCEL_AUTHENTICATION = 10;
+    private static final int MSG_ON_CONFIRM_DEVICE_CREDENTIAL_SUCCESS = 11;
+    private static final int MSG_ON_CONFIRM_DEVICE_CREDENTIAL_ERROR = 12;
+    private static final int MSG_REGISTER_CANCELLATION_CALLBACK = 13;
 
     private static final int[] FEATURE_ID = {
         TYPE_FINGERPRINT,
@@ -128,8 +133,12 @@
      * Authentication is successful, but we're waiting for the user to press "confirm" button.
      */
     private static final int STATE_AUTH_PENDING_CONFIRM = 5;
+    /**
+     * Biometric authentication was canceled, but the device is now showing ConfirmDeviceCredential
+     */
+    private static final int STATE_BIOMETRIC_AUTH_CANCELED_SHOWING_CDC = 6;
 
-    private final class AuthSession {
+    private final class AuthSession implements IBinder.DeathRecipient {
         // Map of Authenticator/Cookie pairs. We expect to receive the cookies back from
         // <Biometric>Services before we can start authenticating. Pairs that have been returned
         // are moved to mModalitiesMatched.
@@ -164,10 +173,14 @@
         // Timestamp when hardware authentication occurred
         private long mAuthenticatedTimeMs;
 
+        // TODO(b/123378871): Remove when moved.
+        private IBiometricConfirmDeviceCredentialCallback mConfirmDeviceCredentialCallback;
+
         AuthSession(HashMap<Integer, Integer> modalities, IBinder token, long sessionId,
                 int userId, IBiometricServiceReceiver receiver, String opPackageName,
                 Bundle bundle, int callingUid, int callingPid, int callingUserId,
-                int modality, boolean requireConfirmation) {
+                int modality, boolean requireConfirmation,
+                IBiometricConfirmDeviceCredentialCallback callback) {
             mModalitiesWaiting = modalities;
             mToken = token;
             mSessionId = sessionId;
@@ -180,12 +193,25 @@
             mCallingUserId = callingUserId;
             mModality = modality;
             mRequireConfirmation = requireConfirmation;
+            mConfirmDeviceCredentialCallback = callback;
+
+            if (isFromConfirmDeviceCredential()) {
+                try {
+                    token.linkToDeath(this, 0 /* flags */);
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Unable to link to death", e);
+                }
+            }
         }
 
         boolean isCrypto() {
             return mSessionId != 0;
         }
 
+        boolean isFromConfirmDeviceCredential() {
+            return mBundle.getBoolean(BiometricPrompt.KEY_FROM_CONFIRM_DEVICE_CREDENTIAL, false);
+        }
+
         boolean containsCookie(int cookie) {
             if (mModalitiesWaiting != null && mModalitiesWaiting.containsValue(cookie)) {
                 return true;
@@ -195,6 +221,25 @@
             }
             return false;
         }
+
+        // TODO(b/123378871): Remove when moved.
+        @Override
+        public void binderDied() {
+            mHandler.post(() -> {
+                Slog.e(TAG, "Binder died, killing ConfirmDeviceCredential");
+                if (mConfirmDeviceCredentialCallback == null) {
+                    Slog.e(TAG, "Callback is null");
+                    return;
+                }
+
+                try {
+                    mConfirmDeviceCredentialCallback.cancel();
+                    mConfirmDeviceCredentialCallback = null;
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Unable to send cancel", e);
+                }
+            });
+        }
     }
 
     private final class BiometricTaskStackListener extends TaskStackListener {
@@ -234,6 +279,14 @@
     private AuthSession mCurrentAuthSession;
     private AuthSession mPendingAuthSession;
 
+    // TODO(b/123378871): Remove when moved.
+    // When BiometricPrompt#setAllowDeviceCredentials is set to true, we need to store the
+    // client (app) receiver. BiometricService internally launches CDCA which invokes
+    // BiometricService to start authentication (normal path). When auth is success/rejected,
+    // CDCA will use an aidl method to poke BiometricService - the result will then be forwarded
+    // to this receiver.
+    private IBiometricServiceReceiver mConfirmDeviceCredentialReceiver;
+
     private final Handler mHandler = new Handler(Looper.getMainLooper()) {
         @Override
         public void handleMessage(Message msg) {
@@ -311,7 +364,8 @@
                             (Bundle) args.arg5 /* bundle */,
                             args.argi2 /* callingUid */,
                             args.argi3 /* callingPid */,
-                            args.argi4 /* callingUserId */);
+                            args.argi4 /* callingUserId */,
+                            (IBiometricConfirmDeviceCredentialCallback) args.arg6 /* callback */);
                     args.recycle();
                     break;
                 }
@@ -325,7 +379,28 @@
                     break;
                 }
 
+                case MSG_ON_CONFIRM_DEVICE_CREDENTIAL_SUCCESS: {
+                    handleOnConfirmDeviceCredentialSuccess();
+                    break;
+                }
+
+                case MSG_ON_CONFIRM_DEVICE_CREDENTIAL_ERROR: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    handleOnConfirmDeviceCredentialError(
+                            args.argi1 /* error */,
+                            (String) args.arg1 /* errorMsg */);
+                    args.recycle();
+                    break;
+                }
+
+                case MSG_REGISTER_CANCELLATION_CALLBACK: {
+                    handleRegisterCancellationCallback(
+                            (IBiometricConfirmDeviceCredentialCallback) msg.obj /* callback */);
+                    break;
+                }
+
                 default:
+                    Slog.e(TAG, "Unknown message: " + msg);
                     break;
             }
         }
@@ -533,14 +608,6 @@
      * cancelAuthentication() can go to the right place.
      */
     private final class BiometricServiceWrapper extends IBiometricService.Stub {
-        // TODO(b/123378871): Remove when moved.
-        // When BiometricPrompt#setAllowDeviceCredentials is set to true, we need to store the
-        // client (app) receiver. BiometricService internally launches CDCA which invokes
-        // BiometricService to start authentication (normal path). When auth is success/rejected,
-        // CDCA will use an aidl method to poke BiometricService - the result will then be forwarded
-        // to this receiver.
-        private IBiometricServiceReceiver mConfirmDeviceCredentialReceiver;
-
         @Override // Binder call
         public void onReadyForAuthentication(int cookie, boolean requireConfirmation, int userId) {
             checkInternalPermission();
@@ -554,12 +621,18 @@
 
         @Override // Binder call
         public void authenticate(IBinder token, long sessionId, int userId,
-                IBiometricServiceReceiver receiver, String opPackageName, Bundle bundle)
+                IBiometricServiceReceiver receiver, String opPackageName, Bundle bundle,
+                IBiometricConfirmDeviceCredentialCallback callback)
                 throws RemoteException {
             final int callingUid = Binder.getCallingUid();
             final int callingPid = Binder.getCallingPid();
             final int callingUserId = UserHandle.getCallingUserId();
 
+            // TODO(b/123378871): Remove when moved.
+            if (callback != null) {
+                checkInternalPermission();
+            }
+
             // In the BiometricServiceBase, check do the AppOps and foreground check.
             if (userId == callingUserId) {
                 // Check the USE_BIOMETRIC permission here.
@@ -576,6 +649,12 @@
                 return;
             }
 
+            final boolean isFromConfirmDeviceCredential =
+                    bundle.getBoolean(BiometricPrompt.KEY_FROM_CONFIRM_DEVICE_CREDENTIAL, false);
+            if (isFromConfirmDeviceCredential) {
+                checkInternalPermission();
+            }
+
             // Check the usage of this in system server. Need to remove this check if it becomes
             // a public API.
             final boolean useDefaultTitle =
@@ -632,6 +711,7 @@
             args.argi2 = callingUid;
             args.argi3 = callingPid;
             args.argi4 = callingUserId;
+            args.arg6 = callback;
 
             mHandler.obtainMessage(MSG_AUTHENTICATE, args).sendToTarget();
         }
@@ -639,35 +719,30 @@
         @Override // Binder call
         public void onConfirmDeviceCredentialSuccess() {
             checkInternalPermission();
-            mHandler.post(() -> {
-                if (mConfirmDeviceCredentialReceiver == null) {
-                    Slog.w(TAG, "onCDCASuccess null!");
-                    return;
-                }
-                try {
-                    mConfirmDeviceCredentialReceiver.onAuthenticationSucceeded();
-                } catch (RemoteException e) {
-                    Slog.e(TAG, "RemoteException", e);
-                }
-                mConfirmDeviceCredentialReceiver = null;
-            });
+
+            mHandler.sendEmptyMessage(MSG_ON_CONFIRM_DEVICE_CREDENTIAL_SUCCESS);
         }
 
         @Override // Binder call
         public void onConfirmDeviceCredentialError(int error, String message) {
             checkInternalPermission();
-            mHandler.post(() -> {
-                if (mConfirmDeviceCredentialReceiver == null) {
-                    Slog.w(TAG, "onCDCAError null! Error: " + error + " " + message);
-                    return;
-                }
-                try {
-                    mConfirmDeviceCredentialReceiver.onError(error, message);
-                } catch (RemoteException e) {
-                    Slog.e(TAG, "RemoteException", e);
-                }
-                mConfirmDeviceCredentialReceiver = null;
-            });
+
+            SomeArgs args = SomeArgs.obtain();
+            args.argi1 = error;
+            args.arg1 = message;
+            mHandler.obtainMessage(MSG_ON_CONFIRM_DEVICE_CREDENTIAL_ERROR, args).sendToTarget();
+        }
+
+        @Override // Binder call
+        public void registerCancellationCallback(
+                IBiometricConfirmDeviceCredentialCallback callback) {
+            // TODO(b/123378871): Remove when moved.
+            // This callback replaces the one stored in the current session. If the session is null
+            // we can ignore this, since it means ConfirmDeviceCredential was launched by something
+            // else (not BiometricPrompt)
+            checkInternalPermission();
+
+            mHandler.obtainMessage(MSG_REGISTER_CANCELLATION_CALLBACK, callback).sendToTarget();
         }
 
         @Override // Binder call
@@ -1104,6 +1179,52 @@
         }
     }
 
+    private void handleOnConfirmDeviceCredentialSuccess() {
+        if (mConfirmDeviceCredentialReceiver == null) {
+            Slog.w(TAG, "onCDCASuccess null!");
+            return;
+        }
+        try {
+            mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
+            mConfirmDeviceCredentialReceiver.onAuthenticationSucceeded();
+            if (mCurrentAuthSession != null) {
+                mCurrentAuthSession.mState = STATE_AUTH_IDLE;
+                mCurrentAuthSession = null;
+            }
+        } catch (RemoteException e) {
+            Slog.e(TAG, "RemoteException", e);
+        }
+        mConfirmDeviceCredentialReceiver = null;
+    }
+
+    private void handleOnConfirmDeviceCredentialError(int error, String message) {
+        if (mConfirmDeviceCredentialReceiver == null) {
+            Slog.w(TAG, "onCDCAError null! Error: " + error + " " + message);
+            return;
+        }
+        try {
+            mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
+            mConfirmDeviceCredentialReceiver.onError(error, message);
+            if (mCurrentAuthSession != null) {
+                mCurrentAuthSession.mState = STATE_AUTH_IDLE;
+                mCurrentAuthSession = null;
+            }
+        } catch (RemoteException e) {
+            Slog.e(TAG, "RemoteException", e);
+        }
+        mConfirmDeviceCredentialReceiver = null;
+    }
+
+    private void handleRegisterCancellationCallback(
+            IBiometricConfirmDeviceCredentialCallback callback) {
+        if (mCurrentAuthSession == null) {
+            Slog.d(TAG, "Current auth session null");
+            return;
+        }
+        Slog.d(TAG, "Updating cancel callback");
+        mCurrentAuthSession.mConfirmDeviceCredentialCallback = callback;
+    }
+
     private void handleOnError(int cookie, int error, String message) {
         Slog.d(TAG, "Error: " + error + " cookie: " + cookie);
         // Errors can either be from the current auth session or the pending auth session.
@@ -1114,7 +1235,18 @@
         // of their intended receivers.
         try {
             if (mCurrentAuthSession != null && mCurrentAuthSession.containsCookie(cookie)) {
-                if (mCurrentAuthSession.mState == STATE_AUTH_STARTED) {
+
+                if (mCurrentAuthSession.isFromConfirmDeviceCredential()) {
+                    // If we were invoked by ConfirmDeviceCredential, do not delete the current
+                    // auth session since we still need to respond to cancel signal while
+                    if (DEBUG) Slog.d(TAG, "From CDC, transition to CANCELED_SHOWING_CDC state");
+
+                    // Send the error to ConfirmDeviceCredential so that it goes to Pin/Pattern/Pass
+                    // screen
+                    mCurrentAuthSession.mClientReceiver.onError(error, message);
+                    mCurrentAuthSession.mState = STATE_BIOMETRIC_AUTH_CANCELED_SHOWING_CDC;
+                    mStatusBarService.hideBiometricDialog();
+                } else if (mCurrentAuthSession.mState == STATE_AUTH_STARTED) {
                     mStatusBarService.onBiometricError(message);
                     if (error == BiometricConstants.BIOMETRIC_ERROR_CANCELED) {
                         mActivityTaskManager.unregisterTaskStackListener(
@@ -1214,9 +1346,16 @@
                 KeyStore.getInstance().addAuthToken(mCurrentAuthSession.mTokenEscrow);
                 mCurrentAuthSession.mClientReceiver.onAuthenticationSucceeded();
             }
-            mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
-            mCurrentAuthSession.mState = STATE_AUTH_IDLE;
-            mCurrentAuthSession = null;
+
+            // Do not clean up yet if we are from ConfirmDeviceCredential. We should be in the
+            // STATE_BIOMETRIC_AUTH_CANCELED_SHOWING_CDC. The session should only be removed when
+            // ConfirmDeviceCredential is confirmed or canceled.
+            // TODO(b/123378871): Remove when moved
+            if (!mCurrentAuthSession.isFromConfirmDeviceCredential()) {
+                mActivityTaskManager.unregisterTaskStackListener(mTaskStackListener);
+                mCurrentAuthSession.mState = STATE_AUTH_IDLE;
+                mCurrentAuthSession = null;
+            }
         } catch (RemoteException e) {
             Slog.e(TAG, "Remote exception", e);
         }
@@ -1235,7 +1374,8 @@
                 mCurrentAuthSession.mCallingUid,
                 mCurrentAuthSession.mCallingPid,
                 mCurrentAuthSession.mCallingUserId,
-                mCurrentAuthSession.mModality);
+                mCurrentAuthSession.mModality,
+                mCurrentAuthSession.mConfirmDeviceCredentialCallback);
     }
 
     private void handleOnReadyForAuthentication(int cookie, boolean requireConfirmation,
@@ -1290,7 +1430,8 @@
 
     private void handleAuthenticate(IBinder token, long sessionId, int userId,
             IBiometricServiceReceiver receiver, String opPackageName, Bundle bundle,
-            int callingUid, int callingPid, int callingUserId) {
+            int callingUid, int callingPid, int callingUserId,
+            IBiometricConfirmDeviceCredentialCallback callback) {
 
         mHandler.post(() -> {
             final Pair<Integer, Integer> result = checkAndGetBiometricModality(userId);
@@ -1328,7 +1469,7 @@
             // Start preparing for authentication. Authentication starts when
             // all modalities requested have invoked onReadyForAuthentication.
             authenticateInternal(token, sessionId, userId, receiver, opPackageName, bundle,
-                    callingUid, callingPid, callingUserId, modality);
+                    callingUid, callingPid, callingUserId, modality, callback);
         });
     }
 
@@ -1343,7 +1484,8 @@
      */
     private void authenticateInternal(IBinder token, long sessionId, int userId,
             IBiometricServiceReceiver receiver, String opPackageName, Bundle bundle,
-            int callingUid, int callingPid, int callingUserId, int modality) {
+            int callingUid, int callingPid, int callingUserId, int modality,
+            IBiometricConfirmDeviceCredentialCallback callback) {
         try {
             boolean requireConfirmation = bundle.getBoolean(
                     BiometricPrompt.KEY_REQUIRE_CONFIRMATION, true /* default */);
@@ -1363,7 +1505,7 @@
             authenticators.put(modality, cookie);
             mPendingAuthSession = new AuthSession(authenticators, token, sessionId, userId,
                     receiver, opPackageName, bundle, callingUid, callingPid, callingUserId,
-                    modality, requireConfirmation);
+                    modality, requireConfirmation, callback);
             mPendingAuthSession.mState = STATE_AUTH_CALLED;
             // No polymorphism :(
             if ((modality & TYPE_FINGERPRINT) != 0) {
@@ -1390,10 +1532,23 @@
             return;
         }
 
-        // We need to check the current authenticators state. If we're pending confirm
-        // or idle, we need to dismiss the dialog and send an ERROR_CANCELED to the client,
-        // since we won't be getting an onError from the driver.
-        if (mCurrentAuthSession != null && mCurrentAuthSession.mState != STATE_AUTH_STARTED) {
+        if (mCurrentAuthSession != null
+                && mCurrentAuthSession.mState == STATE_BIOMETRIC_AUTH_CANCELED_SHOWING_CDC) {
+            if (DEBUG) Slog.d(TAG, "Cancel received while ConfirmDeviceCredential showing");
+            try {
+                mCurrentAuthSession.mConfirmDeviceCredentialCallback.cancel();
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Unable to cancel ConfirmDeviceCredential", e);
+            }
+
+            // TODO(b/123378871): Remove when moved. Piggy back on this for now to clean up.
+            handleOnConfirmDeviceCredentialError(BiometricConstants.BIOMETRIC_ERROR_CANCELED,
+                    getContext().getString(R.string.biometric_error_canceled));
+        } else if (mCurrentAuthSession != null
+                && mCurrentAuthSession.mState != STATE_AUTH_STARTED) {
+            // We need to check the current authenticators state. If we're pending confirm
+            // or idle, we need to dismiss the dialog and send an ERROR_CANCELED to the client,
+            // since we won't be getting an onError from the driver.
             try {
                 // Send error to client
                 mCurrentAuthSession.mClientReceiver.onError(
@@ -1409,11 +1564,22 @@
                 Slog.e(TAG, "Remote exception", e);
             }
         } else {
-            cancelInternal(token, opPackageName, true /* fromClient */);
+            boolean fromCDC = false;
+            if (mCurrentAuthSession != null) {
+                fromCDC = mCurrentAuthSession.mBundle.getBoolean(
+                        BiometricPrompt.KEY_FROM_CONFIRM_DEVICE_CREDENTIAL, false);
+            }
+
+            if (fromCDC) {
+                if (DEBUG) Slog.d(TAG, "Cancelling from CDC");
+                cancelInternal(token, opPackageName, false /* fromClient */);
+            } else {
+                cancelInternal(token, opPackageName, true /* fromClient */);
+            }
+
         }
     }
 
-
     void cancelInternal(IBinder token, String opPackageName, boolean fromClient) {
         final int callingUid = Binder.getCallingUid();
         final int callingPid = Binder.getCallingPid();
diff --git a/services/core/java/com/android/server/connectivity/PermissionMonitor.java b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
index da1360d..b6946023 100644
--- a/services/core/java/com/android/server/connectivity/PermissionMonitor.java
+++ b/services/core/java/com/android/server/connectivity/PermissionMonitor.java
@@ -469,7 +469,10 @@
      */
     @VisibleForTesting
     void sendPackagePermissionsToNetd(SparseIntArray netdPermissionsAppIds) {
-
+        if (mNetd == null) {
+            Log.e(TAG, "Failed to get the netd service");
+            return;
+        }
         ArrayList<Integer> allPermissionAppIds = new ArrayList<>();
         ArrayList<Integer> internetPermissionAppIds = new ArrayList<>();
         ArrayList<Integer> updateStatsPermissionAppIds = new ArrayList<>();
diff --git a/services/core/java/com/android/server/display/color/DisplayTransformManager.java b/services/core/java/com/android/server/display/color/DisplayTransformManager.java
index 026837f..d6aa2ba 100644
--- a/services/core/java/com/android/server/display/color/DisplayTransformManager.java
+++ b/services/core/java/com/android/server/display/color/DisplayTransformManager.java
@@ -28,6 +28,7 @@
 import android.util.SparseArray;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 
 import java.util.Arrays;
 
@@ -73,15 +74,27 @@
     private static final int SURFACE_FLINGER_TRANSACTION_DISPLAY_COLOR = 1023;
     private static final int SURFACE_FLINGER_TRANSACTION_QUERY_COLOR_MANAGED = 1030;
 
-    private static final String PERSISTENT_PROPERTY_SATURATION = "persist.sys.sf.color_saturation";
-    private static final String PERSISTENT_PROPERTY_DISPLAY_COLOR = "persist.sys.sf.native_mode";
+    @VisibleForTesting
+    static final String PERSISTENT_PROPERTY_SATURATION = "persist.sys.sf.color_saturation";
+    @VisibleForTesting
+    static final String PERSISTENT_PROPERTY_DISPLAY_COLOR = "persist.sys.sf.native_mode";
 
     private static final float COLOR_SATURATION_NATURAL = 1.0f;
     private static final float COLOR_SATURATION_BOOSTED = 1.1f;
 
+    /**
+     * Display color modes defined by DisplayColorSetting in
+     * frameworks/native/services/surfaceflinger/SurfaceFlinger.h.
+     */
     private static final int DISPLAY_COLOR_MANAGED = 0;
     private static final int DISPLAY_COLOR_UNMANAGED = 1;
     private static final int DISPLAY_COLOR_ENHANCED = 2;
+    /**
+     * Display color mode range reserved for vendor customizations by the RenderIntent definition in
+     * hardware/interfaces/graphics/common/1.1/types.hal.
+     */
+    private static final int VENDOR_MODE_RANGE_MIN = 256; // 0x100
+    private static final int VENDOR_MODE_RANGE_MAX = 511; // 0x1ff
 
     /**
      * Map of level -> color transformation matrix.
@@ -257,7 +270,11 @@
         } else if (colorMode == ColorDisplayManager.COLOR_MODE_AUTOMATIC) {
             applySaturation(COLOR_SATURATION_NATURAL);
             setDisplayColor(DISPLAY_COLOR_ENHANCED);
+        } else if (colorMode >= VENDOR_MODE_RANGE_MIN && colorMode <= VENDOR_MODE_RANGE_MAX) {
+            applySaturation(COLOR_SATURATION_NATURAL);
+            setDisplayColor(colorMode);
         }
+
         setColorMatrix(LEVEL_COLOR_MATRIX_NIGHT_DISPLAY, nightDisplayMatrix);
 
         updateConfiguration();
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/gpu/GpuService.java b/services/core/java/com/android/server/gpu/GpuService.java
index 647727f..0f73f37 100644
--- a/services/core/java/com/android/server/gpu/GpuService.java
+++ b/services/core/java/com/android/server/gpu/GpuService.java
@@ -36,6 +36,7 @@
 import android.os.Handler;
 import android.os.SystemProperties;
 import android.os.UserHandle;
+import android.provider.DeviceConfig;
 import android.provider.Settings;
 import android.util.Base64;
 import android.util.Slog;
@@ -69,9 +70,11 @@
     private final String mDriverPackageName;
     private final PackageManager mPackageManager;
     private final Object mLock = new Object();
+    private final Object mDeviceConfigLock = new Object();
     private ContentResolver mContentResolver;
     private long mGameDriverVersionCode;
     private SettingsObserver mSettingsObserver;
+    private DeviceConfigListener mDeviceConfigListener;
     @GuardedBy("mLock")
     private Blacklists mBlacklists;
 
@@ -101,10 +104,11 @@
     public void onBootPhase(int phase) {
         if (phase == PHASE_BOOT_COMPLETED) {
             mContentResolver = mContext.getContentResolver();
-            mSettingsObserver = new SettingsObserver();
             if (mDriverPackageName == null || mDriverPackageName.isEmpty()) {
                 return;
             }
+            mSettingsObserver = new SettingsObserver();
+            mDeviceConfigListener = new DeviceConfigListener();
             fetchGameDriverPackageProperties();
             processBlacklists();
             setBlacklist();
@@ -134,6 +138,24 @@
         }
     }
 
+    private final class DeviceConfigListener implements DeviceConfig.OnPropertyChangedListener {
+
+        DeviceConfigListener() {
+            super();
+            DeviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_GAME_DRIVER,
+                    mContext.getMainExecutor(), this);
+        }
+        @Override
+        public void onPropertyChanged(String namespace, String name, String value) {
+            synchronized (mDeviceConfigLock) {
+                if (Settings.Global.GAME_DRIVER_BLACKLISTS.equals(name)) {
+                    parseBlacklists(value != null ? value : "");
+                    setBlacklist();
+                }
+            }
+        }
+    }
+
     private final class PackageReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(@NonNull final Context context, @NonNull final Intent intent) {
@@ -229,13 +251,17 @@
     }
 
     private void processBlacklists() {
-        // TODO(b/121350991) Switch to DeviceConfig with property listener.
-        String base64String =
-                Settings.Global.getString(mContentResolver, Settings.Global.GAME_DRIVER_BLACKLISTS);
-        if (base64String == null || base64String.isEmpty()) {
-            return;
+        String base64String = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_GAME_DRIVER,
+                Settings.Global.GAME_DRIVER_BLACKLISTS);
+        if (base64String == null) {
+            base64String =
+                    Settings.Global.getString(mContentResolver,
+                                              Settings.Global.GAME_DRIVER_BLACKLISTS);
         }
+        parseBlacklists(base64String != null ? base64String : "");
+    }
 
+    private void parseBlacklists(String base64String) {
         synchronized (mLock) {
             // Reset all blacklists
             mBlacklists = null;
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 647e952..d360a63 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;
 
@@ -4100,13 +4101,15 @@
 
     // ----------------------------------------------------------------------
 
-    boolean setInputMethodEnabledLocked(String id, boolean enabled) {
-        // Make sure this is a valid input method.
-        InputMethodInfo imm = mMethodMap.get(id);
-        if (imm == null) {
-            throw new IllegalArgumentException("Unknown id: " + mCurMethodId);
-        }
-
+    /**
+     * Enable or disable the given IME by updating {@link Settings.Secure#ENABLED_INPUT_METHODS}.
+     *
+     * @param id ID of the IME is to be manipulated. It is OK to pass IME ID that is currently not
+     *           recognized by the system.
+     * @param enabled {@code true} if {@code id} needs to be enabled.
+     * @return {@code true} if the IME was previously enabled. {@code false} otherwise.
+     */
+    private boolean setInputMethodEnabledLocked(String id, boolean enabled) {
         List<Pair<String, ArrayList<String>>> enabledInputMethodsList = mSettings
                 .getEnabledInputMethodsAndSubtypeListLocked();
 
@@ -4696,6 +4699,14 @@
             if (!userHasDebugPriv(mSettings.getCurrentUserId(), shellCommand)) {
                 return ShellCommandResult.SUCCESS;
             }
+            // Make sure this is a valid input method.
+            if (enabled && !mMethodMap.containsKey(id)) {
+                final PrintWriter error = shellCommand.getErrPrintWriter();
+                error.print("Unknown input method ");
+                error.print(id);
+                error.println(" cannot be enabled");
+                return ShellCommandResult.SUCCESS;
+            }
             previouslyEnabled = setInputMethodEnabledLocked(id, enabled);
         }
         final PrintWriter pr = shellCommand.getOutPrintWriter();
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/media/MediaSessionServiceImpl.java b/services/core/java/com/android/server/media/MediaSessionServiceImpl.java
index 0cabf1d..de36dea 100644
--- a/services/core/java/com/android/server/media/MediaSessionServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaSessionServiceImpl.java
@@ -1489,8 +1489,10 @@
             final long token = Binder.clearCallingIdentity();
 
             if (DEBUG_KEY_EVENT) {
-                Log.d(TAG, "dispatchVolumeKeyEvent, pkg=" + packageName + ", pid=" + pid + ", uid="
-                        + uid + ", asSystem=" + asSystemService + ", event=" + keyEvent);
+                Log.d(TAG, "dispatchVolumeKeyEvent, pkg=" + packageName
+                        + ", opPkg=" + opPackageName + ", pid=" + pid + ", uid=" + uid
+                        + ", asSystem=" + asSystemService + ", event=" + keyEvent
+                        + ", stream=" + stream + ", musicOnly=" + musicOnly);
             }
 
             try {
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 1559911..f34ace5 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -25,6 +25,7 @@
 import static android.content.Intent.EXTRA_UID;
 import static android.net.ConnectivityManager.ACTION_TETHER_STATE_CHANGED;
 import static android.net.ConnectivityManager.isNetworkTypeMobile;
+import static android.net.NetworkStack.checkNetworkStackPermission;
 import static android.net.NetworkStats.DEFAULT_NETWORK_ALL;
 import static android.net.NetworkStats.IFACE_ALL;
 import static android.net.NetworkStats.INTERFACES_ALL;
@@ -866,7 +867,7 @@
             VpnInfo[] vpnArray,
             NetworkState[] networkStates,
             String activeIface) {
-        mContext.enforceCallingOrSelfPermission(READ_NETWORK_USAGE_HISTORY, TAG);
+        checkNetworkStackPermission(mContext);
         assertBandwidthControlEnabled();
 
         final long token = Binder.clearCallingIdentity();
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index f2e56b5..dec47a1 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -29,6 +29,7 @@
 import static android.app.NotificationManager.IMPORTANCE_LOW;
 import static android.app.NotificationManager.IMPORTANCE_MIN;
 import static android.app.NotificationManager.IMPORTANCE_NONE;
+import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY;
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECTS_UNSET;
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
@@ -2868,7 +2869,7 @@
 
         @Override
         public void allowAssistantCapability(String adjustmentType) {
-            checkCallerIsSystemOrShell();
+            checkCallerIsSystemOrSystemUiOrShell();
             mAssistants.allowAdjustmentType(adjustmentType);
 
             handleSavePolicyFile();
@@ -2876,7 +2877,7 @@
 
         @Override
         public void disallowAssistantCapability(String adjustmentType) {
-            checkCallerIsSystemOrShell();
+            checkCallerIsSystemOrSystemUiOrShell();
             mAssistants.disallowAdjustmentType(adjustmentType);
 
             handleSavePolicyFile();
@@ -3419,8 +3420,7 @@
         }
 
         @Override
-        public String addAutomaticZenRule(AutomaticZenRule automaticZenRule)
-                throws RemoteException {
+        public String addAutomaticZenRule(AutomaticZenRule automaticZenRule) {
             Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
             Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
             if (automaticZenRule.getOwner() == null
@@ -3429,6 +3429,11 @@
                         "Rule must have a conditionproviderservice and/or configuration activity");
             }
             Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
+            if (automaticZenRule.getZenPolicy() != null
+                    && automaticZenRule.getInterruptionFilter() != INTERRUPTION_FILTER_PRIORITY) {
+                throw new IllegalArgumentException("ZenPolicy is only applicable to "
+                        + "INTERRUPTION_FILTER_PRIORITY filters");
+            }
             enforcePolicyAccess(Binder.getCallingUid(), "addAutomaticZenRule");
 
             return mZenModeHelper.addAutomaticZenRule(automaticZenRule,
@@ -3806,7 +3811,7 @@
 
         @Override
         public ComponentName getAllowedNotificationAssistantForUser(int userId) {
-            checkCallerIsSystem();
+            checkCallerIsSystemOrSystemUiOrShell();
             List<ComponentName> allowedComponents = mAssistants.getAllowedComponents(userId);
             if (allowedComponents.size() > 1) {
                 throw new IllegalStateException(
@@ -3889,7 +3894,7 @@
         @Override
         public void setNotificationAssistantAccessGrantedForUser(ComponentName assistant,
                 int userId, boolean granted) {
-            checkCallerIsSystemOrShell();
+            checkCallerIsSystemOrSystemUiOrShell();
             mAssistants.setUserSet(userId, true);
             final long identity = Binder.clearCallingIdentity();
             try {
@@ -3924,10 +3929,6 @@
                         }
                     }
                     if (!foundEnqueued) {
-                        // adjustment arrived too late to apply to enqueued; apply to posted
-                        // However, since the notification is now posted and may have alerted,
-                        // ignore any importance related adjustments
-                        adjustment.getSignals().remove(Adjustment.KEY_IMPORTANCE);
                         applyAdjustmentFromAssistant(token, adjustment);
                     }
                 }
@@ -4118,7 +4119,7 @@
             }
             return;
         }
-        if (mAllowedManagedServicePackages.test(assistant.getPackageName(), userId,
+        if (!granted || mAllowedManagedServicePackages.test(assistant.getPackageName(), userId,
                 mAssistants.getRequiredPermission())) {
             mConditionProviders.setPackageOrComponentEnabled(assistant.flattenToString(),
                     userId, false, granted);
@@ -6990,6 +6991,16 @@
         throw new SecurityException("Disallowed call for uid " + Binder.getCallingUid());
     }
 
+    private void checkCallerIsSystemOrSystemUiOrShell() {
+        if (Binder.getCallingUid() == Process.SHELL_UID) {
+            return;
+        }
+        if (isCallerSystemOrPhone()) {
+            return;
+        }
+        getContext().enforceCallingPermission(android.Manifest.permission.STATUS_BAR_SERVICE, null);
+    }
+
     private void checkCallerIsSystemOrSameApp(String pkg) {
         if (isCallerSystemOrPhone()) {
             return;
@@ -7297,7 +7308,7 @@
 
         @GuardedBy("mLock")
         private ArrayMap<Integer, Boolean> mUserSetMap = new ArrayMap<>();
-        private List<String> mAllowedAdjustments = new ArrayList<>();
+        private Set<String> mAllowedAdjustments = new ArraySet<>();
 
         public NotificationAssistants(Context context, Object lock, UserProfiles up,
                 IPackageManager pm) {
@@ -7385,12 +7396,18 @@
             synchronized (mLock) {
                 mAllowedAdjustments.add(type);
             }
+            for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
+                mHandler.post(() -> notifyCapabilitiesChanged(info));
+            }
         }
 
         protected void disallowAdjustmentType(String type) {
             synchronized (mLock) {
                 mAllowedAdjustments.remove(type);
             }
+            for (final ManagedServiceInfo info : NotificationAssistants.this.getServices()) {
+                    mHandler.post(() -> notifyCapabilitiesChanged(info));
+            }
         }
 
         protected List<String> getAllowedAssistantCapabilities() {
@@ -7450,6 +7467,15 @@
             setUserSet(userId, userSet);
         }
 
+        private void notifyCapabilitiesChanged(final ManagedServiceInfo info) {
+            final INotificationListener assistant = (INotificationListener) info.service;
+            try {
+                assistant.onCapabilitiesChanged();
+            } catch (RemoteException ex) {
+                Slog.e(TAG, "unable to notify assistant (capabilities): " + assistant, ex);
+            }
+        }
+
         private void notifySeen(final ManagedServiceInfo info,
                 final ArrayList<String> keys) {
             final INotificationListener assistant = (INotificationListener) info.service;
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/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 1ce9d82..6c5abe4 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -757,124 +757,9 @@
         @Override public final boolean hasFeature(String feature) {
             return PackageManagerService.this.hasSystemFeature(feature, 0);
         }
-
-        final List<PackageParser.Package> getStaticOverlayPackages(
-                Collection<PackageParser.Package> allPackages, String targetPackageName) {
-            if ("android".equals(targetPackageName)) {
-                // Static RROs targeting to "android", ie framework-res.apk, are already applied by
-                // native AssetManager.
-                return null;
-            }
-
-            List<PackageParser.Package> overlayPackages = null;
-            for (PackageParser.Package p : allPackages) {
-                if (targetPackageName.equals(p.mOverlayTarget) && p.mOverlayIsStatic) {
-                    if (overlayPackages == null) {
-                        overlayPackages = new ArrayList<>();
-                    }
-                    overlayPackages.add(p);
-                }
-            }
-            if (overlayPackages != null) {
-                Comparator<PackageParser.Package> cmp =
-                        Comparator.comparingInt(p -> p.mOverlayPriority);
-                overlayPackages.sort(cmp);
-            }
-            return overlayPackages;
-        }
-
-        final String[] getStaticOverlayPaths(List<PackageParser.Package> overlayPackages,
-                String targetPath) {
-            if (overlayPackages == null || overlayPackages.isEmpty()) {
-                return null;
-            }
-            List<String> overlayPathList = null;
-            for (PackageParser.Package overlayPackage : overlayPackages) {
-                if (targetPath == null) {
-                    if (overlayPathList == null) {
-                        overlayPathList = new ArrayList<>();
-                    }
-                    overlayPathList.add(overlayPackage.baseCodePath);
-                    continue;
-                }
-
-                try {
-                    // Creates idmaps for system to parse correctly the Android manifest of the
-                    // target package.
-                    //
-                    // OverlayManagerService will update each of them with a correct gid from its
-                    // target package app id.
-                    mInstaller.idmap(targetPath, overlayPackage.baseCodePath,
-                            UserHandle.getSharedAppGid(
-                                    UserHandle.getUserGid(UserHandle.USER_SYSTEM)));
-                    if (overlayPathList == null) {
-                        overlayPathList = new ArrayList<>();
-                    }
-                    overlayPathList.add(overlayPackage.baseCodePath);
-                } catch (InstallerException e) {
-                    Slog.e(TAG, "Failed to generate idmap for " + targetPath + " and " +
-                            overlayPackage.baseCodePath);
-                }
-            }
-            return overlayPathList == null ? null : overlayPathList.toArray(new String[0]);
-        }
-
-        String[] getStaticOverlayPaths(String targetPackageName, String targetPath) {
-            List<PackageParser.Package> overlayPackages;
-            synchronized (mInstallLock) {
-                synchronized (mPackages) {
-                    overlayPackages = getStaticOverlayPackages(
-                            mPackages.values(), targetPackageName);
-                }
-                // It is safe to keep overlayPackages without holding mPackages because static overlay
-                // packages can't be uninstalled or disabled.
-                return getStaticOverlayPaths(overlayPackages, targetPath);
-            }
-        }
-
-        @Override public final String[] getOverlayApks(String targetPackageName) {
-            return getStaticOverlayPaths(targetPackageName, null);
-        }
-
-        @Override public final String[] getOverlayPaths(String targetPackageName,
-                String targetPath) {
-            return getStaticOverlayPaths(targetPackageName, targetPath);
-        }
-    }
-
-    class ParallelPackageParserCallback extends PackageParserCallback {
-        List<PackageParser.Package> mOverlayPackages = null;
-
-        void findStaticOverlayPackages() {
-            synchronized (mPackages) {
-                for (PackageParser.Package p : mPackages.values()) {
-                    if (p.mOverlayIsStatic) {
-                        if (mOverlayPackages == null) {
-                            mOverlayPackages = new ArrayList<>();
-                        }
-                        mOverlayPackages.add(p);
-                    }
-                }
-            }
-        }
-
-        @Override
-        synchronized String[] getStaticOverlayPaths(String targetPackageName, String targetPath) {
-            // We can trust mOverlayPackages without holding mPackages because package uninstall
-            // can't happen while running parallel parsing.
-            // And we can call mInstaller inside getStaticOverlayPaths without holding mInstallLock
-            // because mInstallLock is held before running parallel parsing.
-            // Moreover holding mPackages or mInstallLock on each parsing thread causes dead-lock.
-            return mOverlayPackages == null ? null :
-                    getStaticOverlayPaths(
-                            getStaticOverlayPackages(mOverlayPackages, targetPackageName),
-                            targetPath);
-        }
     }
 
     final PackageParser.Callback mPackageParserCallback = new PackageParserCallback();
-    final ParallelPackageParserCallback mParallelPackageParserCallback =
-            new ParallelPackageParserCallback();
 
     // Currently known shared libraries.
     final ArrayMap<String, LongSparseArray<SharedLibraryInfo>> mSharedLibraries = new ArrayMap<>();
@@ -2558,8 +2443,6 @@
                     | SCAN_AS_ODM,
                     0);
 
-            mParallelPackageParserCallback.findStaticOverlayPackages();
-
             // Find base frameworks (resource packages without code).
             scanDirTracedLI(frameworkDir,
                     mDefParseFlags
@@ -8782,7 +8665,7 @@
         }
         try (ParallelPackageParser parallelPackageParser = new ParallelPackageParser(
                 mSeparateProcesses, mOnlyCore, mMetrics, mCacheDir,
-                mParallelPackageParserCallback)) {
+                mPackageParserCallback)) {
             // Submit files for parsing in parallel
             int fileCount = 0;
             for (File file : files) {
@@ -24816,11 +24699,9 @@
         }
         if (mExternalSourcesPolicy != null) {
             int isTrusted = mExternalSourcesPolicy.getPackageTrustedToInstallApps(packageName, uid);
-            if (isTrusted != PackageManagerInternal.ExternalSourcesPolicy.USER_DEFAULT) {
-                return isTrusted == PackageManagerInternal.ExternalSourcesPolicy.USER_TRUSTED;
-            }
+            return isTrusted == PackageManagerInternal.ExternalSourcesPolicy.USER_TRUSTED;
         }
-        return checkUidPermission(appOpPermission, uid) == PERMISSION_GRANTED;
+        return false;
     }
 
     @Override
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 5df2f86..b819aa5 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -302,6 +302,7 @@
     }
 
     public void grantDefaultPermissions(int userId) {
+        removeSystemFixedStorage(userId);
         grantPermissionsToSysComponentsAndPrivApps(userId);
         grantDefaultSystemHandlerPermissions(userId);
         grantDefaultPermissionExceptions(userId);
@@ -310,6 +311,46 @@
         }
     }
 
+    // STOPSHIP: This is meant to fix the devices messed up by storage permission model 2 and
+    //           should be removed once all devices were updated
+    private void removeSystemFixedStorage(int userId) {
+        List<PackageInfo> packages = mContext.getPackageManager().getInstalledPackagesAsUser(
+                DEFAULT_PACKAGE_INFO_QUERY_FLAGS, userId);
+
+        for (PackageInfo pkg : packages) {
+            if (pkg == null || pkg.requestedPermissions == null) {
+                continue;
+            }
+
+            for (String permission : pkg.requestedPermissions) {
+                if (!(Manifest.permission.READ_EXTERNAL_STORAGE.equals(permission)
+                        || Manifest.permission.WRITE_EXTERNAL_STORAGE.equals(permission))) {
+                    continue;
+                }
+
+                int flags = mContext.getPackageManager().getPermissionFlags(permission,
+                        pkg.packageName, UserHandle.of(userId));
+                if ((flags & PackageManager.FLAG_PERMISSION_SYSTEM_FIXED) == 0) {
+                    continue;
+                }
+
+                Log.v(TAG, "Removing system fixed " + pkg.packageName + "/" + permission);
+                mContext.getPackageManager().updatePermissionFlags(permission, pkg.packageName,
+                        PackageManager.FLAG_PERMISSION_SYSTEM_FIXED, 0, UserHandle.of(userId));
+
+                if (!doesPackageSupportRuntimePermissions(pkg)
+                        || (flags & (PackageManager.FLAG_PERMISSION_USER_SET
+                        | PackageManager.FLAG_PERMISSION_POLICY_FIXED)) != 0) {
+                    continue;
+                }
+
+                Log.v(TAG, "Revoking " + pkg.packageName + "/" + permission);
+                mContext.getPackageManager().revokeRuntimePermission(pkg.packageName, permission,
+                        UserHandle.of(userId));
+            }
+        }
+    }
+
     private void grantRuntimePermissionsForSystemPackage(int userId, PackageInfo pkg) {
         Set<String> permissions = new ArraySet<>();
         for (String permission : pkg.requestedPermissions) {
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/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 6ac41ba..e2253e7 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -693,13 +693,13 @@
         }
     }
 
-    void scheduleTopResumedActivityChanged(boolean onTop) {
+    boolean scheduleTopResumedActivityChanged(boolean onTop) {
         if (!attachedToProcess()) {
             if (DEBUG_STATES) {
                 Slog.w(TAG, "Can't report activity position update - client not running"
                                 + ", activityRecord=" + this);
             }
-            return;
+            return false;
         }
         try {
             if (DEBUG_STATES) {
@@ -710,7 +710,9 @@
                     TopResumedActivityChangeItem.obtain(onTop));
         } catch (RemoteException e) {
             // If process died, whatever.
+            return false;
         }
+        return true;
     }
 
     void updateMultiWindowMode() {
@@ -863,7 +865,7 @@
             name = intent.getComponent().flattenToShortString();
         }
 
-        private static ActivityRecord tokenToActivityRecordLocked(Token token) {
+        private static @Nullable ActivityRecord tokenToActivityRecordLocked(Token token) {
             if (token == null) {
                 return null;
             }
@@ -891,7 +893,7 @@
         }
     }
 
-    static ActivityRecord forTokenLocked(IBinder token) {
+    static @Nullable ActivityRecord forTokenLocked(IBinder token) {
         try {
             return Token.tokenToActivityRecordLocked((Token)token);
         } catch (ClassCastException e) {
@@ -2127,10 +2129,13 @@
     static void activityResumedLocked(IBinder token) {
         final ActivityRecord r = ActivityRecord.forTokenLocked(token);
         if (DEBUG_SAVED_STATE) Slog.i(TAG_STATES, "Resumed activity; dropping state of: " + r);
-        if (r != null) {
-            r.icicle = null;
-            r.haveState = false;
+        if (r == null) {
+            // If an app reports resumed after a long delay, the record on server side might have
+            // been removed (e.g. destroy timeout), so the token could be null.
+            return;
         }
+        r.icicle = null;
+        r.haveState = false;
 
         final ActivityDisplay display = r.getDisplay();
         if (display != null) {
@@ -3405,7 +3410,6 @@
             transaction.addCallback(callbackItem);
             transaction.setLifecycleStateRequest(lifecycleItem);
             mAtmService.getLifecycleManager().scheduleTransaction(transaction);
-            mStackSupervisor.updateTopResumedActivityIfNeeded();
             // Note: don't need to call pauseIfSleepingLocked() here, because the caller will only
             // request resume if this activity is currently resumed, which implies we aren't
             // sleeping.
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index e0890a6..419f5be 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -1500,7 +1500,6 @@
                 + " callers=" + Debug.getCallers(5));
         r.setState(RESUMED, "minimalResumeActivityLocked");
         r.completeResumeLocked();
-        mStackSupervisor.updateTopResumedActivityIfNeeded();
         if (DEBUG_SAVED_STATE) Slog.i(TAG_SAVED_STATE,
                 "Launch completed; removing icicle of " + r.icicle);
     }
@@ -1804,7 +1803,7 @@
             if (prev.finishing) {
                 if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Executing finish of activity: " + prev);
                 prev = finishCurrentActivityLocked(prev, FINISH_AFTER_VISIBLE, false,
-                        "completedPausedLocked");
+                        "completePausedLocked");
             } else if (prev.hasProcess()) {
                 if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Enqueue pending stop if needed: " + prev
                         + " wasStopping=" + wasStopping + " visible=" + prev.visible);
@@ -2571,7 +2570,6 @@
             // Protect against recursion.
             mInResumeTopActivity = true;
             result = resumeTopActivityInnerLocked(prev, options);
-            mStackSupervisor.updateTopResumedActivityIfNeeded();
 
             // When resuming the top activity, it may be necessary to pause the top activity (for
             // example, returning to the lock screen. We suppress the normal pause logic in
@@ -2606,6 +2604,7 @@
         if (DEBUG_STACK) Slog.d(TAG_STACK, "setResumedActivity stack:" + this + " + from: "
                 + mResumedActivity + " to:" + r + " reason:" + reason);
         mResumedActivity = r;
+        mStackSupervisor.updateTopResumedActivityIfNeeded();
     }
 
     @GuardedBy("mService")
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 53dc1df..afdbd73 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -853,7 +853,6 @@
 
                 // Schedule transaction.
                 mService.getLifecycleManager().scheduleTransaction(clientTransaction);
-                updateTopResumedActivityIfNeeded();
 
                 if ((proc.mInfo.privateFlags & ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE) != 0
                         && mService.mHasHeavyWeightFeature) {
@@ -2321,8 +2320,8 @@
         // mTopResumedActivityWaitingForPrev == true at this point would mean that an activity
         // before the prevTopActivity one hasn't reported back yet. So server never sent the top
         // resumed state change message to prevTopActivity.
-        if (prevActivityReceivedTopState) {
-            prevTopActivity.scheduleTopResumedActivityChanged(false /* onTop */);
+        if (prevActivityReceivedTopState
+                && prevTopActivity.scheduleTopResumedActivityChanged(false /* onTop */)) {
             scheduleTopResumedStateLossTimeout(prevTopActivity);
             mTopResumedActivityWaitingForPrev = true;
         }
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/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index 4a0831e..7714458 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -104,7 +104,8 @@
     private int mMinVisibleWidth;
     private int mMinVisibleHeight;
 
-    private Task mTask;
+    @VisibleForTesting
+    Task mTask;
     private boolean mResizing;
     private boolean mPreserveOrientation;
     private boolean mStartOrientationWasLandscape;
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/core/java/com/android/server/wm/WindowAnimationSpec.java b/services/core/java/com/android/server/wm/WindowAnimationSpec.java
index 57311e1..d8ebd84 100644
--- a/services/core/java/com/android/server/wm/WindowAnimationSpec.java
+++ b/services/core/java/com/android/server/wm/WindowAnimationSpec.java
@@ -98,14 +98,25 @@
         tmp.transformation.getMatrix().postTranslate(mPosition.x, mPosition.y);
         t.setMatrix(leash, tmp.transformation.getMatrix(), tmp.floats);
         t.setAlpha(leash, tmp.transformation.getAlpha());
-        if (mStackClipMode == STACK_CLIP_NONE || mStackClipMode == STACK_CLIP_AFTER_ANIM) {
-            t.setWindowCrop(leash, tmp.transformation.getClipRect());
+
+        boolean cropSet = false;
+        if (mStackClipMode == STACK_CLIP_NONE) {
+            if (tmp.transformation.hasClipRect()) {
+                t.setWindowCrop(leash, tmp.transformation.getClipRect());
+                cropSet = true;
+            }
         } else {
             mTmpRect.set(mStackBounds);
-            mTmpRect.intersect(tmp.transformation.getClipRect());
+            if (tmp.transformation.hasClipRect()) {
+                mTmpRect.intersect(tmp.transformation.getClipRect());
+            }
             t.setWindowCrop(leash, mTmpRect);
+            cropSet = true;
         }
-        if (mAnimation.hasRoundedCorners() && mWindowCornerRadius > 0) {
+
+        // We can only apply rounded corner if a crop is set, as otherwise the value is meaningless,
+        // since it doesn't have anything it's relative to.
+        if (cropSet && mAnimation.hasRoundedCorners() && mWindowCornerRadius > 0) {
             t.setCornerRadius(leash, mWindowCornerRadius);
         }
     }
diff --git a/services/net/java/android/net/ip/IIpClient.aidl b/services/net/java/android/net/ip/IIpClient.aidl
index b834e45..1e77264 100644
--- a/services/net/java/android/net/ip/IIpClient.aidl
+++ b/services/net/java/android/net/ip/IIpClient.aidl
@@ -32,4 +32,5 @@
     void setMulticastFilter(boolean enabled);
     void addKeepalivePacketFilter(int slot, in TcpKeepalivePacketDataParcelable pkt);
     void removeKeepalivePacketFilter(int slot);
+    void setL2KeyAndGroupHint(in String l2Key, in String groupHint);
 }
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index fce7599..01f2f6b 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -68,6 +68,7 @@
     <uses-permission android:name="android.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS" />
     <uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
     <uses-permission android:name="android.permission.WRITE_DEVICE_CONFIG" />
+    <uses-permission android:name="android.permission.HARDWARE_TEST"/>
 
     <!-- Uses API introduced in O (26) -->
     <uses-sdk android:minSdkVersion="1"
diff --git a/services/tests/servicestests/src/com/android/server/display/color/DisplayTransformManagerTest.java b/services/tests/servicestests/src/com/android/server/display/color/DisplayTransformManagerTest.java
new file mode 100644
index 0000000..fc74c97
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/display/color/DisplayTransformManagerTest.java
@@ -0,0 +1,102 @@
+/*
+ * 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.display.color;
+
+import static com.android.server.display.color.DisplayTransformManager.LEVEL_COLOR_MATRIX_NIGHT_DISPLAY;
+import static com.android.server.display.color.DisplayTransformManager.PERSISTENT_PROPERTY_DISPLAY_COLOR;
+import static com.android.server.display.color.DisplayTransformManager.PERSISTENT_PROPERTY_SATURATION;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.hardware.display.ColorDisplayManager;
+import android.os.SystemProperties;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class DisplayTransformManagerTest {
+
+    private DisplayTransformManager mDtm;
+    private float[] mNightDisplayMatrix;
+
+    @Before
+    public void setUp() {
+        mDtm = new DisplayTransformManager();
+        mNightDisplayMatrix = mDtm.getColorMatrix(LEVEL_COLOR_MATRIX_NIGHT_DISPLAY);
+
+        SystemProperties.set(PERSISTENT_PROPERTY_DISPLAY_COLOR, null);
+        SystemProperties.set(PERSISTENT_PROPERTY_SATURATION, null);
+    }
+
+    @Test
+    public void setColorMode_natural() {
+        mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL, mNightDisplayMatrix);
+        assertThat(SystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR, null))
+                .isEqualTo("0" /* managed */);
+        assertThat(SystemProperties.get(PERSISTENT_PROPERTY_SATURATION, null))
+                .isEqualTo("1.0" /* natural */);
+    }
+
+    @Test
+    public void setColorMode_boosted() {
+        mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_BOOSTED, mNightDisplayMatrix);
+        assertThat(SystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR, null))
+                .isEqualTo("0" /* managed */);
+        assertThat(SystemProperties.get(PERSISTENT_PROPERTY_SATURATION, null))
+                .isEqualTo("1.1" /* boosted */);
+    }
+
+    @Test
+    public void setColorMode_saturated() {
+        mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_SATURATED, mNightDisplayMatrix);
+        assertThat(SystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR, null))
+                .isEqualTo("1" /* unmanaged */);
+        assertThat(SystemProperties.get(PERSISTENT_PROPERTY_SATURATION, null))
+                .isEqualTo("1.0" /* natural */);
+    }
+
+    @Test
+    public void setColorMode_automatic() {
+        mDtm.setColorMode(ColorDisplayManager.COLOR_MODE_AUTOMATIC, mNightDisplayMatrix);
+        assertThat(SystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR, null))
+                .isEqualTo("2" /* enhanced */);
+        assertThat(SystemProperties.get(PERSISTENT_PROPERTY_SATURATION, null))
+                .isEqualTo("1.0" /* natural */);
+    }
+
+    @Test
+    public void setColorMode_vendor() {
+        mDtm.setColorMode(0x100, mNightDisplayMatrix);
+        assertThat(SystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR, null))
+                .isEqualTo(Integer.toString(0x100) /* pass-through */);
+        assertThat(SystemProperties.get(PERSISTENT_PROPERTY_SATURATION, null))
+                .isEqualTo("1.0" /* default */);
+    }
+
+    @Test
+    public void setColorMode_outOfBounds() {
+        mDtm.setColorMode(0x50, mNightDisplayMatrix);
+        assertThat(SystemProperties.get(PERSISTENT_PROPERTY_DISPLAY_COLOR, null))
+                .isEqualTo("" /* default */);
+        assertThat(SystemProperties.get(PERSISTENT_PROPERTY_SATURATION, null))
+                .isEqualTo("" /* default */);
+    }
+}
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/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index ca7a71e..bafcd5f 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -71,8 +71,10 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.AppOpsManager;
+import android.app.AutomaticZenRule;
 import android.app.IActivityManager;
 import android.app.INotificationManager;
 import android.app.ITransientNotification;
@@ -117,6 +119,7 @@
 import android.service.notification.NotificationStats;
 import android.service.notification.NotifyingApp;
 import android.service.notification.StatusBarNotification;
+import android.service.notification.ZenPolicy;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableContext;
@@ -2887,7 +2890,7 @@
     }
 
     @Test
-    public void testApplyEnqueuedAdjustmentFromAssistant_importance_onTime() throws Exception {
+    public void testApplyEnqueuedAdjustmentFromAssistant_importance() throws Exception {
         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
         mService.addEnqueuedNotification(r);
         NotificationManagerService.WorkerHandler handler = mock(
@@ -2905,25 +2908,6 @@
     }
 
     @Test
-    public void testApplyEnqueuedAdjustmentFromAssistant_importance_tooLate() throws Exception {
-        final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
-        mService.addNotification(r);
-        NotificationManagerService.WorkerHandler handler = mock(
-                NotificationManagerService.WorkerHandler.class);
-        mService.setHandler(handler);
-        when(mAssistants.isSameUser(eq(null), anyInt())).thenReturn(true);
-
-        Bundle signals = new Bundle();
-        signals.putInt(KEY_IMPORTANCE, IMPORTANCE_LOW);
-        Adjustment adjustment = new Adjustment(
-                r.sbn.getPackageName(), r.getKey(), signals, "", r.getUser().getIdentifier());
-        mBinderService.applyEnqueuedAdjustmentFromAssistant(null, adjustment);
-
-        assertEquals(IMPORTANCE_DEFAULT, r.getImportance());
-        assertFalse(r.hasAdjustment(KEY_IMPORTANCE));
-    }
-
-    @Test
     public void testApplyEnqueuedAdjustmentFromAssistant_crossUser() throws Exception {
         final NotificationRecord r = generateNotificationRecord(mTestNotificationChannel);
         mService.addEnqueuedNotification(r);
@@ -4305,6 +4289,36 @@
     }
 
     @Test
+    public void testFlagBubble() throws RemoteException {
+        // Bubbles are allowed!
+        mService.setPreferencesHelper(mPreferencesHelper);
+        when(mPreferencesHelper.areBubblesAllowed(anyString(), anyInt())).thenReturn(true);
+        when(mPreferencesHelper.getNotificationChannel(
+                anyString(), anyInt(), anyString(), anyBoolean())).thenReturn(
+                mTestNotificationChannel);
+        when(mPreferencesHelper.getImportance(anyString(), anyInt())).thenReturn(
+                mTestNotificationChannel.getImportance());
+
+        // Notif with bubble metadata but not our other misc requirements
+        NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel,
+                null /* tvExtender */, true /* isBubble */);
+
+        // Say we're foreground
+        when(mActivityManager.getPackageImportance(nr.sbn.getPackageName())).thenReturn(
+                IMPORTANCE_FOREGROUND);
+
+        mBinderService.enqueueNotificationWithTag(PKG, PKG, "tag",
+                nr.sbn.getId(), nr.sbn.getNotification(), nr.sbn.getUserId());
+        waitForIdle();
+
+        StatusBarNotification[] notifs = mBinderService.getActiveNotifications(PKG);
+        assertEquals(1, notifs.length);
+        assertTrue((notifs[0].getNotification().flags & FLAG_BUBBLE) != 0);
+        assertTrue(mService.getNotificationRecord(
+                nr.sbn.getKey()).getNotification().isBubbleNotification());
+    }
+
+    @Test
     public void testFlagBubbleNotifs_flag_appForeground() throws RemoteException {
         // Bubbles are allowed!
         mService.setPreferencesHelper(mPreferencesHelper);
@@ -4967,6 +4981,29 @@
         assertEquals(USER_SENTIMENT_NEUTRAL, r.getUserSentiment());
     }
 
+    public void testAutomaticZenRuleValidation_policyFilterAgreement() throws Exception {
+        ComponentName owner = mock(ComponentName.class);
+        ZenPolicy zenPolicy = new ZenPolicy.Builder().allowAlarms(true).build();
+        boolean isEnabled = true;
+        AutomaticZenRule rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class),
+                zenPolicy, NotificationManager.INTERRUPTION_FILTER_NONE, isEnabled);
+
+        try {
+            mBinderService.addAutomaticZenRule(rule);
+            fail("Zen policy only aplies to priority only mode");
+        } catch (IllegalArgumentException e) {
+            // yay
+        }
+
+        rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class),
+                zenPolicy, NotificationManager.INTERRUPTION_FILTER_PRIORITY, isEnabled);
+        mBinderService.addAutomaticZenRule(rule);
+
+        rule = new AutomaticZenRule("test", owner, owner, mock(Uri.class),
+                null, NotificationManager.INTERRUPTION_FILTER_NONE, isEnabled);
+        mBinderService.addAutomaticZenRule(rule);
+    }
+
     public void testAreNotificationsEnabledForPackage_crossUser() throws Exception {
         try {
             mBinderService.areNotificationsEnabledForPackage(mContext.getPackageName(),
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/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java
index 2377df4..9cdb465 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskPositionerTests.java
@@ -19,16 +19,14 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.server.wm.TaskPositioner.MIN_ASPECT;
 import static com.android.server.wm.WindowManagerService.dipToPixel;
 import static com.android.server.wm.WindowState.MINIMUM_VISIBLE_HEIGHT_IN_DP;
 import static com.android.server.wm.WindowState.MINIMUM_VISIBLE_WIDTH_IN_DP;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 
@@ -39,9 +37,9 @@
 import android.util.Log;
 import android.view.Display;
 
-import androidx.test.filters.FlakyTest;
 import androidx.test.filters.SmallTest;
 
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
@@ -53,7 +51,6 @@
  */
 @SmallTest
 @Presubmit
-@FlakyTest
 public class TaskPositionerTests extends WindowTestsBase {
 
     private static final boolean DEBUGGING = false;
@@ -66,10 +63,9 @@
     private int mMinVisibleHeight;
     private TaskPositioner mPositioner;
     private WindowState mWindow;
-    private Rect mDimBounds = new Rect();
 
     @Before
-    public void setUp() throws Exception {
+    public void setUp() {
         TaskPositioner.setFactory(null);
 
         final Display display = mDisplayContent.getDisplay();
@@ -84,17 +80,16 @@
         mPositioner.register(mDisplayContent);
 
         mWindow = createWindow(null, TYPE_BASE_APPLICATION, "window");
-        final Task task = mWindow.getTask();
-        spyOn(task);
-        doAnswer(invocation -> {
-            final Rect rect = (Rect) invocation.getArguments()[0];
-            rect.set(mDimBounds);
-            return null;
-        }).when(task).getDimBounds(any(Rect.class));
-
+        mPositioner.mTask = mWindow.getTask();
         mWindow.getStack().setWindowingMode(WINDOWING_MODE_FREEFORM);
     }
 
+    @After
+    public void tearDown() {
+        mWindow = null;
+        mPositioner = null;
+    }
+
     @Test
     public void testOverrideFactory() {
         final boolean[] created = new boolean[1];
@@ -119,11 +114,11 @@
     public void testBasicFreeWindowResizing() {
         final Rect r = new Rect(100, 220, 700, 520);
         final int midY = (r.top + r.bottom) / 2;
-        mDimBounds.set(r);
+        mPositioner.mTask.setBounds(r, true);
 
         // Start a drag resize starting upper left.
-        mPositioner.startDrag(mWindow, true /*resizing*/,
-                false /*preserveOrientation*/, r.left - MOUSE_DELTA_X, r.top - MOUSE_DELTA_Y);
+        mPositioner.startDrag(mWindow, true /* resizing */,
+                false /* preserveOrientation */, r.left - MOUSE_DELTA_X, r.top - MOUSE_DELTA_Y);
         assertBoundsEquals(r, mPositioner.getWindowDragBounds());
 
         // Drag to a good landscape size.
@@ -149,8 +144,8 @@
                 mPositioner.getWindowDragBounds());
 
         // Start a drag resize left and see that only the left coord changes..
-        mPositioner.startDrag(mWindow, true /*resizing*/,
-                false /*preserveOrientation*/, r.left - MOUSE_DELTA_X, midY);
+        mPositioner.startDrag(mWindow, true /* resizing */,
+                false /* preserveOrientation */, r.left - MOUSE_DELTA_X, midY);
 
         // Drag to the left.
         mPositioner.resizeDrag(0.0f, midY);
@@ -181,77 +176,77 @@
         final Rect r = new Rect(100, 220, 700, 520);
         final int midX = (r.left + r.right) / 2;
         final int midY = (r.top + r.bottom) / 2;
-        mDimBounds.set(r);
+        mPositioner.mTask.setBounds(r, true);
 
         // Drag upper left.
-        mPositioner.startDrag(mWindow, true /*resizing*/,
-                false /*preserveOrientation*/, r.left - MOUSE_DELTA_X, r.top - MOUSE_DELTA_Y);
+        mPositioner.startDrag(mWindow, true /* resizing */,
+                false /* preserveOrientation */, r.left - MOUSE_DELTA_X, r.top - MOUSE_DELTA_Y);
         mPositioner.resizeDrag(0.0f, 0.0f);
-        assertTrue(r.left != mPositioner.getWindowDragBounds().left);
+        assertNotEquals(r.left, mPositioner.getWindowDragBounds().left);
         assertEquals(r.right, mPositioner.getWindowDragBounds().right);
-        assertTrue(r.top != mPositioner.getWindowDragBounds().top);
+        assertNotEquals(r.top, mPositioner.getWindowDragBounds().top);
         assertEquals(r.bottom, mPositioner.getWindowDragBounds().bottom);
 
         // Drag upper.
-        mPositioner.startDrag(mWindow, true /*resizing*/,
-                false /*preserveOrientation*/, midX, r.top - MOUSE_DELTA_Y);
+        mPositioner.startDrag(mWindow, true /* resizing */,
+                false /* preserveOrientation */, midX, r.top - MOUSE_DELTA_Y);
         mPositioner.resizeDrag(0.0f, 0.0f);
         assertEquals(r.left, mPositioner.getWindowDragBounds().left);
         assertEquals(r.right, mPositioner.getWindowDragBounds().right);
-        assertTrue(r.top != mPositioner.getWindowDragBounds().top);
+        assertNotEquals(r.top, mPositioner.getWindowDragBounds().top);
         assertEquals(r.bottom, mPositioner.getWindowDragBounds().bottom);
 
         // Drag upper right.
-        mPositioner.startDrag(mWindow, true /*resizing*/,
-                false /*preserveOrientation*/, r.right + MOUSE_DELTA_X, r.top - MOUSE_DELTA_Y);
+        mPositioner.startDrag(mWindow, true /* resizing */,
+                false /* preserveOrientation */, r.right + MOUSE_DELTA_X, r.top - MOUSE_DELTA_Y);
         mPositioner.resizeDrag(r.right + 100, 0.0f);
         assertEquals(r.left, mPositioner.getWindowDragBounds().left);
-        assertTrue(r.right != mPositioner.getWindowDragBounds().right);
-        assertTrue(r.top != mPositioner.getWindowDragBounds().top);
+        assertNotEquals(r.right, mPositioner.getWindowDragBounds().right);
+        assertNotEquals(r.top, mPositioner.getWindowDragBounds().top);
         assertEquals(r.bottom, mPositioner.getWindowDragBounds().bottom);
 
         // Drag right.
-        mPositioner.startDrag(mWindow, true /*resizing*/,
-                false /*preserveOrientation*/, r.right + MOUSE_DELTA_X, midY);
+        mPositioner.startDrag(mWindow, true /* resizing */,
+                false /* preserveOrientation */, r.right + MOUSE_DELTA_X, midY);
         mPositioner.resizeDrag(r.right + 100, 0.0f);
         assertEquals(r.left, mPositioner.getWindowDragBounds().left);
-        assertTrue(r.right != mPositioner.getWindowDragBounds().right);
+        assertNotEquals(r.right, mPositioner.getWindowDragBounds().right);
         assertEquals(r.top, mPositioner.getWindowDragBounds().top);
         assertEquals(r.bottom, mPositioner.getWindowDragBounds().bottom);
 
         // Drag bottom right.
-        mPositioner.startDrag(mWindow, true /*resizing*/,
-                false /*preserveOrientation*/,
+        mPositioner.startDrag(mWindow, true /* resizing */,
+                false /* preserveOrientation */,
                 r.right + MOUSE_DELTA_X, r.bottom + MOUSE_DELTA_Y);
         mPositioner.resizeDrag(r.right + 100, r.bottom + 100);
         assertEquals(r.left, mPositioner.getWindowDragBounds().left);
-        assertTrue(r.right != mPositioner.getWindowDragBounds().right);
+        assertNotEquals(r.right, mPositioner.getWindowDragBounds().right);
         assertEquals(r.top, mPositioner.getWindowDragBounds().top);
-        assertTrue(r.bottom != mPositioner.getWindowDragBounds().bottom);
+        assertNotEquals(r.bottom, mPositioner.getWindowDragBounds().bottom);
 
         // Drag bottom.
-        mPositioner.startDrag(mWindow, true /*resizing*/,
-                false /*preserveOrientation*/, midX, r.bottom + MOUSE_DELTA_Y);
+        mPositioner.startDrag(mWindow, true /* resizing */,
+                false /* preserveOrientation */, midX, r.bottom + MOUSE_DELTA_Y);
         mPositioner.resizeDrag(r.right + 100, r.bottom + 100);
         assertEquals(r.left, mPositioner.getWindowDragBounds().left);
         assertEquals(r.right, mPositioner.getWindowDragBounds().right);
         assertEquals(r.top, mPositioner.getWindowDragBounds().top);
-        assertTrue(r.bottom != mPositioner.getWindowDragBounds().bottom);
+        assertNotEquals(r.bottom, mPositioner.getWindowDragBounds().bottom);
 
         // Drag bottom left.
-        mPositioner.startDrag(mWindow, true /*resizing*/,
-                false /*preserveOrientation*/, r.left - MOUSE_DELTA_X, r.bottom + MOUSE_DELTA_Y);
+        mPositioner.startDrag(mWindow, true /* resizing */,
+                false /* preserveOrientation */, r.left - MOUSE_DELTA_X, r.bottom + MOUSE_DELTA_Y);
         mPositioner.resizeDrag(0.0f, r.bottom + 100);
-        assertTrue(r.left != mPositioner.getWindowDragBounds().left);
+        assertNotEquals(r.left, mPositioner.getWindowDragBounds().left);
         assertEquals(r.right, mPositioner.getWindowDragBounds().right);
         assertEquals(r.top, mPositioner.getWindowDragBounds().top);
-        assertTrue(r.bottom != mPositioner.getWindowDragBounds().bottom);
+        assertNotEquals(r.bottom, mPositioner.getWindowDragBounds().bottom);
 
         // Drag left.
-        mPositioner.startDrag(mWindow, true /*resizing*/,
-                false /*preserveOrientation*/, r.left - MOUSE_DELTA_X, midX);
+        mPositioner.startDrag(mWindow, true /* resizing */,
+                false /* preserveOrientation */, r.left - MOUSE_DELTA_X, midY);
         mPositioner.resizeDrag(0.0f, r.bottom + 100);
-        assertTrue(r.left != mPositioner.getWindowDragBounds().left);
+        assertNotEquals(r.left, mPositioner.getWindowDragBounds().left);
         assertEquals(r.right, mPositioner.getWindowDragBounds().right);
         assertEquals(r.top, mPositioner.getWindowDragBounds().top);
         assertEquals(r.bottom, mPositioner.getWindowDragBounds().bottom);
@@ -264,10 +259,10 @@
     @Test
     public void testLandscapePreservedWindowResizingDragTopLeft() {
         final Rect r = new Rect(100, 220, 700, 520);
-        mDimBounds.set(r);
+        mPositioner.mTask.setBounds(r, true);
 
-        mPositioner.startDrag(mWindow, true /*resizing*/,
-                true /*preserveOrientation*/, r.left - MOUSE_DELTA_X, r.top - MOUSE_DELTA_Y);
+        mPositioner.startDrag(mWindow, true /* resizing */,
+                true /* preserveOrientation */, r.left - MOUSE_DELTA_X, r.top - MOUSE_DELTA_Y);
         assertBoundsEquals(r, mPositioner.getWindowDragBounds());
 
         // Drag to a good landscape size.
@@ -303,10 +298,10 @@
     public void testLandscapePreservedWindowResizingDragLeft() {
         final Rect r = new Rect(100, 220, 700, 520);
         final int midY = (r.top + r.bottom) / 2;
-        mDimBounds.set(r);
+        mPositioner.mTask.setBounds(r, true);
 
-        mPositioner.startDrag(mWindow, true /*resizing*/,
-                true /*preserveOrientation*/, r.left - MOUSE_DELTA_X, midY);
+        mPositioner.startDrag(mWindow, true /* resizing */,
+                true /* preserveOrientation */, r.left - MOUSE_DELTA_X, midY);
 
         // Drag to the left.
         mPositioner.resizeDrag(0.0f, midY);
@@ -344,7 +339,7 @@
     public void testLandscapePreservedWindowResizingDragTop() {
         final Rect r = new Rect(100, 220, 700, 520);
         final int midX = (r.left + r.right) / 2;
-        mDimBounds.set(r);
+        mPositioner.mTask.setBounds(r, true);
 
         mPositioner.startDrag(mWindow, true /*resizing*/,
                 true /*preserveOrientation*/, midX, r.top - MOUSE_DELTA_Y);
@@ -380,7 +375,7 @@
     @Test
     public void testPortraitPreservedWindowResizingDragTopLeft() {
         final Rect r = new Rect(330, 100, 630, 600);
-        mDimBounds.set(r);
+        mPositioner.mTask.setBounds(r, true);
 
         mPositioner.startDrag(mWindow, true /*resizing*/,
                 true /*preserveOrientation*/, r.left - MOUSE_DELTA_X, r.top - MOUSE_DELTA_Y);
@@ -414,10 +409,10 @@
     public void testPortraitPreservedWindowResizingDragLeft() {
         final Rect r = new Rect(330, 100, 630, 600);
         final int midY = (r.top + r.bottom) / 2;
-        mDimBounds.set(r);
+        mPositioner.mTask.setBounds(r, true);
 
-        mPositioner.startDrag(mWindow, true /*resizing*/,
-                true /*preserveOrientation*/, r.left - MOUSE_DELTA_X, midY);
+        mPositioner.startDrag(mWindow, true /* resizing */,
+                true /* preserveOrientation */, r.left - MOUSE_DELTA_X, midY);
 
         // Drag to the left.
         mPositioner.resizeDrag(0.0f, midY);
@@ -457,10 +452,10 @@
     public void testPortraitPreservedWindowResizingDragTop() {
         final Rect r = new Rect(330, 100, 630, 600);
         final int midX = (r.left + r.right) / 2;
-        mDimBounds.set(r);
+        mPositioner.mTask.setBounds(r, true);
 
-        mPositioner.startDrag(mWindow, true /*resizing*/,
-                true /*preserveOrientation*/, midX, r.top - MOUSE_DELTA_Y);
+        mPositioner.startDrag(mWindow, true /* resizing */,
+                true /* preserveOrientation */, midX, r.top - MOUSE_DELTA_Y);
 
         // Drag to the left (no change).
         mPositioner.resizeDrag(0.0f, r.top);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowAnimationSpecTest.java b/services/tests/wmtests/src/com/android/server/wm/WindowAnimationSpecTest.java
index 897f0a2..0330de8 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowAnimationSpecTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowAnimationSpecTest.java
@@ -22,6 +22,8 @@
 import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_BEFORE_ANIM;
 import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_NONE;
 
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyFloat;
 import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.never;
@@ -70,7 +72,8 @@
                 mStackBounds, false /* canSkipFirstFrame */, STACK_CLIP_AFTER_ANIM,
                 true /* isAppAnimation */, 0 /* windowCornerRadius */);
         windowAnimationSpec.apply(mTransaction, mSurfaceControl, 0);
-        verify(mTransaction).setWindowCrop(eq(mSurfaceControl), argThat(Rect::isEmpty));
+        verify(mTransaction).setWindowCrop(eq(mSurfaceControl),
+                argThat(rect -> rect.equals(mStackBounds)));
     }
 
     @Test
@@ -80,7 +83,8 @@
                 new Point(20, 40), mStackBounds, false /* canSkipFirstFrame */,
                 STACK_CLIP_AFTER_ANIM, true /* isAppAnimation */, 0 /* windowCornerRadius */);
         windowAnimationSpec.apply(mTransaction, mSurfaceControl, 0);
-        verify(mTransaction).setWindowCrop(eq(mSurfaceControl), argThat(Rect::isEmpty));
+        verify(mTransaction).setWindowCrop(eq(mSurfaceControl),
+                argThat(rect -> rect.equals(mStackBounds)));
     }
 
     @Test
@@ -121,6 +125,17 @@
     }
 
     @Test
+    public void testApply_setCornerRadius_noClip() {
+        final float windowCornerRadius = 30f;
+        WindowAnimationSpec windowAnimationSpec = new WindowAnimationSpec(mAnimation, null,
+                mStackBounds, false /* canSkipFirstFrame */, STACK_CLIP_NONE,
+                true /* isAppAnimation */, windowCornerRadius);
+        when(mAnimation.hasRoundedCorners()).thenReturn(true);
+        windowAnimationSpec.apply(mTransaction, mSurfaceControl, 0);
+        verify(mTransaction, never()).setCornerRadius(any(), anyFloat());
+    }
+
+    @Test
     public void testApply_clipBeforeSmallerAnimationClip() {
         // Stack bounds is (0, 0, 10, 10) animation clip is (0, 0, 5, 5)
         Rect windowCrop = new Rect(0, 0, 5, 5);
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index ad1e3ef..4d7ae73 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -1238,6 +1238,9 @@
 
             RoleObserver(@NonNull @CallbackExecutor Executor executor) {
                 mRm.addOnRoleHoldersChangedListenerAsUser(executor, this, UserHandle.ALL);
+                UserHandle currentUser = UserHandle.of(LocalServices.getService(
+                        ActivityManagerInternal.class).getCurrentUserId());
+                onRoleHoldersChanged(RoleManager.ROLE_ASSISTANT, currentUser);
             }
 
             private @NonNull String getDefaultRecognizer(@NonNull UserHandle user) {
@@ -1285,7 +1288,9 @@
                     // Try to set role holder as VoiceInteractionService
                     List<ResolveInfo> services = mPm.queryIntentServicesAsUser(
                             new Intent(VoiceInteractionService.SERVICE_INTERFACE).setPackage(pkg),
-                            PackageManager.GET_META_DATA, userId);
+                            PackageManager.GET_META_DATA
+                                    | PackageManager.MATCH_DIRECT_BOOT_AWARE
+                                    | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
 
                     for (ResolveInfo resolveInfo : services) {
                         ServiceInfo serviceInfo = resolveInfo.serviceInfo;
@@ -1318,7 +1323,9 @@
                     // If no service could be found try to set assist activity
                     final List<ResolveInfo> activities = mPm.queryIntentActivitiesAsUser(
                             new Intent(Intent.ACTION_ASSIST).setPackage(pkg),
-                            PackageManager.MATCH_DEFAULT_ONLY, userId);
+                            PackageManager.MATCH_DEFAULT_ONLY
+                                    | PackageManager.MATCH_DIRECT_BOOT_AWARE
+                                    | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userId);
 
                     for (ResolveInfo resolveInfo : activities) {
                         ActivityInfo activityInfo = resolveInfo.activityInfo;
@@ -1331,6 +1338,7 @@
                         Settings.Secure.putStringForUser(getContext().getContentResolver(),
                                 Settings.Secure.VOICE_RECOGNITION_SERVICE,
                                 getDefaultRecognizer(user), userId);
+                        return;
                     }
                 }
             }
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/telecomm/java/android/telecom/CallRedirectionService.java b/telecomm/java/android/telecom/CallRedirectionService.java
index 37fab09..36c6377 100644
--- a/telecomm/java/android/telecom/CallRedirectionService.java
+++ b/telecomm/java/android/telecom/CallRedirectionService.java
@@ -119,18 +119,18 @@
      * {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)}. The response corresponds to the
      * latest request via {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)}.
      *
-     * @param handle the new phone number to dial
+     * @param gatewayUri the gateway uri for call redirection.
      * @param targetPhoneAccount the {@link PhoneAccountHandle} to use when placing the call.
      * @param confirmFirst Telecom will ask users to confirm the redirection via a yes/no dialog
      *                     if the confirmFirst is true, and if the redirection request of this
      *                     response was sent with a true flag of allowInteractiveResponse via
      *                     {@link #onPlaceCall(Uri, PhoneAccountHandle, boolean)}
      */
-    public final void redirectCall(@NonNull Uri handle,
+    public final void redirectCall(@NonNull Uri gatewayUri,
                                    @NonNull PhoneAccountHandle targetPhoneAccount,
                                    boolean confirmFirst) {
         try {
-            mCallRedirectionAdapter.redirectCall(handle, targetPhoneAccount, confirmFirst);
+            mCallRedirectionAdapter.redirectCall(gatewayUri, targetPhoneAccount, confirmFirst);
         } catch (RemoteException e) {
             e.rethrowAsRuntimeException();
         }
diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java
index 52e0ebd..2d8a8cb 100644
--- a/telephony/java/android/provider/Telephony.java
+++ b/telephony/java/android/provider/Telephony.java
@@ -4321,6 +4321,22 @@
          * @hide
          */
         public static final String IS_USING_CARRIER_AGGREGATION = "is_using_carrier_aggregation";
+
+        /**
+         * The current registered raw data network operator name in long alphanumeric format.
+         * <p>
+         * This is the same as {@link ServiceState#getOperatorAlphaLongRaw()}.
+         * @hide
+         */
+        public static final String OPERATOR_ALPHA_LONG_RAW = "operator_alpha_long_raw";
+
+        /**
+         * The current registered raw data network operator name in short alphanumeric format.
+         * <p>
+         * This is the same as {@link ServiceState#getOperatorAlphaShortRaw()}.
+         * @hide
+         */
+        public static final String OPERATOR_ALPHA_SHORT_RAW = "operator_alpha_short_raw";
     }
 
     /**
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 0f8f873..9f6528b 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -1312,6 +1312,24 @@
             "hide_lte_plus_data_icon_bool";
 
     /**
+     * The string is used to filter redundant string from PLMN Network Name that's supplied by
+     * specific carrier.
+     *
+     * @hide
+     */
+    public static final String KEY_OPERATOR_NAME_FILTER_PATTERN_STRING =
+            "operator_name_filter_pattern_string";
+
+    /**
+     * The string is used to compare with operator name. If it matches the pattern then show
+     * specific data icon.
+     *
+     * @hide
+     */
+    public static final String KEY_SHOW_CARRIER_DATA_ICON_PATTERN_STRING =
+            "show_carrier_data_icon_pattern_string";
+
+    /**
      * Boolean to decide whether to show precise call failed cause to user
      * @hide
      */
@@ -2803,6 +2821,19 @@
     public static final String KEY_IS_OPPORTUNISTIC_SUBSCRIPTION_BOOL =
             "key_is_opportunistic_subscription_bool";
 
+    /**
+     * A list of 4 GSM RSSI thresholds above which a signal level is considered POOR,
+     * MODERATE, GOOD, or EXCELLENT, to be used in SignalStrength reporting.
+     *
+     * Note that the min and max thresholds are fixed at -113 and -51, as set in 3GPP TS 27.007
+     * section 8.5.
+     * <p>
+     * See CellSignalStrengthGsm#GSM_RSSI_MAX and CellSignalStrengthGsm#GSM_RSSI_MIN. Any signal
+     * level outside these boundaries is considered invalid.
+     * @hide
+     */
+    public static final String KEY_GSM_RSSI_THRESHOLDS_INT_ARRAY =
+            "gsm_rssi_thresholds_int_array";
 
     /** The default value for every variable. */
     private final static PersistableBundle sDefaults;
@@ -3139,6 +3170,8 @@
         sDefaults.putBoolean(KEY_SPN_DISPLAY_RULE_USE_ROAMING_FROM_SERVICE_STATE_BOOL, false);
         sDefaults.putBoolean(KEY_ALWAYS_SHOW_DATA_RAT_ICON_BOOL, false);
         sDefaults.putBoolean(KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL, false);
+        sDefaults.putString(KEY_OPERATOR_NAME_FILTER_PATTERN_STRING, "");
+        sDefaults.putString(KEY_SHOW_CARRIER_DATA_ICON_PATTERN_STRING, "");
         sDefaults.putBoolean(KEY_HIDE_LTE_PLUS_DATA_ICON_BOOL, true);
         sDefaults.putBoolean(KEY_LTE_ENABLED_BOOL, true);
         sDefaults.putBoolean(KEY_SUPPORT_TDSCDMA_BOOL, false);
@@ -3204,6 +3237,13 @@
                 false);
         sDefaults.putString(KEY_SUBSCRIPTION_GROUP_UUID_STRING, "");
         sDefaults.putBoolean(KEY_IS_OPPORTUNISTIC_SUBSCRIPTION_BOOL, false);
+        sDefaults.putIntArray(KEY_GSM_RSSI_THRESHOLDS_INT_ARRAY,
+                new int[] {
+                        -107, /* SIGNAL_STRENGTH_POOR */
+                        -103, /* SIGNAL_STRENGTH_MODERATE */
+                        -97, /* SIGNAL_STRENGTH_GOOD */
+                        -89,  /* SIGNAL_STRENGTH_GREAT */
+                });
     }
 
     /**
diff --git a/telephony/java/android/telephony/CellIdentity.java b/telephony/java/android/telephony/CellIdentity.java
index 3745277..3087516 100644
--- a/telephony/java/android/telephony/CellIdentity.java
+++ b/telephony/java/android/telephony/CellIdentity.java
@@ -49,10 +49,10 @@
 
     // long alpha Operator Name String or Enhanced Operator Name String
     /** @hide */
-    protected final String mAlphaLong;
+    protected String mAlphaLong;
     // short alpha Operator Name String or Enhanced Operator Name String
     /** @hide */
-    protected final String mAlphaShort;
+    protected String mAlphaShort;
 
     /** @hide */
     protected CellIdentity(String tag, int type, String mcc, String mnc, String alphal,
@@ -145,6 +145,13 @@
     }
 
     /**
+     * @hide
+     */
+    public void setOperatorAlphaLong(String alphaLong) {
+        mAlphaLong = alphaLong;
+    }
+
+    /**
      * @return The short alpha tag associated with the current scan result (may be the operator
      * name string or extended operator name string).  May be null if unknown.
      */
@@ -154,6 +161,13 @@
     }
 
     /**
+     * @hide
+     */
+    public void setOperatorAlphaShort(String alphaShort) {
+        mAlphaShort = alphaShort;
+    }
+
+    /**
      * @return a CellLocation object for this CellIdentity
      * @hide
      */
diff --git a/telephony/java/android/telephony/CellIdentityGsm.java b/telephony/java/android/telephony/CellIdentityGsm.java
index 5e44bf2..864540d 100644
--- a/telephony/java/android/telephony/CellIdentityGsm.java
+++ b/telephony/java/android/telephony/CellIdentityGsm.java
@@ -166,6 +166,7 @@
     /**
      * @return Mobile Country Code in string format, null if unavailable.
      */
+    @Nullable
     public String getMccString() {
         return mMccStr;
     }
@@ -173,6 +174,7 @@
     /**
      * @return Mobile Network Code in string format, null if unavailable.
      */
+    @Nullable
     public String getMncString() {
         return mMncStr;
     }
diff --git a/telephony/java/android/telephony/CellIdentityLte.java b/telephony/java/android/telephony/CellIdentityLte.java
index 2dd72d6..14503c7 100644
--- a/telephony/java/android/telephony/CellIdentityLte.java
+++ b/telephony/java/android/telephony/CellIdentityLte.java
@@ -187,6 +187,7 @@
     /**
      * @return Mobile Country Code in string format, null if unavailable.
      */
+    @Nullable
     public String getMccString() {
         return mMccStr;
     }
@@ -194,6 +195,7 @@
     /**
      * @return Mobile Network Code in string format, null if unavailable.
      */
+    @Nullable
     public String getMncString() {
         return mMncStr;
     }
diff --git a/telephony/java/android/telephony/CellIdentityTdscdma.java b/telephony/java/android/telephony/CellIdentityTdscdma.java
index a591bd1..937de70 100644
--- a/telephony/java/android/telephony/CellIdentityTdscdma.java
+++ b/telephony/java/android/telephony/CellIdentityTdscdma.java
@@ -104,6 +104,7 @@
      * Get Mobile Country Code in string format
      * @return Mobile Country Code in string format, null if unknown
      */
+    @Nullable
     public String getMccString() {
         return mMccStr;
     }
@@ -112,6 +113,7 @@
      * Get Mobile Network Code in string format
      * @return Mobile Network Code in string format, null if unknown
      */
+    @Nullable
     public String getMncString() {
         return mMncStr;
     }
diff --git a/telephony/java/android/telephony/CellIdentityWcdma.java b/telephony/java/android/telephony/CellIdentityWcdma.java
index 674c40c..b4a2ead 100644
--- a/telephony/java/android/telephony/CellIdentityWcdma.java
+++ b/telephony/java/android/telephony/CellIdentityWcdma.java
@@ -150,6 +150,7 @@
     /**
      * @return Mobile Country Code in string version, null if unavailable.
      */
+    @Nullable
     public String getMccString() {
         return mMccStr;
     }
@@ -157,6 +158,7 @@
     /**
      * @return Mobile Network Code in string version, null if unavailable.
      */
+    @Nullable
     public String getMncString() {
         return mMncStr;
     }
diff --git a/telephony/java/android/telephony/CellInfoCdma.java b/telephony/java/android/telephony/CellInfoCdma.java
index a4570e4..30b131f 100644
--- a/telephony/java/android/telephony/CellInfoCdma.java
+++ b/telephony/java/android/telephony/CellInfoCdma.java
@@ -16,6 +16,7 @@
 
 package android.telephony;
 
+import android.annotation.NonNull;
 import android.annotation.UnsupportedAppUsage;
 import android.os.Build;
 import android.os.Parcel;
@@ -76,18 +77,25 @@
                 new CellSignalStrengthCdma(cic.signalStrengthCdma, cic.signalStrengthEvdo);
     }
 
+    /**
+     * @return a {@link CellIdentityCdma} instance.
+     */
     @Override
-    public CellIdentityCdma getCellIdentity() {
+    public @NonNull CellIdentityCdma getCellIdentity() {
         return mCellIdentityCdma;
     }
+
     /** @hide */
     @UnsupportedAppUsage
     public void setCellIdentity(CellIdentityCdma cid) {
         mCellIdentityCdma = cid;
     }
 
+    /**
+     * @return a {@link CellSignalStrengthCdma} instance.
+     */
     @Override
-    public CellSignalStrengthCdma getCellSignalStrength() {
+    public @NonNull CellSignalStrengthCdma getCellSignalStrength() {
         return mCellSignalStrengthCdma;
     }
 
diff --git a/telephony/java/android/telephony/CellInfoGsm.java b/telephony/java/android/telephony/CellInfoGsm.java
index ce32bc1..137f97e 100644
--- a/telephony/java/android/telephony/CellInfoGsm.java
+++ b/telephony/java/android/telephony/CellInfoGsm.java
@@ -16,6 +16,7 @@
 
 package android.telephony;
 
+import android.annotation.NonNull;
 import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -71,17 +72,24 @@
         mCellSignalStrengthGsm = new CellSignalStrengthGsm(cig.signalStrengthGsm);
     }
 
+    /**
+     * @return a {@link CellIdentityGsm} instance.
+     */
     @Override
-    public CellIdentityGsm getCellIdentity() {
+    public @NonNull CellIdentityGsm getCellIdentity() {
         return mCellIdentityGsm;
     }
+
     /** @hide */
     public void setCellIdentity(CellIdentityGsm cid) {
         mCellIdentityGsm = cid;
     }
 
+    /**
+     * @return a {@link CellSignalStrengthGsm} instance.
+     */
     @Override
-    public CellSignalStrengthGsm getCellSignalStrength() {
+    public @NonNull CellSignalStrengthGsm getCellSignalStrength() {
         return mCellSignalStrengthGsm;
     }
 
diff --git a/telephony/java/android/telephony/CellInfoLte.java b/telephony/java/android/telephony/CellInfoLte.java
index 01ee20a..da7b7ab 100644
--- a/telephony/java/android/telephony/CellInfoLte.java
+++ b/telephony/java/android/telephony/CellInfoLte.java
@@ -16,6 +16,7 @@
 
 package android.telephony;
 
+import android.annotation.NonNull;
 import android.annotation.UnsupportedAppUsage;
 import android.os.Build;
 import android.os.Parcel;
@@ -79,11 +80,15 @@
         mCellConfig = new CellConfigLte(cil.cellConfig);
     }
 
+    /**
+     * @return a {@link CellIdentityLte} instance.
+     */
     @Override
-    public CellIdentityLte getCellIdentity() {
+    public @NonNull CellIdentityLte getCellIdentity() {
         if (DBG) log("getCellIdentity: " + mCellIdentityLte);
         return mCellIdentityLte;
     }
+
     /** @hide */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     public void setCellIdentity(CellIdentityLte cid) {
@@ -91,8 +96,11 @@
         mCellIdentityLte = cid;
     }
 
+    /**
+     * @return a {@link CellSignalStrengthLte} instance.
+     */
     @Override
-    public CellSignalStrengthLte getCellSignalStrength() {
+    public @NonNull CellSignalStrengthLte getCellSignalStrength() {
         if (DBG) log("getCellSignalStrength: " + mCellSignalStrengthLte);
         return mCellSignalStrengthLte;
     }
diff --git a/telephony/java/android/telephony/CellInfoNr.java b/telephony/java/android/telephony/CellInfoNr.java
index ba4a907..9775abd 100644
--- a/telephony/java/android/telephony/CellInfoNr.java
+++ b/telephony/java/android/telephony/CellInfoNr.java
@@ -43,12 +43,18 @@
         mCellSignalStrength = other.mCellSignalStrength;
     }
 
+    /**
+     * @return a {@link CellIdentityNr} instance.
+     */
     @Override
     @NonNull
     public CellIdentity getCellIdentity() {
         return mCellIdentity;
     }
 
+    /**
+     * @return a {@link CellSignalStrengthNr} instance.
+     */
     @Override
     @NonNull
     public CellSignalStrength getCellSignalStrength() {
diff --git a/telephony/java/android/telephony/CellInfoTdscdma.java b/telephony/java/android/telephony/CellInfoTdscdma.java
index ccafda6..f1305f5 100644
--- a/telephony/java/android/telephony/CellInfoTdscdma.java
+++ b/telephony/java/android/telephony/CellInfoTdscdma.java
@@ -75,6 +75,9 @@
         mCellSignalStrengthTdscdma = new CellSignalStrengthTdscdma(cit.signalStrengthTdscdma);
     }
 
+    /**
+     * @return a {@link CellIdentityTdscdma} instance.
+     */
     @Override
     public @NonNull CellIdentityTdscdma getCellIdentity() {
         return mCellIdentityTdscdma;
@@ -85,6 +88,9 @@
         mCellIdentityTdscdma = cid;
     }
 
+    /**
+     * @return a {@link CellSignalStrengthTdscdma} instance.
+     */
     @Override
     public @NonNull CellSignalStrengthTdscdma getCellSignalStrength() {
         return mCellSignalStrengthTdscdma;
diff --git a/telephony/java/android/telephony/CellInfoWcdma.java b/telephony/java/android/telephony/CellInfoWcdma.java
index 1b32178..ee5fec8 100644
--- a/telephony/java/android/telephony/CellInfoWcdma.java
+++ b/telephony/java/android/telephony/CellInfoWcdma.java
@@ -71,15 +71,22 @@
         mCellSignalStrengthWcdma = new CellSignalStrengthWcdma(ciw.signalStrengthWcdma);
     }
 
+    /**
+     * @return a {@link CellIdentityWcdma} instance.
+     */
     @Override
     public CellIdentityWcdma getCellIdentity() {
         return mCellIdentityWcdma;
     }
+
     /** @hide */
     public void setCellIdentity(CellIdentityWcdma cid) {
         mCellIdentityWcdma = cid;
     }
 
+    /**
+     * @return a {@link CellSignalStrengthWcdma} instance.
+     */
     @Override
     public CellSignalStrengthWcdma getCellSignalStrength() {
         return mCellSignalStrengthWcdma;
diff --git a/telephony/java/android/telephony/CellSignalStrength.java b/telephony/java/android/telephony/CellSignalStrength.java
index 740b970..e65b048ec 100644
--- a/telephony/java/android/telephony/CellSignalStrength.java
+++ b/telephony/java/android/telephony/CellSignalStrength.java
@@ -16,6 +16,7 @@
 
 package android.telephony;
 
+import android.annotation.IntRange;
 import android.os.PersistableBundle;
 
 /**
@@ -57,23 +58,24 @@
     public abstract void setDefaultValues();
 
     /**
-     * Get signal level as an int from 0..4
-     * <p>
-     * @see #SIGNAL_STRENGTH_NONE_OR_UNKNOWN
-     * @see #SIGNAL_STRENGTH_POOR
-     * @see #SIGNAL_STRENGTH_MODERATE
-     * @see #SIGNAL_STRENGTH_GOOD
-     * @see #SIGNAL_STRENGTH_GREAT
+     * Retrieve an abstract level value for the overall signal quality.
+     *
+     * @return a single integer from 0 to 4 representing the general signal quality.
+     *     0 represents very poor or unknown signal quality while 4 represents excellent
+     *     signal quality.
      */
+    @IntRange(from = SIGNAL_STRENGTH_NONE_OR_UNKNOWN, to = SIGNAL_STRENGTH_GREAT)
     public abstract int getLevel();
 
     /**
-     * Get the signal level as an asu value between 0..31, 99 is unknown
+     * Get the technology-specific signal strength in Arbitrary Strength Units, calculated from the
+     * strength of the pilot signal or equivalent.
      */
     public abstract int getAsuLevel();
 
     /**
-     * Get the signal strength as dBm
+     * Get the technology-specific signal strength in dBm, which is the signal strength of the
+     * pilot signal or equivalent.
      */
     public abstract int getDbm();
 
diff --git a/telephony/java/android/telephony/CellSignalStrengthCdma.java b/telephony/java/android/telephony/CellSignalStrengthCdma.java
index 5b19599..1998439 100644
--- a/telephony/java/android/telephony/CellSignalStrengthCdma.java
+++ b/telephony/java/android/telephony/CellSignalStrengthCdma.java
@@ -16,6 +16,7 @@
 
 package android.telephony;
 
+import android.annotation.IntRange;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.PersistableBundle;
@@ -114,13 +115,9 @@
         mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
     }
 
-    /**
-     * Retrieve an abstract level value for the overall signal strength.
-     *
-     * @return a single integer from 0 to 4 representing the general signal quality.
-     *     0 represents very poor signal strength while 4 represents a very strong signal strength.
-     */
+    /** {@inheritDoc} */
     @Override
+    @IntRange(from = SIGNAL_STRENGTH_NONE_OR_UNKNOWN, to = SIGNAL_STRENGTH_GREAT)
     public int getLevel() {
         return mLevel;
     }
diff --git a/telephony/java/android/telephony/CellSignalStrengthGsm.java b/telephony/java/android/telephony/CellSignalStrengthGsm.java
index 0aeb0f6..14ae689 100644
--- a/telephony/java/android/telephony/CellSignalStrengthGsm.java
+++ b/telephony/java/android/telephony/CellSignalStrengthGsm.java
@@ -16,6 +16,7 @@
 
 package android.telephony;
 
+import android.annotation.IntRange;
 import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -37,6 +38,10 @@
     private static final int GSM_RSSI_GOOD = -97;
     private static final int GSM_RSSI_MODERATE = -103;
     private static final int GSM_RSSI_POOR = -107;
+    private static final int GSM_RSSI_MIN = -113;
+
+    private static final int[] sRssiThresholds = new int[] {
+            GSM_RSSI_POOR, GSM_RSSI_MODERATE, GSM_RSSI_GOOD, GSM_RSSI_GREAT};
 
     private int mRssi; // in dBm [-113, -51] or UNAVAILABLE
     @UnsupportedAppUsage
@@ -53,7 +58,7 @@
 
     /** @hide */
     public CellSignalStrengthGsm(int rssi, int ber, int ta) {
-        mRssi = inRangeOrUnavailable(rssi, -113, -51);
+        mRssi = inRangeOrUnavailable(rssi, GSM_RSSI_MIN, GSM_RSSI_MAX);
         mBitErrorRate = inRangeOrUnavailable(ber, 0, 7, 99);
         mTimingAdvance = inRangeOrUnavailable(ta, 0, 219);
         updateLevel(null, null);
@@ -97,13 +102,9 @@
         mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
     }
 
-    /**
-     * Retrieve an abstract level value for the overall signal strength.
-     *
-     * @return a single integer from 0 to 4 representing the general signal quality.
-     *     0 represents very poor signal strength while 4 represents a very strong signal strength.
-     */
+    /** {@inheritDoc} */
     @Override
+    @IntRange(from = SIGNAL_STRENGTH_NONE_OR_UNKNOWN, to = SIGNAL_STRENGTH_GREAT)
     public int getLevel() {
         return mLevel;
     }
@@ -111,12 +112,22 @@
     /** @hide */
     @Override
     public void updateLevel(PersistableBundle cc, ServiceState ss) {
-        if (mRssi > GSM_RSSI_MAX) mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
-        else if (mRssi >= GSM_RSSI_GREAT) mLevel = SIGNAL_STRENGTH_GREAT;
-        else if (mRssi >= GSM_RSSI_GOOD)  mLevel = SIGNAL_STRENGTH_GOOD;
-        else if (mRssi >= GSM_RSSI_MODERATE)  mLevel = SIGNAL_STRENGTH_MODERATE;
-        else if (mRssi >= GSM_RSSI_POOR) mLevel = SIGNAL_STRENGTH_POOR;
-        else mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+        int[] rssiThresholds;
+        if (cc == null) {
+            rssiThresholds = sRssiThresholds;
+        } else {
+            rssiThresholds = cc.getIntArray(CarrierConfigManager.KEY_GSM_RSSI_THRESHOLDS_INT_ARRAY);
+            if (rssiThresholds == null || rssiThresholds.length != NUM_SIGNAL_STRENGTH_THRESHOLDS) {
+                rssiThresholds = sRssiThresholds;
+            }
+        }
+        int level = NUM_SIGNAL_STRENGTH_THRESHOLDS;
+        if (mRssi < GSM_RSSI_MIN || mRssi > GSM_RSSI_MAX) {
+            mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
+            return;
+        }
+        while (level > 0 && mRssi < rssiThresholds[level - 1]) level--;
+        mLevel = level;
     }
 
     /**
@@ -141,7 +152,7 @@
     /**
      * Get the RSSI in ASU.
      *
-     * Asu is calculated based on 3GPP RSRP. Refer to 3GPP 27.007 (Ver 10.3.0) Sec 8.69
+     * Asu is calculated based on 3GPP RSSI. Refer to 3GPP 27.007 (Ver 10.3.0) Sec 8.69
      *
      * @return RSSI in ASU 0..31, 99, or UNAVAILABLE
      */
diff --git a/telephony/java/android/telephony/CellSignalStrengthLte.java b/telephony/java/android/telephony/CellSignalStrengthLte.java
index 5687ada..2272dc9 100644
--- a/telephony/java/android/telephony/CellSignalStrengthLte.java
+++ b/telephony/java/android/telephony/CellSignalStrengthLte.java
@@ -16,6 +16,7 @@
 
 package android.telephony;
 
+import android.annotation.IntRange;
 import android.annotation.UnsupportedAppUsage;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -145,13 +146,9 @@
         mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
     }
 
-    /**
-     * Retrieve an abstract level value for the overall signal strength.
-     *
-     * @return a single integer from 0 to 4 representing the general signal quality.
-     *     0 represents very poor signal strength while 4 represents a very strong signal strength.
-     */
+    /** {@inheritDoc} */
     @Override
+    @IntRange(from = SIGNAL_STRENGTH_NONE_OR_UNKNOWN, to = SIGNAL_STRENGTH_GREAT)
     public int getLevel() {
         return mLevel;
     }
diff --git a/telephony/java/android/telephony/CellSignalStrengthNr.java b/telephony/java/android/telephony/CellSignalStrengthNr.java
index fff3adf..1912c60 100644
--- a/telephony/java/android/telephony/CellSignalStrengthNr.java
+++ b/telephony/java/android/telephony/CellSignalStrengthNr.java
@@ -16,6 +16,7 @@
 
 package android.telephony;
 
+import android.annotation.IntRange;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.PersistableBundle;
@@ -183,7 +184,9 @@
         mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
     }
 
+    /** {@inheritDoc} */
     @Override
+    @IntRange(from = SIGNAL_STRENGTH_NONE_OR_UNKNOWN, to = SIGNAL_STRENGTH_GREAT)
     public int getLevel() {
         return mLevel;
     }
@@ -227,6 +230,9 @@
         return asuLevel;
     }
 
+    /**
+     * Get the CSI-RSRP as dBm value -140..-44dBm or {@link CellInfo#UNAVAILABLE UNAVAILABLE}.
+     */
     @Override
     public int getDbm() {
         return mCsiRsrp;
diff --git a/telephony/java/android/telephony/CellSignalStrengthTdscdma.java b/telephony/java/android/telephony/CellSignalStrengthTdscdma.java
index ddbd851..f4a3dbb 100644
--- a/telephony/java/android/telephony/CellSignalStrengthTdscdma.java
+++ b/telephony/java/android/telephony/CellSignalStrengthTdscdma.java
@@ -16,6 +16,7 @@
 
 package android.telephony;
 
+import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -34,14 +35,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
 
@@ -121,13 +122,10 @@
         mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
     }
 
-    /**
-     * Retrieve an abstract level value for the overall signal strength.
-     *
-     * @return a single integer from 0 to 4 representing the general signal quality.
-     *     0 represents very poor signal strength while 4 represents a very strong signal strength.
-     */
+
+    /** {@inheritDoc} */
     @Override
+    @IntRange(from = 0, to = 4)
     public int getLevel() {
         return mLevel;
     }
@@ -135,16 +133,16 @@
     /** @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;
     }
 
     /**
-     * Get the signal strength as dBm
+     * Get the RSCP as dBm value -120..-24dBm or {@link CellInfo#UNAVAILABLE UNAVAILABLE}.
      */
     @Override
     public int getDbm() {
@@ -159,6 +157,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..1693252 100644
--- a/telephony/java/android/telephony/CellSignalStrengthWcdma.java
+++ b/telephony/java/android/telephony/CellSignalStrengthWcdma.java
@@ -16,6 +16,7 @@
 
 package android.telephony;
 
+import android.annotation.IntRange;
 import android.annotation.StringDef;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -66,7 +67,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
@@ -143,13 +144,9 @@
         mLevel = SIGNAL_STRENGTH_NONE_OR_UNKNOWN;
     }
 
-    /**
-     * Retrieve an abstract level value for the overall signal strength.
-     *
-     * @return a single integer from 0 to 4 representing the general signal quality.
-     *     0 represents very poor signal strength while 4 represents a very strong signal strength.
-     */
+    /** {@inheritDoc} */
     @Override
+    @IntRange(from = SIGNAL_STRENGTH_NONE_OR_UNKNOWN, to = SIGNAL_STRENGTH_GREAT)
     public int getLevel() {
         return mLevel;
     }
@@ -161,14 +158,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) {
@@ -202,7 +199,7 @@
     }
 
     /**
-     * Get the signal strength as dBm
+     * Get the RSCP as dBm value -120..-24dBm or {@link CellInfo#UNAVAILABLE UNAVAILABLE}.
      */
     @Override
     public int getDbm() {
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 8c92e84..1a160f4 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -339,6 +339,9 @@
 
     private List<NetworkRegistrationInfo> mNetworkRegistrationInfos = new ArrayList<>();
 
+    private String mOperatorAlphaLongRaw;
+    private String mOperatorAlphaShortRaw;
+
     /**
      * get String description of roaming type
      * @hide
@@ -420,6 +423,8 @@
         mNetworkRegistrationInfos = s.mNetworkRegistrationInfos == null ? null :
                 new ArrayList<>(s.mNetworkRegistrationInfos);
         mNrFrequencyRange = s.mNrFrequencyRange;
+        mOperatorAlphaLongRaw = s.mOperatorAlphaLongRaw;
+        mOperatorAlphaShortRaw = s.mOperatorAlphaShortRaw;
     }
 
     /**
@@ -453,6 +458,8 @@
         mChannelNumber = in.readInt();
         mCellBandwidths = in.createIntArray();
         mNrFrequencyRange = in.readInt();
+        mOperatorAlphaLongRaw = in.readString();
+        mOperatorAlphaShortRaw = in.readString();
     }
 
     public void writeToParcel(Parcel out, int flags) {
@@ -478,6 +485,8 @@
         out.writeInt(mChannelNumber);
         out.writeIntArray(mCellBandwidths);
         out.writeInt(mNrFrequencyRange);
+        out.writeString(mOperatorAlphaLongRaw);
+        out.writeString(mOperatorAlphaShortRaw);
     }
 
     public int describeContents() {
@@ -836,7 +845,9 @@
                 mIsEmergencyOnly,
                 mLteEarfcnRsrpBoost,
                 mNetworkRegistrationInfos,
-                mNrFrequencyRange);
+                mNrFrequencyRange,
+                mOperatorAlphaLongRaw,
+                mOperatorAlphaShortRaw);
     }
 
     @Override
@@ -862,6 +873,8 @@
                 && equalsHandlesNulls(mCdmaDefaultRoamingIndicator,
                         s.mCdmaDefaultRoamingIndicator)
                 && mIsEmergencyOnly == s.mIsEmergencyOnly
+                && equalsHandlesNulls(mOperatorAlphaLongRaw, s.mOperatorAlphaLongRaw)
+                && equalsHandlesNulls(mOperatorAlphaShortRaw, s.mOperatorAlphaShortRaw)
                 && (mNetworkRegistrationInfos == null
                 ? s.mNetworkRegistrationInfos == null : s.mNetworkRegistrationInfos != null
                 && mNetworkRegistrationInfos.containsAll(s.mNetworkRegistrationInfos))
@@ -1019,6 +1032,8 @@
             .append(", mLteEarfcnRsrpBoost=").append(mLteEarfcnRsrpBoost)
             .append(", mNetworkRegistrationInfos=").append(mNetworkRegistrationInfos)
             .append(", mNrFrequencyRange=").append(mNrFrequencyRange)
+            .append(", mOperatorAlphaLongRaw=").append(mOperatorAlphaLongRaw)
+            .append(", mOperatorAlphaShortRaw=").append(mOperatorAlphaShortRaw)
             .append("}").toString();
     }
 
@@ -1056,6 +1071,8 @@
                 .setTransportType(AccessNetworkConstants.TRANSPORT_TYPE_WWAN)
                 .setRegistrationState(NetworkRegistrationInfo.REGISTRATION_STATE_UNKNOWN)
                 .build());
+        mOperatorAlphaLongRaw = null;
+        mOperatorAlphaShortRaw = null;
     }
 
     public void setStateOutOfService() {
@@ -1297,6 +1314,8 @@
         m.putInt("ChannelNumber", mChannelNumber);
         m.putIntArray("CellBandwidths", mCellBandwidths);
         m.putInt("mNrFrequencyRange", mNrFrequencyRange);
+        m.putString("operator-alpha-long-raw", mOperatorAlphaLongRaw);
+        m.putString("operator-alpha-short-raw", mOperatorAlphaShortRaw);
     }
 
     /** @hide */
@@ -1906,4 +1925,36 @@
 
         return state;
     }
+
+    /**
+     * @hide
+     */
+    public void setOperatorAlphaLongRaw(String operatorAlphaLong) {
+        mOperatorAlphaLongRaw = operatorAlphaLong;
+    }
+
+    /**
+     * The current registered raw data network operator name in long alphanumeric format.
+     *
+     * @hide
+     */
+    public String getOperatorAlphaLongRaw() {
+        return mOperatorAlphaLongRaw;
+    }
+
+    /**
+     * @hide
+     */
+    public void setOperatorAlphaShortRaw(String operatorAlphaShort) {
+        mOperatorAlphaShortRaw = operatorAlphaShort;
+    }
+
+    /**
+     * The current registered raw data network operator name in short alphanumeric format.
+     *
+     * @hide
+     */
+    public String getOperatorAlphaShortRaw() {
+        return mOperatorAlphaShortRaw;
+    }
 }
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. */
diff --git a/tests/net/java/android/net/NetworkStackTest.java b/tests/net/java/android/net/NetworkStackTest.java
new file mode 100644
index 0000000..f7c6c99
--- /dev/null
+++ b/tests/net/java/android/net/NetworkStackTest.java
@@ -0,0 +1,75 @@
+/*
+ * 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 android.net;
+
+import static android.Manifest.permission.NETWORK_STACK;
+import static android.content.pm.PackageManager.PERMISSION_DENIED;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
+import static android.net.NetworkStack.checkNetworkStackPermission;
+import static android.net.NetworkStack.checkNetworkStackPermissionOr;
+
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+public class NetworkStackTest {
+    private static final String [] OTHER_PERMISSION = {"otherpermission1", "otherpermission2"};
+
+    @Mock Context mCtx;
+
+    @Before public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    @Test
+    public void testCheckNetworkStackPermission() throws Exception {
+        when(mCtx.checkCallingOrSelfPermission(eq(NETWORK_STACK))).thenReturn(PERMISSION_GRANTED);
+        when(mCtx.checkCallingOrSelfPermission(eq(PERMISSION_MAINLINE_NETWORK_STACK)))
+                .thenReturn(PERMISSION_DENIED);
+        checkNetworkStackPermission(mCtx);
+        checkNetworkStackPermissionOr(mCtx, OTHER_PERMISSION);
+
+        when(mCtx.checkCallingOrSelfPermission(eq(NETWORK_STACK))).thenReturn(PERMISSION_DENIED);
+        when(mCtx.checkCallingOrSelfPermission(eq(PERMISSION_MAINLINE_NETWORK_STACK)))
+                .thenReturn(PERMISSION_GRANTED);
+        checkNetworkStackPermission(mCtx);
+        checkNetworkStackPermissionOr(mCtx, OTHER_PERMISSION);
+
+        when(mCtx.checkCallingOrSelfPermission(any())).thenReturn(PERMISSION_DENIED);
+
+        try {
+            checkNetworkStackPermissionOr(mCtx, OTHER_PERMISSION);
+        } catch (SecurityException e) {
+            // Expect to get a SecurityException
+            return;
+        }
+
+        fail("Expect fail but permission granted.");
+    }
+}
diff --git a/tests/net/java/com/android/server/IpSecServiceRefcountedResourceTest.java b/tests/net/java/com/android/server/IpSecServiceRefcountedResourceTest.java
index 68ff777..22a2c94 100644
--- a/tests/net/java/com/android/server/IpSecServiceRefcountedResourceTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceRefcountedResourceTest.java
@@ -18,6 +18,7 @@
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.anyObject;
 import static org.mockito.Matchers.eq;
@@ -134,11 +135,11 @@
         IBinder binderMock = mock(IBinder.class);
         doThrow(new RemoteException()).when(binderMock).linkToDeath(anyObject(), anyInt());
 
-        RefcountedResource<IResource> refcountedResource = getTestRefcountedResource(binderMock);
-
-        // Verify that cleanup is performed (Spy limitations prevent verification of method calls
-        // for binder death scenario; check refcount to determine if cleanup was performed.)
-        assertEquals(-1, refcountedResource.mRefCount);
+        try {
+            getTestRefcountedResource(binderMock);
+            fail("Expected exception to propogate when binder fails to link to death");
+        } catch (RuntimeException expected) {
+        }
     }
 
     @Test
diff --git a/tests/net/java/com/android/server/IpSecServiceTest.java b/tests/net/java/com/android/server/IpSecServiceTest.java
index b5c3e92..4a35015 100644
--- a/tests/net/java/com/android/server/IpSecServiceTest.java
+++ b/tests/net/java/com/android/server/IpSecServiceTest.java
@@ -156,10 +156,21 @@
 
     @Test
     public void testOpenAndCloseUdpEncapsulationSocket() throws Exception {
-        int localport = findUnusedPort();
+        int localport = -1;
+        IpSecUdpEncapResponse udpEncapResp = null;
 
-        IpSecUdpEncapResponse udpEncapResp =
-                mIpSecService.openUdpEncapsulationSocket(localport, new Binder());
+        for (int i = 0; i < IpSecService.MAX_PORT_BIND_ATTEMPTS; i++) {
+            localport = findUnusedPort();
+
+            udpEncapResp = mIpSecService.openUdpEncapsulationSocket(localport, new Binder());
+            assertNotNull(udpEncapResp);
+            if (udpEncapResp.status == IpSecManager.Status.OK) {
+                break;
+            }
+
+            // Else retry to reduce possibility for port-bind failures.
+        }
+
         assertNotNull(udpEncapResp);
         assertEquals(IpSecManager.Status.OK, udpEncapResp.status);
         assertEquals(localport, udpEncapResp.port);
@@ -204,12 +215,11 @@
 
     @Test
     public void testOpenUdpEncapsulationSocketAfterClose() throws Exception {
-        int localport = findUnusedPort();
         IpSecUdpEncapResponse udpEncapResp =
-                mIpSecService.openUdpEncapsulationSocket(localport, new Binder());
+                mIpSecService.openUdpEncapsulationSocket(0, new Binder());
         assertNotNull(udpEncapResp);
         assertEquals(IpSecManager.Status.OK, udpEncapResp.status);
-        assertEquals(localport, udpEncapResp.port);
+        int localport = udpEncapResp.port;
 
         mIpSecService.closeUdpEncapsulationSocket(udpEncapResp.resourceId);
         udpEncapResp.fileDescriptor.close();
@@ -226,12 +236,11 @@
      */
     @Test
     public void testUdpEncapPortNotReleased() throws Exception {
-        int localport = findUnusedPort();
         IpSecUdpEncapResponse udpEncapResp =
-                mIpSecService.openUdpEncapsulationSocket(localport, new Binder());
+                mIpSecService.openUdpEncapsulationSocket(0, new Binder());
         assertNotNull(udpEncapResp);
         assertEquals(IpSecManager.Status.OK, udpEncapResp.status);
-        assertEquals(localport, udpEncapResp.port);
+        int localport = udpEncapResp.port;
 
         udpEncapResp.fileDescriptor.close();
 
@@ -273,14 +282,11 @@
 
     @Test
     public void testOpenUdpEncapsulationSocketTwice() throws Exception {
-        int localport = findUnusedPort();
-
         IpSecUdpEncapResponse udpEncapResp =
-                mIpSecService.openUdpEncapsulationSocket(localport, new Binder());
+                mIpSecService.openUdpEncapsulationSocket(0, new Binder());
         assertNotNull(udpEncapResp);
         assertEquals(IpSecManager.Status.OK, udpEncapResp.status);
-        assertEquals(localport, udpEncapResp.port);
-        mIpSecService.openUdpEncapsulationSocket(localport, new Binder());
+        int localport = udpEncapResp.port;
 
         IpSecUdpEncapResponse testUdpEncapResp =
                 mIpSecService.openUdpEncapsulationSocket(localport, new Binder());
diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp
index 4e6d073..1aad4be 100644
--- a/tools/stats_log_api_gen/main.cpp
+++ b/tools/stats_log_api_gen/main.cpp
@@ -1177,7 +1177,7 @@
 
         // Initialize the buffer with list data type.
         fprintf(out, "        buff[pos] = LIST_TYPE;\n");
-        fprintf(out, "        buff[pos + 1] = %lu;\n", signature.size() + 2);
+        fprintf(out, "        buff[pos + 1] = %zu;\n", signature.size() + 2);
         fprintf(out, "        pos += LIST_TYPE_OVERHEAD;\n");
 
         // Write timestamp.
diff --git a/wifi/java/android/net/wifi/aware/ConfigRequest.java b/wifi/java/android/net/wifi/aware/ConfigRequest.java
index 1e46d1b..b07d8ed 100644
--- a/wifi/java/android/net/wifi/aware/ConfigRequest.java
+++ b/wifi/java/android/net/wifi/aware/ConfigRequest.java
@@ -213,7 +213,7 @@
      * Builder used to build {@link ConfigRequest} objects.
      */
     public static final class Builder {
-        private boolean mSupport5gBand = false;
+        private boolean mSupport5gBand = true;
         private int mMasterPreference = 0;
         private int mClusterLow = CLUSTER_ID_MIN;
         private int mClusterHigh = CLUSTER_ID_MAX;
diff --git a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
index 52bb284..db8220b 100644
--- a/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
+++ b/wifi/tests/src/android/net/wifi/aware/WifiAwareManagerTest.java
@@ -576,7 +576,7 @@
                 equalTo(configRequest.mClusterLow));
         collector.checkThat("mMasterPreference", 0,
                 equalTo(configRequest.mMasterPreference));
-        collector.checkThat("mSupport5gBand", false, equalTo(configRequest.mSupport5gBand));
+        collector.checkThat("mSupport5gBand", true, equalTo(configRequest.mSupport5gBand));
         collector.checkThat("mDiscoveryWindowInterval.length", 2,
                 equalTo(configRequest.mDiscoveryWindowInterval.length));
         collector.checkThat("mDiscoveryWindowInterval[2.4GHz]", ConfigRequest.DW_INTERVAL_NOT_INIT,