Merge "Reposition the stack to a similar position upon rotation." into qt-dev
diff --git a/Android.bp b/Android.bp
index c3025e8..b4110fa 100644
--- a/Android.bp
+++ b/Android.bp
@@ -920,6 +920,7 @@
         "core/java/com/android/internal/util/RingBufferIndices.java",
         "core/java/com/android/internal/util/State.java",
         "core/java/com/android/internal/util/StateMachine.java",
+        "core/java/com/android/internal/util/TrafficStatsConstants.java",
         "core/java/com/android/internal/util/WakeupMessage.java",
         "core/java/android/net/shared/*.java",
     ]
diff --git a/api/current.txt b/api/current.txt
index 8ec7594..f9db63d 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -287,7 +287,6 @@
     field public static final int allowBackup = 16843392; // 0x1010280
     field public static final int allowClearUserData = 16842757; // 0x1010005
     field public static final int allowEmbedded = 16843765; // 0x10103f5
-    field public static final int allowExternalStorageSandbox = 16844201; // 0x10105a9
     field public static final int allowParallelSyncs = 16843570; // 0x1010332
     field public static final int allowSingleTap = 16843353; // 0x1010259
     field public static final int allowTaskReparenting = 16843268; // 0x1010204
@@ -1125,6 +1124,7 @@
     field public static final int reqKeyboardType = 16843304; // 0x1010228
     field public static final int reqNavigation = 16843306; // 0x101022a
     field public static final int reqTouchScreen = 16843303; // 0x1010227
+    field public static final int requestLegacyExternalStorage = 16844201; // 0x10105a9
     field public static final int requireDeviceUnlock = 16843756; // 0x10103ec
     field public static final int required = 16843406; // 0x101028e
     field public static final int requiredAccountType = 16843734; // 0x10103d6
@@ -11859,6 +11859,7 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.content.pm.PermissionInfo> CREATOR;
     field public static final int FLAG_COSTS_MONEY = 1; // 0x1
     field public static final int FLAG_HARD_RESTRICTED = 4; // 0x4
+    field public static final int FLAG_IMMUTABLY_RESTRICTED = 16; // 0x10
     field public static final int FLAG_INSTALLED = 1073741824; // 0x40000000
     field public static final int FLAG_SOFT_RESTRICTED = 8; // 0x8
     field public static final int PROTECTION_DANGEROUS = 1; // 0x1
@@ -39144,7 +39145,7 @@
     field public static final String CONTENT_ID = "cid";
     field public static final String CONTENT_LOCATION = "cl";
     field public static final String CONTENT_TYPE = "ct";
-    field public static final android.net.Uri CONTENT_URI;
+    field @NonNull public static final android.net.Uri CONTENT_URI;
     field public static final String CT_START = "ctt_s";
     field public static final String CT_TYPE = "ctt_t";
     field public static final String FILENAME = "fn";
@@ -51509,6 +51510,7 @@
     method public android.transition.Transition getSharedElementReturnTransition();
     method public boolean getSharedElementsUseOverlay();
     method @ColorInt public abstract int getStatusBarColor();
+    method @NonNull public java.util.List<android.graphics.Rect> getSystemGestureExclusionRects();
     method public long getTransitionBackgroundFadeDuration();
     method public android.transition.TransitionManager getTransitionManager();
     method public abstract int getVolumeControlStream();
@@ -51587,6 +51589,7 @@
     method public void setSoftInputMode(int);
     method public abstract void setStatusBarColor(@ColorInt int);
     method public void setSustainedPerformanceMode(boolean);
+    method public void setSystemGestureExclusionRects(@NonNull java.util.List<android.graphics.Rect>);
     method public abstract void setTitle(CharSequence);
     method @Deprecated public abstract void setTitleColor(@ColorInt int);
     method public void setTransitionBackgroundFadeDuration(long);
@@ -53614,29 +53617,23 @@
     method @NonNull public android.view.textclassifier.TextClassifier.EntityConfig.Builder setIncludedTypes(@Nullable java.util.Collection<java.lang.String>);
   }
 
-  public final class TextClassifierEvent implements android.os.Parcelable {
+  public abstract class TextClassifierEvent implements android.os.Parcelable {
     method public int describeContents();
     method @NonNull public int[] getActionIndices();
     method @NonNull public String[] getEntityTypes();
     method public int getEventCategory();
     method @Nullable public android.view.textclassifier.TextClassificationContext getEventContext();
     method public int getEventIndex();
-    method public long getEventTime();
     method public int getEventType();
     method @NonNull public android.os.Bundle getExtras();
-    method @Nullable public String getLanguage();
-    method public int getRelativeSuggestedWordEndIndex();
-    method public int getRelativeSuggestedWordStartIndex();
-    method public int getRelativeWordEndIndex();
-    method public int getRelativeWordStartIndex();
+    method @Nullable public String getModelName();
     method @Nullable public String getResultId();
-    method public float getScore();
+    method @NonNull public float[] getScores();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final int CATEGORY_CONVERSATION_ACTIONS = 3; // 0x3
     field public static final int CATEGORY_LANGUAGE_DETECTION = 4; // 0x4
     field public static final int CATEGORY_LINKIFY = 2; // 0x2
     field public static final int CATEGORY_SELECTION = 1; // 0x1
-    field public static final int CATEGORY_UNDEFINED = 0; // 0x0
     field @NonNull public static final android.os.Parcelable.Creator<android.view.textclassifier.TextClassifierEvent> CREATOR;
     field public static final int TYPE_ACTIONS_GENERATED = 20; // 0x14
     field public static final int TYPE_ACTIONS_SHOWN = 6; // 0x6
@@ -53658,25 +53655,63 @@
     field public static final int TYPE_SMART_ACTION = 13; // 0xd
     field public static final int TYPE_SMART_SELECTION_MULTI = 4; // 0x4
     field public static final int TYPE_SMART_SELECTION_SINGLE = 3; // 0x3
-    field public static final int TYPE_UNDEFINED = 0; // 0x0
   }
 
-  public static final class TextClassifierEvent.Builder {
-    ctor public TextClassifierEvent.Builder(int, int);
-    method @NonNull public android.view.textclassifier.TextClassifierEvent build();
-    method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setActionIndices(@NonNull int...);
-    method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setEntityTypes(@NonNull java.lang.String...);
-    method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setEventContext(@Nullable android.view.textclassifier.TextClassificationContext);
-    method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setEventIndex(int);
-    method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setEventTime(long);
-    method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setExtras(@NonNull android.os.Bundle);
-    method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setLanguage(@Nullable String);
-    method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setRelativeSuggestedWordEndIndex(int);
-    method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setRelativeSuggestedWordStartIndex(int);
-    method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setRelativeWordEndIndex(int);
-    method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setRelativeWordStartIndex(int);
-    method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setResultId(@Nullable String);
-    method @NonNull public android.view.textclassifier.TextClassifierEvent.Builder setScore(float);
+  public abstract static class TextClassifierEvent.Builder<T extends android.view.textclassifier.TextClassifierEvent.Builder<T>> {
+    method @NonNull public T setActionIndices(@NonNull int...);
+    method @NonNull public T setEntityTypes(@NonNull java.lang.String...);
+    method @NonNull public T setEventContext(@Nullable android.view.textclassifier.TextClassificationContext);
+    method @NonNull public T setEventIndex(int);
+    method @NonNull public T setExtras(@NonNull android.os.Bundle);
+    method @NonNull public T setModelName(@Nullable String);
+    method @NonNull public T setResultId(@Nullable String);
+    method @NonNull public T setScores(@NonNull float...);
+  }
+
+  public static final class TextClassifierEvent.ConversationActionsEvent extends android.view.textclassifier.TextClassifierEvent implements android.os.Parcelable {
+    field @NonNull public static final android.os.Parcelable.Creator<android.view.textclassifier.TextClassifierEvent.ConversationActionsEvent> CREATOR;
+  }
+
+  public static final class TextClassifierEvent.ConversationActionsEvent.Builder extends android.view.textclassifier.TextClassifierEvent.Builder<android.view.textclassifier.TextClassifierEvent.ConversationActionsEvent.Builder> {
+    ctor public TextClassifierEvent.ConversationActionsEvent.Builder(int);
+    method @NonNull public android.view.textclassifier.TextClassifierEvent.ConversationActionsEvent build();
+  }
+
+  public static final class TextClassifierEvent.LanguageDetectionEvent extends android.view.textclassifier.TextClassifierEvent implements android.os.Parcelable {
+    method @Nullable public android.icu.util.ULocale getLocale();
+    field @NonNull public static final android.os.Parcelable.Creator<android.view.textclassifier.TextClassifierEvent.LanguageDetectionEvent> CREATOR;
+  }
+
+  public static final class TextClassifierEvent.LanguageDetectionEvent.Builder extends android.view.textclassifier.TextClassifierEvent.Builder<android.view.textclassifier.TextClassifierEvent.LanguageDetectionEvent.Builder> {
+    ctor public TextClassifierEvent.LanguageDetectionEvent.Builder(int);
+    method @NonNull public android.view.textclassifier.TextClassifierEvent.LanguageDetectionEvent build();
+    method @NonNull public android.view.textclassifier.TextClassifierEvent.LanguageDetectionEvent.Builder setLocale(@Nullable android.icu.util.ULocale);
+  }
+
+  public static final class TextClassifierEvent.TextLinkifyEvent extends android.view.textclassifier.TextClassifierEvent implements android.os.Parcelable {
+    field @NonNull public static final android.os.Parcelable.Creator<android.view.textclassifier.TextClassifierEvent.TextLinkifyEvent> CREATOR;
+  }
+
+  public static final class TextClassifierEvent.TextLinkifyEvent.Builder extends android.view.textclassifier.TextClassifierEvent.Builder<android.view.textclassifier.TextClassifierEvent.TextLinkifyEvent.Builder> {
+    ctor public TextClassifierEvent.TextLinkifyEvent.Builder(int);
+    method @NonNull public android.view.textclassifier.TextClassifierEvent.TextLinkifyEvent build();
+  }
+
+  public static final class TextClassifierEvent.TextSelectionEvent extends android.view.textclassifier.TextClassifierEvent implements android.os.Parcelable {
+    method public int getRelativeSuggestedWordEndIndex();
+    method public int getRelativeSuggestedWordStartIndex();
+    method public int getRelativeWordEndIndex();
+    method public int getRelativeWordStartIndex();
+    field @NonNull public static final android.os.Parcelable.Creator<android.view.textclassifier.TextClassifierEvent.TextSelectionEvent> CREATOR;
+  }
+
+  public static final class TextClassifierEvent.TextSelectionEvent.Builder extends android.view.textclassifier.TextClassifierEvent.Builder<android.view.textclassifier.TextClassifierEvent.TextSelectionEvent.Builder> {
+    ctor public TextClassifierEvent.TextSelectionEvent.Builder(int);
+    method @NonNull public android.view.textclassifier.TextClassifierEvent.TextSelectionEvent build();
+    method @NonNull public android.view.textclassifier.TextClassifierEvent.TextSelectionEvent.Builder setRelativeSuggestedWordEndIndex(int);
+    method @NonNull public android.view.textclassifier.TextClassifierEvent.TextSelectionEvent.Builder setRelativeSuggestedWordStartIndex(int);
+    method @NonNull public android.view.textclassifier.TextClassifierEvent.TextSelectionEvent.Builder setRelativeWordEndIndex(int);
+    method @NonNull public android.view.textclassifier.TextClassifierEvent.TextSelectionEvent.Builder setRelativeWordStartIndex(int);
   }
 
   public final class TextLanguage implements android.os.Parcelable {
diff --git a/api/system-current.txt b/api/system-current.txt
index c031429..b60e850 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1092,11 +1092,14 @@
   }
 
   public static final class AppTarget.Builder {
+    ctor @Deprecated public AppTarget.Builder(@NonNull android.app.prediction.AppTargetId);
     ctor public AppTarget.Builder(@NonNull android.app.prediction.AppTargetId, @NonNull String, @NonNull android.os.UserHandle);
     ctor public AppTarget.Builder(@NonNull android.app.prediction.AppTargetId, @NonNull android.content.pm.ShortcutInfo);
     method @NonNull public android.app.prediction.AppTarget build();
     method @NonNull public android.app.prediction.AppTarget.Builder setClassName(@NonNull String);
     method @NonNull public android.app.prediction.AppTarget.Builder setRank(@IntRange(from=0) int);
+    method @Deprecated @NonNull public android.app.prediction.AppTarget.Builder setTarget(@NonNull String, @NonNull android.os.UserHandle);
+    method @Deprecated @NonNull public android.app.prediction.AppTarget.Builder setTarget(@NonNull android.content.pm.ShortcutInfo);
   }
 
   public final class AppTargetEvent implements android.os.Parcelable {
@@ -4225,9 +4228,12 @@
     method public static void setThreadStatsTagApp();
     method public static void setThreadStatsTagBackup();
     method public static void setThreadStatsTagRestore();
-    field public static final int TAG_SYSTEM_DHCP = -192; // 0xffffff40
-    field public static final int TAG_SYSTEM_DHCP_SERVER = -186; // 0xffffff46
-    field public static final int TAG_SYSTEM_PROBE = -190; // 0xffffff42
+    field public static final int TAG_NETWORK_STACK_IMPERSONATION_RANGE_END = -113; // 0xffffff8f
+    field public static final int TAG_NETWORK_STACK_IMPERSONATION_RANGE_START = -128; // 0xffffff80
+    field public static final int TAG_NETWORK_STACK_RANGE_END = -257; // 0xfffffeff
+    field public static final int TAG_NETWORK_STACK_RANGE_START = -768; // 0xfffffd00
+    field public static final int TAG_SYSTEM_IMPERSONATION_RANGE_END = -241; // 0xffffff0f
+    field public static final int TAG_SYSTEM_IMPERSONATION_RANGE_START = -256; // 0xffffff00
   }
 
   public abstract class Uri implements java.lang.Comparable<android.net.Uri> android.os.Parcelable {
diff --git a/api/test-current.txt b/api/test-current.txt
index 811ad43..f76b383 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -503,6 +503,8 @@
     method @NonNull public android.app.prediction.AppTarget build();
     method @NonNull public android.app.prediction.AppTarget.Builder setClassName(@NonNull String);
     method @NonNull public android.app.prediction.AppTarget.Builder setRank(@IntRange(from=0) int);
+    method @Deprecated @NonNull public android.app.prediction.AppTarget.Builder setTarget(@NonNull String, @NonNull android.os.UserHandle);
+    method @Deprecated @NonNull public android.app.prediction.AppTarget.Builder setTarget(@NonNull android.content.pm.ShortcutInfo);
   }
 
   public final class AppTargetEvent implements android.os.Parcelable {
@@ -1104,6 +1106,7 @@
     method @RequiresPermission("android.permission.MODIFY_AUDIO_ROUTING") public void setFocusRequestResult(@NonNull android.media.AudioFocusInfo, int, @NonNull android.media.audiopolicy.AudioPolicy);
     method @RequiresPermission("android.permission.MODIFY_AUDIO_ROUTING") public void unregisterAudioPolicy(@NonNull android.media.audiopolicy.AudioPolicy);
     method @RequiresPermission("android.permission.MODIFY_AUDIO_ROUTING") public void unregisterAudioPolicyAsync(@NonNull android.media.audiopolicy.AudioPolicy);
+    field public static final int SUCCESS = 0; // 0x0
   }
 
   public static final class AudioRecord.MetricsConstants {
@@ -1129,22 +1132,6 @@
     field public static final String SAMPLE_RATE = "android.media.audiotrack.sampleRate";
   }
 
-  public final class BufferingParams implements android.os.Parcelable {
-    method public int describeContents();
-    method public int getInitialMarkMs();
-    method public int getResumePlaybackMarkMs();
-    method public void writeToParcel(android.os.Parcel, int);
-    field @NonNull public static final android.os.Parcelable.Creator<android.media.BufferingParams> CREATOR;
-  }
-
-  public static class BufferingParams.Builder {
-    ctor public BufferingParams.Builder();
-    ctor public BufferingParams.Builder(android.media.BufferingParams);
-    method public android.media.BufferingParams build();
-    method public android.media.BufferingParams.Builder setInitialMarkMs(int);
-    method public android.media.BufferingParams.Builder setResumePlaybackMarkMs(int);
-  }
-
   public static final class MediaCodecInfo.VideoCapabilities.PerformancePoint {
     ctor public MediaCodecInfo.VideoCapabilities.PerformancePoint(int, int, int, int, @NonNull android.util.Size);
     ctor public MediaCodecInfo.VideoCapabilities.PerformancePoint(@NonNull android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint, @NonNull android.util.Size);
@@ -1241,8 +1228,10 @@
     method public int detachMixes(@NonNull java.util.List<android.media.audiopolicy.AudioMix>);
     method public int getFocusDuckingBehavior();
     method public int getStatus();
+    method public boolean removeUidDeviceAffinity(int);
     method public int setFocusDuckingBehavior(int) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
     method public void setRegistration(String);
+    method public boolean setUidDeviceAffinity(int, @NonNull java.util.List<android.media.AudioDeviceInfo>);
     method public String toLogFriendlyString();
     field public static final int FOCUS_POLICY_DUCKING_DEFAULT = 0; // 0x0
     field public static final int FOCUS_POLICY_DUCKING_IN_APP = 0; // 0x0
@@ -1459,9 +1448,6 @@
     method public static long getLoopbackRxPackets();
     method public static long getLoopbackTxBytes();
     method public static long getLoopbackTxPackets();
-    field public static final int TAG_SYSTEM_DHCP = -192; // 0xffffff40
-    field public static final int TAG_SYSTEM_DHCP_SERVER = -186; // 0xffffff46
-    field public static final int TAG_SYSTEM_PROBE = -190; // 0xffffff42
   }
 
 }
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index 55d3fba..d28108c 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -268,7 +268,8 @@
         TouchGestureClassified touch_gesture_classified = 177;
         HiddenApiUsed hidden_api_used = 178 [(allow_from_any_uid) = true];
         StyleUIChanged style_ui_changed = 179;
-        PrivacyIndicatorsInteracted privacy_indicators_interacted = 180;
+        PrivacyIndicatorsInteracted privacy_indicators_interacted =
+	    180 [(log_from_module) = "permissioncontroller"];
         AppInstallOnExternalStorageReported app_install_on_external_storage_reported = 181;
         NetworkStackReported network_stack_reported = 182 [(log_from_module) = "network_stack"];
         AppMovedStorageReported app_moved_storage_reported = 183;
@@ -340,6 +341,7 @@
         SystemIonHeapSize system_ion_heap_size = 10056;
         AppsOnExternalStorageInfo apps_on_external_storage_info = 10057;
         FaceSettings face_settings = 10058;
+        CoolingDevice cooling_device = 10059;
     }
 
     // DO NOT USE field numbers above 100,000 in AOSP.
@@ -410,17 +412,25 @@
  *   frameworks/base/services/core/java/com/android/server/stats/StatsCompanionService.java
  */
 message ThermalThrottlingStateChanged {
+    // The type of temperature being reported (CPU, GPU, SKIN, etc)
     optional android.os.TemperatureTypeEnum sensor_type = 1;
 
+    // Throttling state, this field is DEPRECATED
     enum State {
         UNKNOWN = 0;
-        START = 1;
-        STOP = 2;
+        START = 1; // START indicated that throttling was triggered.
+        STOP = 2; // STOP indicates that throttling was cleared.
     }
-
     optional State state = 2;
 
+    // Temperature in deci degrees celsius
     optional float temperature = 3;
+
+    // Severity of throttling
+    optional android.os.ThrottlingSeverityEnum severity = 4;
+
+    // Thermistor name
+    optional string sensor_name = 5;
 }
 
 /**
@@ -3957,8 +3967,7 @@
  * Pulls the temperature of various parts of the device.
  * The units are tenths of a degree Celsius. Eg: 30.3C is reported as 303.
  *
- * Pulled from:
- *   frameworks/base/cmds/statsd/src/external/ResourceThermalManagerPuller.cpp
+ * Pulled from StatsCompanionService.java
  */
 message Temperature {
     // The type of temperature being reported. Eg. CPU, GPU, SKIN, BATTERY, BCL_.
@@ -3970,6 +3979,9 @@
     // Temperature in tenths of a degree C.
     // For BCL, it is decimillivolt, decimilliamps, and percentage * 10.
     optional int32 temperature_deci_celsius = 3;
+
+    // Relative severity of the throttling, see enum definition.
+    optional android.os.ThrottlingSeverityEnum severity = 4;
 }
 
 /**
@@ -5947,3 +5959,19 @@
     // Whether or not a diverse set of poses are required during enrollment.
     optional bool unlock_diversity_required = 6;
 }
+
+/**
+ * Logs cooling devices maintained by the kernel.
+ *
+ * Pulled from StatsCompanionService.java
+ */
+message CoolingDevice {
+    // The type of cooling device being reported. Eg. CPU, GPU...
+    optional android.os.CoolingTypeEnum device_location = 1;
+    // The name of the cooling device source. Eg. CPU0
+    optional string device_name = 2;
+    // Current throttle state of the cooling device. The value can any unsigned
+    // integer between 0 and max_state defined in its driver. 0 means device is
+    // not in throttling, higher value means deeper throttling.
+    optional int32 state = 3;
+}
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index 51839c4..ca73059 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -159,6 +159,9 @@
         // temperature
         {android::util::TEMPERATURE,
          {.puller = new StatsCompanionServicePuller(android::util::TEMPERATURE)}},
+        // cooling_device
+        {android::util::COOLING_DEVICE,
+         {.puller = new StatsCompanionServicePuller(android::util::COOLING_DEVICE)}},
         // binder_calls
         {android::util::BINDER_CALLS,
          {.additiveFields = {4, 5, 6, 8, 12},
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 5f972c9..6e935e1 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -127,7 +127,6 @@
 import android.view.autofill.IAutofillWindowPresenter;
 import android.view.contentcapture.ContentCaptureContext;
 import android.view.contentcapture.ContentCaptureManager;
-import android.view.contentcapture.ContentCaptureManager.ContentCaptureClient;
 import android.widget.AdapterView;
 import android.widget.Toast;
 import android.widget.Toolbar;
@@ -724,7 +723,7 @@
         Window.Callback, KeyEvent.Callback,
         OnCreateContextMenuListener, ComponentCallbacks2,
         Window.OnWindowDismissedCallback, WindowControllerCallback,
-        AutofillManager.AutofillClient, ContentCaptureManager.ContentCaptureClient {
+        AutofillManager.AutofillClient {
     private static final String TAG = "Activity";
     private static final boolean DEBUG_LIFECYCLE = false;
 
@@ -1124,12 +1123,6 @@
         return this;
     }
 
-    /** @hide */
-    @Override
-    public final ContentCaptureClient getContentCaptureClient() {
-        return this;
-    }
-
     /**
      * Register an {@link Application.ActivityLifecycleCallbacks} instance that receives
      * lifecycle callbacks for only this Activity.
@@ -6509,12 +6502,6 @@
         return getComponentName();
     }
 
-    /** @hide */
-    @Override
-    public final ComponentName contentCaptureClientGetComponentName() {
-        return getComponentName();
-    }
-
     /**
      * Retrieve a {@link SharedPreferences} object for accessing preferences
      * that are private to this activity.  This simply calls the underlying
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 0260faa..5e5611b 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -4549,7 +4549,7 @@
         if (!show && !r.stopped) {
             performStopActivityInner(r, null /* stopInfo */, show, false /* saveState */,
                     false /* finalStateRequest */, "handleWindowVisibility");
-        } else if (show && r.stopped) {
+        } else if (show && r.getLifecycleState() == ON_STOP) {
             // If we are getting ready to gc after going to the background, well
             // we are back active so skip it.
             unscheduleGcIdler();
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 6f92244..7243624 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -823,9 +823,11 @@
     public static final int OP_LEGACY_STORAGE = 87;
     /** @hide Accessing accessibility features */
     public static final int OP_ACCESS_ACCESSIBILITY = 88;
+    /** @hide Read the device identifiers (IMEI / MEID, IMSI, SIM / Build serial) */
+    public static final int OP_READ_DEVICE_IDENTIFIERS = 89;
     /** @hide */
     @UnsupportedAppUsage
-    public static final int _NUM_OP = 89;
+    public static final int _NUM_OP = 90;
 
     /** Access to coarse location information. */
     public static final String OPSTR_COARSE_LOCATION = "android:coarse_location";
@@ -1099,6 +1101,8 @@
     /** @hide Interact with accessibility. */
     @SystemApi
     public static final String OPSTR_ACCESS_ACCESSIBILITY = "android:access_accessibility";
+    /** @hide Read device identifiers */
+    public static final String OPSTR_READ_DEVICE_IDENTIFIERS = "android:read_device_identifiers";
 
     // Warning: If an permission is added here it also has to be added to
     // com.android.packageinstaller.permission.utils.EventLogger
@@ -1259,6 +1263,7 @@
             OP_WRITE_MEDIA_IMAGES,              // WRITE_MEDIA_IMAGES
             OP_LEGACY_STORAGE,                  // LEGACY_STORAGE
             OP_ACCESS_ACCESSIBILITY,            // ACCESS_ACCESSIBILITY
+            OP_READ_DEVICE_IDENTIFIERS,         // READ_DEVICE_IDENTIFIERS
     };
 
     /**
@@ -1354,6 +1359,7 @@
             OPSTR_WRITE_MEDIA_IMAGES,
             OPSTR_LEGACY_STORAGE,
             OPSTR_ACCESS_ACCESSIBILITY,
+            OPSTR_READ_DEVICE_IDENTIFIERS,
     };
 
     /**
@@ -1450,6 +1456,7 @@
             "WRITE_MEDIA_IMAGES",
             "LEGACY_STORAGE",
             "ACCESS_ACCESSIBILITY",
+            "READ_DEVICE_IDENTIFIERS",
     };
 
     /**
@@ -1547,6 +1554,7 @@
             null, // no permission for OP_WRITE_MEDIA_IMAGES
             null, // no permission for OP_LEGACY_STORAGE
             null, // no permission for OP_ACCESS_ACCESSIBILITY
+            null, // no direct permission for OP_READ_DEVICE_IDENTIFIERS
     };
 
     /**
@@ -1644,6 +1652,7 @@
             null, // WRITE_MEDIA_IMAGES
             null, // LEGACY_STORAGE
             null, // ACCESS_ACCESSIBILITY
+            null, // READ_DEVICE_IDENTIFIERS
     };
 
     /**
@@ -1740,6 +1749,7 @@
             false, // WRITE_MEDIA_IMAGES
             false, // LEGACY_STORAGE
             false, // ACCESS_ACCESSIBILITY
+            false, // READ_DEVICE_IDENTIFIERS
     };
 
     /**
@@ -1752,21 +1762,21 @@
             AppOpsManager.MODE_ALLOWED, // VIBRATE
             AppOpsManager.MODE_ALLOWED, // READ_CONTACTS
             AppOpsManager.MODE_ALLOWED, // WRITE_CONTACTS
-            AppOpsManager.MODE_DEFAULT, // READ_CALL_LOG
-            AppOpsManager.MODE_DEFAULT, // WRITE_CALL_LOG
+            AppOpsManager.MODE_ALLOWED, // READ_CALL_LOG
+            AppOpsManager.MODE_ALLOWED, // WRITE_CALL_LOG
             AppOpsManager.MODE_ALLOWED, // READ_CALENDAR
             AppOpsManager.MODE_ALLOWED, // WRITE_CALENDAR
             AppOpsManager.MODE_ALLOWED, // WIFI_SCAN
             AppOpsManager.MODE_ALLOWED, // POST_NOTIFICATION
             AppOpsManager.MODE_ALLOWED, // NEIGHBORING_CELLS
             AppOpsManager.MODE_ALLOWED, // CALL_PHONE
-            AppOpsManager.MODE_DEFAULT, // READ_SMS
+            AppOpsManager.MODE_ALLOWED, // READ_SMS
             AppOpsManager.MODE_IGNORED, // WRITE_SMS
-            AppOpsManager.MODE_DEFAULT, // RECEIVE_SMS
+            AppOpsManager.MODE_ALLOWED, // RECEIVE_SMS
             AppOpsManager.MODE_ALLOWED, // RECEIVE_EMERGENCY_BROADCAST
-            AppOpsManager.MODE_DEFAULT, // RECEIVE_MMS
-            AppOpsManager.MODE_DEFAULT, // RECEIVE_WAP_PUSH
-            AppOpsManager.MODE_DEFAULT, // SEND_SMS
+            AppOpsManager.MODE_ALLOWED, // RECEIVE_MMS
+            AppOpsManager.MODE_ALLOWED, // RECEIVE_WAP_PUSH
+            AppOpsManager.MODE_ALLOWED, // SEND_SMS
             AppOpsManager.MODE_ALLOWED, // READ_ICC_SMS
             AppOpsManager.MODE_ALLOWED, // WRITE_ICC_SMS
             AppOpsManager.MODE_DEFAULT, // WRITE_SETTINGS
@@ -1800,10 +1810,10 @@
             AppOpsManager.MODE_ALLOWED, // READ_PHONE_STATE
             AppOpsManager.MODE_ALLOWED, // ADD_VOICEMAIL
             AppOpsManager.MODE_ALLOWED, // USE_SIP
-            AppOpsManager.MODE_DEFAULT, // PROCESS_OUTGOING_CALLS
+            AppOpsManager.MODE_ALLOWED, // PROCESS_OUTGOING_CALLS
             AppOpsManager.MODE_ALLOWED, // USE_FINGERPRINT
             AppOpsManager.MODE_ALLOWED, // BODY_SENSORS
-            AppOpsManager.MODE_DEFAULT, // READ_CELL_BROADCASTS
+            AppOpsManager.MODE_ALLOWED, // READ_CELL_BROADCASTS
             AppOpsManager.MODE_ERRORED, // MOCK_LOCATION
             AppOpsManager.MODE_ALLOWED, // READ_EXTERNAL_STORAGE
             AppOpsManager.MODE_ALLOWED, // WRITE_EXTERNAL_STORAGE
@@ -1835,6 +1845,7 @@
             AppOpsManager.MODE_ERRORED, // WRITE_MEDIA_IMAGES
             AppOpsManager.MODE_DEFAULT, // LEGACY_STORAGE
             AppOpsManager.MODE_ALLOWED, // ACCESS_ACCESSIBILITY
+            AppOpsManager.MODE_ERRORED, // READ_DEVICE_IDENTIFIERS
     };
 
     /**
@@ -1934,6 +1945,7 @@
             false, // WRITE_MEDIA_IMAGES
             false, // LEGACY_STORAGE
             false, // ACCESS_ACCESSIBILITY
+            false, // READ_DEVICE_IDENTIFIERS
     };
 
     /**
diff --git a/core/java/android/app/TEST_MAPPING b/core/java/android/app/TEST_MAPPING
index 14c58e7..def1f45 100644
--- a/core/java/android/app/TEST_MAPPING
+++ b/core/java/android/app/TEST_MAPPING
@@ -27,5 +27,15 @@
                 }
             ]
         }
+    ],
+    "postsubmit": [
+        {
+            "file_patterns": ["(/|^)ActivityThreadClientTest.java"],
+            "name": "FrameworksMockingCoreTests"
+        },
+        {
+            "file_patterns": ["(/|^)ActivityThreadTest.java"],
+            "name": "FrameworksCoreTests"
+        }
     ]
 }
diff --git a/core/java/android/app/prediction/AppPredictor.java b/core/java/android/app/prediction/AppPredictor.java
index 3f2f209..cd635d6 100644
--- a/core/java/android/app/prediction/AppPredictor.java
+++ b/core/java/android/app/prediction/AppPredictor.java
@@ -271,7 +271,9 @@
             if (mCloseGuard != null) {
                 mCloseGuard.warnIfOpen();
             }
-            destroy();
+            if (!mIsClosed.get()) {
+                destroy();
+            }
         } finally {
             super.finalize();
         }
diff --git a/core/java/android/app/prediction/AppTarget.java b/core/java/android/app/prediction/AppTarget.java
index 4704661..61e4569 100644
--- a/core/java/android/app/prediction/AppTarget.java
+++ b/core/java/android/app/prediction/AppTarget.java
@@ -208,6 +208,7 @@
          * @hide
          */
         @Deprecated
+        @SystemApi
         public Builder(@NonNull AppTargetId id) {
             mId = id;
         }
@@ -243,7 +244,6 @@
 
         /**
          * @deprecated Use the appropriate constructor.
-         * @hide
          */
         @NonNull
         @Deprecated
@@ -258,7 +258,6 @@
 
         /**
          * @deprecated Use the appropriate constructor.
-         * @hide
          */
         @NonNull
         @Deprecated
diff --git a/core/java/android/app/role/RoleControllerManager.java b/core/java/android/app/role/RoleControllerManager.java
index 027e152..394a0d6 100644
--- a/core/java/android/app/role/RoleControllerManager.java
+++ b/core/java/android/app/role/RoleControllerManager.java
@@ -52,7 +52,10 @@
 
     private static final String LOG_TAG = RoleControllerManager.class.getSimpleName();
 
+    private static volatile ComponentName sRemoteServiceComponentName;
+
     private static final Object sRemoteServicesLock = new Object();
+
     /**
      * Global remote services (per user) used by all {@link RoleControllerManager managers}.
      */
@@ -62,18 +65,36 @@
     @NonNull
     private final RemoteService mRemoteService;
 
-    public RoleControllerManager(@NonNull Context context, @NonNull Handler handler) {
+    /**
+     * Initialize the remote service component name once so that we can avoid acquiring the
+     * PackageManagerService lock in constructor.
+     *
+     * @see #createWithInitializedRemoteServiceComponentName(Handler, Context)
+     */
+    public static void initializeRemoteServiceComponentName(@NonNull Context context) {
+        sRemoteServiceComponentName = getRemoteServiceComponentName(context);
+    }
+
+    /**
+     * Create a {@link RoleControllerManager} instance with the initialized remote service component
+     * name so that we can avoid acquiring the PackageManagerService lock in constructor.
+     *
+     * @see #initializeRemoteServiceComponentName(Context)
+     */
+    @NonNull
+    public static RoleControllerManager createWithInitializedRemoteServiceComponentName(
+            @NonNull Handler handler, @NonNull Context context) {
+        return new RoleControllerManager(sRemoteServiceComponentName, handler, context);
+    }
+
+    private RoleControllerManager(@NonNull ComponentName remoteServiceComponentName,
+            @NonNull Handler handler, @NonNull Context context) {
         synchronized (sRemoteServicesLock) {
             int userId = context.getUserId();
             RemoteService remoteService = sRemoteServices.get(userId);
             if (remoteService == null) {
-                Intent intent = new Intent(RoleControllerService.SERVICE_INTERFACE);
-                PackageManager packageManager = context.getPackageManager();
-                intent.setPackage(packageManager.getPermissionControllerPackageName());
-                ResolveInfo resolveInfo = packageManager.resolveService(intent, 0);
-
                 remoteService = new RemoteService(context.getApplicationContext(),
-                        resolveInfo.getComponentInfo().getComponentName(), handler, userId);
+                        remoteServiceComponentName, handler, userId);
                 sRemoteServices.put(userId, remoteService);
             }
             mRemoteService = remoteService;
@@ -81,7 +102,16 @@
     }
 
     public RoleControllerManager(@NonNull Context context) {
-        this(context, context.getMainThreadHandler());
+        this(getRemoteServiceComponentName(context), context.getMainThreadHandler(), context);
+    }
+
+    @NonNull
+    private static ComponentName getRemoteServiceComponentName(@NonNull Context context) {
+        Intent intent = new Intent(RoleControllerService.SERVICE_INTERFACE);
+        PackageManager packageManager = context.getPackageManager();
+        intent.setPackage(packageManager.getPermissionControllerPackageName());
+        ResolveInfo resolveInfo = packageManager.resolveService(intent, 0);
+        return resolveInfo.getComponentInfo().getComponentName();
     }
 
     /**
diff --git a/core/java/android/content/AutofillOptions.java b/core/java/android/content/AutofillOptions.java
index f59bc98..8fb9501 100644
--- a/core/java/android/content/AutofillOptions.java
+++ b/core/java/android/content/AutofillOptions.java
@@ -24,7 +24,7 @@
 import android.util.ArraySet;
 import android.util.Log;
 import android.view.autofill.AutofillManager;
-import android.view.contentcapture.ContentCaptureManager.ContentCaptureClient;
+import android.view.autofill.AutofillManager.AutofillClient;
 
 import java.io.PrintWriter;
 
@@ -73,10 +73,10 @@
     public boolean isAugmentedAutofillEnabled(@NonNull Context context) {
         if (!augmentedAutofillEnabled) return false;
 
-        final ContentCaptureClient contentCaptureClient = context.getContentCaptureClient();
-        if (contentCaptureClient == null) return false;
+        final AutofillClient autofillClient = context.getAutofillClient();
+        if (autofillClient == null) return false;
 
-        final ComponentName component = contentCaptureClient.contentCaptureClientGetComponentName();
+        final ComponentName component = autofillClient.autofillClientGetComponentName();
         return whitelistedActivitiesForAugmentedAutofill == null
                 || whitelistedActivitiesForAugmentedAutofill.contains(component);
     }
diff --git a/core/java/android/content/ContentProviderOperation.java b/core/java/android/content/ContentProviderOperation.java
index a646e49..c201e4d 100644
--- a/core/java/android/content/ContentProviderOperation.java
+++ b/core/java/android/content/ContentProviderOperation.java
@@ -283,14 +283,6 @@
         return mType == TYPE_ASSERT;
     }
 
-    private ContentProviderResult fail(String msg) throws OperationApplicationException {
-        if (mFailureAllowed) {
-            return new ContentProviderResult(msg);
-        } else {
-            throw new OperationApplicationException(msg);
-        }
-    }
-
     /**
      * Applies this operation using the given provider. The backRefs array is used to resolve any
      * back references that were requested using
@@ -307,20 +299,35 @@
      */
     public ContentProviderResult apply(ContentProvider provider, ContentProviderResult[] backRefs,
             int numBackRefs) throws OperationApplicationException {
+        if (mFailureAllowed) {
+            try {
+                return applyInternal(provider, backRefs, numBackRefs);
+            } catch (Exception e) {
+                return new ContentProviderResult(e.getMessage());
+            }
+        } else {
+            return applyInternal(provider, backRefs, numBackRefs);
+        }
+    }
+
+    private ContentProviderResult applyInternal(ContentProvider provider,
+            ContentProviderResult[] backRefs, int numBackRefs)
+            throws OperationApplicationException {
         ContentValues values = resolveValueBackReferences(backRefs, numBackRefs);
         String[] selectionArgs =
                 resolveSelectionArgsBackReferences(backRefs, numBackRefs);
 
         if (mType == TYPE_INSERT) {
-            Uri newUri = provider.insert(mUri, values);
-            if (newUri == null) {
-                Log.e(TAG, this.toString());
-                return fail("Insert into " + mUri + " returned no result");
+            final Uri newUri = provider.insert(mUri, values);
+            if (newUri != null) {
+                return new ContentProviderResult(newUri);
+            } else {
+                throw new OperationApplicationException(
+                        "Insert into " + mUri + " returned no result");
             }
-            return new ContentProviderResult(newUri);
         }
 
-        int numRows;
+        final int numRows;
         if (mType == TYPE_DELETE) {
             numRows = provider.delete(mUri, mSelection, selectionArgs);
         } else if (mType == TYPE_UPDATE) {
@@ -346,8 +353,7 @@
                             final String expectedValue = values.getAsString(projection[i]);
                             if (!TextUtils.equals(cursorValue, expectedValue)) {
                                 // Throw exception when expected values don't match
-                                Log.e(TAG, this.toString());
-                                return fail("Found value " + cursorValue
+                                throw new OperationApplicationException("Found value " + cursorValue
                                         + " when expected " + expectedValue + " for column "
                                         + projection[i]);
                             }
@@ -358,13 +364,12 @@
                 cursor.close();
             }
         } else {
-            Log.e(TAG, this.toString());
             throw new IllegalStateException("bad type, " + mType);
         }
 
         if (mExpectedCount != null && mExpectedCount != numRows) {
-            Log.e(TAG, this.toString());
-            return fail("Expected " + mExpectedCount + " rows but actual " + numRows);
+            throw new OperationApplicationException(
+                    "Expected " + mExpectedCount + " rows but actual " + numRows);
         }
 
         return new ContentProviderResult(numRows);
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 5a844aa..0ba457e 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -70,7 +70,6 @@
 import android.view.ViewDebug;
 import android.view.WindowManager;
 import android.view.autofill.AutofillManager.AutofillClient;
-import android.view.contentcapture.ContentCaptureManager.ContentCaptureClient;
 import android.view.textclassifier.TextClassificationManager;
 
 import java.io.File;
@@ -5414,14 +5413,6 @@
     /**
      * @hide
      */
-    @Nullable
-    public ContentCaptureClient getContentCaptureClient() {
-        return null;
-    }
-
-    /**
-     * @hide
-     */
     public final boolean isAutofillCompatibilityEnabled() {
         final AutofillOptions options = getAutofillOptions();
         return options != null && options.compatModeEnabled;
diff --git a/core/java/android/content/pm/ApplicationInfo.java b/core/java/android/content/pm/ApplicationInfo.java
index deb181f..9bc5f80 100644
--- a/core/java/android/content/pm/ApplicationInfo.java
+++ b/core/java/android/content/pm/ApplicationInfo.java
@@ -679,13 +679,13 @@
     public static final int PRIVATE_FLAG_IS_RESOURCE_OVERLAY = 1 << 28;
 
     /**
-     * Value for {@link #privateFlags}: If {@code true} this app allows
-     * shared/external storage media to be a sandboxed view that only contains
-     * files owned by the app.
+     * Value for {@link #privateFlags}: If {@code true} this app requests
+     * full external storage access. The request may not be honored due to
+     * policy or other reasons.
      *
      * @hide
      */
-    public static final int PRIVATE_FLAG_ALLOW_EXTERNAL_STORAGE_SANDBOX = 1 << 29;
+    public static final int PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE = 1 << 29;
 
     /**
      * Value for {@link #privateFlags}: whether this app is pre-installed on the
@@ -723,7 +723,7 @@
             PRIVATE_FLAG_HAS_FRAGILE_USER_DATA,
             PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE,
             PRIVATE_FLAG_ALLOW_AUDIO_PLAYBACK_CAPTURE,
-            PRIVATE_FLAG_ALLOW_EXTERNAL_STORAGE_SANDBOX,
+            PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE,
             PRIVATE_FLAG_ODM,
     })
     @Retention(RetentionPolicy.SOURCE)
@@ -1858,13 +1858,12 @@
     }
 
     /**
-     * If {@code true} this app allows shared/external storage media to be a
-     * sandboxed view that only contains files owned by the app.
+     * If {@code true} this app requested to run in the legacy storage mode.
      *
      * @hide
      */
-    public boolean isExternalStorageSandboxAllowed() {
-        return (privateFlags & PRIVATE_FLAG_ALLOW_EXTERNAL_STORAGE_SANDBOX) != 0;
+    public boolean hasRequestedLegacyExternalStorage() {
+        return (privateFlags & PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE) != 0;
     }
 
     private boolean isAllowedToUseHiddenApis() {
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 6ce6828..d2f0fb3 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -1505,13 +1505,14 @@
          * allows the app to hold that permission and whitelisting a soft restricted
          * permission allows the app to hold the permission in its full, unrestricted form.
          *
-         * <p>The whitelisted permissions would be applied as the {@link
-         * PackageManager#FLAG_PERMISSION_WHITELIST_INSTALLER installer whitelist}.
+         * <p> Permissions can also be immutably restricted which means that the whitelist
+         * state of the permission can be determined only at install time and cannot be
+         * changed on updated or at a later point via the package manager APIs.
          *
-         * @param permissions The restricted permissions to whitelist. Pass
-         * {@link #RESTRICTED_PERMISSIONS_ALL} to whitelist all permissions and
-         * <code>null</code> to clear. If you want to whitelist some permissions
-         * (not all) the list must contain at least one permission.
+         * <p>The whitelisted non-immutably restricted permissions would be added to
+         * the {@link PackageManager#FLAG_PERMISSION_WHITELIST_INSTALLER installer whitelist}
+         * while the immutably restricted permissions would be added to the {@link
+         * PackageManager#FLAG_PERMISSION_WHITELIST_SYSTEM system whitelist}
          *
          * @see PackageManager#addWhitelistedRestrictedPermission(String, String, int)
          * @see PackageManager#removeWhitelistedRestrictedPermission(String, String, int)
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index bdd80e32..0ea5200 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -3700,9 +3700,9 @@
         }
 
         if (sa.getBoolean(
-                R.styleable.AndroidManifestApplication_allowExternalStorageSandbox,
-                owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.Q)) {
-            ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_ALLOW_EXTERNAL_STORAGE_SANDBOX;
+                R.styleable.AndroidManifestApplication_requestLegacyExternalStorage,
+                owner.applicationInfo.targetSdkVersion < Build.VERSION_CODES.Q)) {
+            ai.privateFlags |= ApplicationInfo.PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE;
         }
 
         ai.maxAspectRatio = sa.getFloat(R.styleable.AndroidManifestApplication_maxAspectRatio, 0);
diff --git a/core/java/android/content/pm/PermissionInfo.java b/core/java/android/content/pm/PermissionInfo.java
index f838900..14340fe 100644
--- a/core/java/android/content/pm/PermissionInfo.java
+++ b/core/java/android/content/pm/PermissionInfo.java
@@ -341,6 +341,17 @@
     public static final int FLAG_SOFT_RESTRICTED = 1<<3;
 
     /**
+     * Flag for {@link #flags}, corresponding to <code>immutablyRestricted</code>
+     * value of {@link android.R.attr#permissionFlags}.
+     *
+     * <p>This permission is restricted immutably which means that its
+     * restriction state may be specified only on the first install of
+     * the app and will stay in this initial whitelist state until
+     * the app is uninstalled.
+     */
+    public static final int FLAG_IMMUTABLY_RESTRICTED = 1<<4;
+
+    /**
      * Flag for {@link #flags}, indicating that this permission has been
      * installed into the system's globally defined permissions.
      */
diff --git a/core/java/android/net/DnsResolver.java b/core/java/android/net/DnsResolver.java
index b6c4fe2..68826cb 100644
--- a/core/java/android/net/DnsResolver.java
+++ b/core/java/android/net/DnsResolver.java
@@ -197,7 +197,7 @@
         final FileDescriptor queryfd;
         try {
             queryfd = resNetworkSend((network != null
-                ? network.netId : NETID_UNSET), query, query.length, flags);
+                ? network.getNetIdForResolv() : NETID_UNSET), query, query.length, flags);
         } catch (ErrnoException e) {
             executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e)));
             return;
@@ -238,7 +238,7 @@
         final FileDescriptor queryfd;
         try {
             queryfd = resNetworkQuery((network != null
-                    ? network.netId : NETID_UNSET), domain, nsClass, nsType, flags);
+                    ? network.getNetIdForResolv() : NETID_UNSET), domain, nsClass, nsType, flags);
         } catch (ErrnoException e) {
             executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e)));
             return;
@@ -346,7 +346,8 @@
         if (queryIpv6) {
             try {
                 v6fd = resNetworkQuery((network != null
-                        ? network.netId : NETID_UNSET), domain, CLASS_IN, TYPE_AAAA, flags);
+                        ? network.getNetIdForResolv() : NETID_UNSET),
+                        domain, CLASS_IN, TYPE_AAAA, flags);
             } catch (ErrnoException e) {
                 executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e)));
                 return;
@@ -365,7 +366,8 @@
         if (queryIpv4) {
             try {
                 v4fd = resNetworkQuery((network != null
-                        ? network.netId : NETID_UNSET), domain, CLASS_IN, TYPE_A, flags);
+                        ? network.getNetIdForResolv() : NETID_UNSET),
+                        domain, CLASS_IN, TYPE_A, flags);
             } catch (ErrnoException e) {
                 if (queryIpv6) resNetworkCancel(v6fd);  // Closes fd, marks it invalid.
                 executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e)));
@@ -423,7 +425,7 @@
         final FileDescriptor queryfd;
         try {
             queryfd = resNetworkQuery((network != null
-                    ? network.netId : NETID_UNSET), domain, CLASS_IN, nsType, flags);
+                    ? network.getNetIdForResolv() : NETID_UNSET), domain, CLASS_IN, nsType, flags);
         } catch (ErrnoException e) {
             executor.execute(() -> callback.onError(new DnsException(ERROR_SYSTEM, e)));
             return;
diff --git a/core/java/android/net/SntpClient.java b/core/java/android/net/SntpClient.java
index b8d7cf1..a55d9d0 100644
--- a/core/java/android/net/SntpClient.java
+++ b/core/java/android/net/SntpClient.java
@@ -20,6 +20,8 @@
 import android.os.SystemClock;
 import android.util.Log;
 
+import com.android.internal.util.TrafficStatsConstants;
+
 import java.net.DatagramPacket;
 import java.net.DatagramSocket;
 import java.net.InetAddress;
@@ -99,7 +101,8 @@
 
     public boolean requestTime(InetAddress address, int port, int timeout, Network network) {
         DatagramSocket socket = null;
-        final int oldTag = TrafficStats.getAndSetThreadStatsTag(TrafficStats.TAG_SYSTEM_NTP);
+        final int oldTag = TrafficStats.getAndSetThreadStatsTag(
+                TrafficStatsConstants.TAG_SYSTEM_NTP);
         try {
             socket = new DatagramSocket();
             network.bindSocket(socket);
diff --git a/core/java/android/net/TrafficStats.java b/core/java/android/net/TrafficStats.java
index 49c6f74..4332d8a 100644
--- a/core/java/android/net/TrafficStats.java
+++ b/core/java/android/net/TrafficStats.java
@@ -90,6 +90,42 @@
     public static final int UID_TETHERING = -5;
 
     /**
+     * Tag values in this range are reserved for the network stack. The network stack is
+     * running as UID {@link android.os.Process.NETWORK_STACK_UID} when in the mainline
+     * module separate process, and as the system UID otherwise.
+     */
+    /** @hide */
+    @SystemApi
+    public static final int TAG_NETWORK_STACK_RANGE_START = 0xFFFFFD00;
+    /** @hide */
+    @SystemApi
+    public static final int TAG_NETWORK_STACK_RANGE_END = 0xFFFFFEFF;
+
+    /**
+     * Tags between 0xFFFFFF00 and 0xFFFFFFFF are reserved and used internally by system services
+     * like DownloadManager when performing traffic on behalf of an application.
+     */
+    // Please note there is no enforcement of these constants, so do not rely on them to
+    // determine that the caller is a system caller.
+    /** @hide */
+    @SystemApi
+    public static final int TAG_SYSTEM_IMPERSONATION_RANGE_START = 0xFFFFFF00;
+    /** @hide */
+    @SystemApi
+    public static final int TAG_SYSTEM_IMPERSONATION_RANGE_END = 0xFFFFFF0F;
+
+    /**
+     * Tag values between these ranges are reserved for the network stack to do traffic
+     * on behalf of applications. It is a subrange of the range above.
+     */
+    /** @hide */
+    @SystemApi
+    public static final int TAG_NETWORK_STACK_IMPERSONATION_RANGE_START = 0xFFFFFF80;
+    /** @hide */
+    @SystemApi
+    public static final int TAG_NETWORK_STACK_IMPERSONATION_RANGE_END = 0xFFFFFF8F;
+
+    /**
      * Default tag value for {@link DownloadManager} traffic.
      *
      * @hide
@@ -127,26 +163,9 @@
      */
     public static final int TAG_SYSTEM_APP = 0xFFFFFF05;
 
+    // TODO : remove this constant when Wifi code is updated
     /** @hide */
-    @SystemApi
-    @TestApi
-    public static final int TAG_SYSTEM_DHCP = 0xFFFFFF40;
-    /** @hide */
-    public static final int TAG_SYSTEM_NTP = 0xFFFFFF41;
-    /** @hide */
-    @SystemApi
-    @TestApi
     public static final int TAG_SYSTEM_PROBE = 0xFFFFFF42;
-    /** @hide */
-    public static final int TAG_SYSTEM_NEIGHBOR = 0xFFFFFF43;
-    /** @hide */
-    public static final int TAG_SYSTEM_GPS = 0xFFFFFF44;
-    /** @hide */
-    public static final int TAG_SYSTEM_PAC = 0xFFFFFF45;
-    /** @hide */
-    @SystemApi
-    @TestApi
-    public static final int TAG_SYSTEM_DHCP_SERVER = 0xFFFFFF46;
 
     private static INetworkStatsService sStatsService;
 
diff --git a/core/java/android/os/Environment.java b/core/java/android/os/Environment.java
index ed5c1b1..dde1e6a 100644
--- a/core/java/android/os/Environment.java
+++ b/core/java/android/os/Environment.java
@@ -1148,15 +1148,9 @@
         final Context context = AppGlobals.getInitialApplication();
         final AppOpsManager appOps = context.getSystemService(AppOpsManager.class);
 
-        final boolean hasLegacy = appOps.checkOpNoThrow(AppOpsManager.OP_LEGACY_STORAGE,
+        return appOps.checkOpNoThrow(AppOpsManager.OP_LEGACY_STORAGE,
                 context.getApplicationInfo().uid,
-                context.getOpPackageName()) == AppOpsManager.MODE_ALLOWED;
-
-        // STOPSHIP: only use app-op once permission model has fully landed
-        final boolean requestedLegacy = !AppGlobals.getInitialApplication().getApplicationInfo()
-                .isExternalStorageSandboxAllowed();
-
-        return !(hasLegacy || requestedLegacy);
+                context.getOpPackageName()) != AppOpsManager.MODE_ALLOWED;
     }
 
     static File getDirectory(String variableName, String defaultPath) {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 335ed21..488f417 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -5802,6 +5802,14 @@
                 "autofill_field_classification";
 
         /**
+         * Boolean indicating if the dark mode dialog shown on first toggle has been seen.
+         *
+         * @hide
+         */
+        public static final String DARK_MODE_DIALOG_SEEN =
+                "dark_mode_dialog_seen";
+
+        /**
          * Defines value returned by {@link android.service.autofill.UserData#getMaxUserDataSize()}.
          *
          * @hide
@@ -8849,6 +8857,7 @@
             SILENCE_NOTIFICATION_GESTURE_COUNT,
             SILENCE_CALL_GESTURE_COUNT,
             SILENCE_TIMER_GESTURE_COUNT,
+            DARK_MODE_DIALOG_SEEN
         };
 
         /**
@@ -9029,6 +9038,7 @@
             VALIDATORS.put(SILENCE_CALL_GESTURE_COUNT, SILENCE_GESTURE_COUNT_VALIDATOR);
             VALIDATORS.put(SILENCE_NOTIFICATION_GESTURE_COUNT, SILENCE_GESTURE_COUNT_VALIDATOR);
             VALIDATORS.put(ODI_CAPTIONS_ENABLED, ODI_CAPTIONS_ENABLED_VALIDATOR);
+            VALIDATORS.put(DARK_MODE_DIALOG_SEEN, BOOLEAN_VALIDATOR);
         }
 
         /**
diff --git a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
index b00eb8a..656127a 100644
--- a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
+++ b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
@@ -27,6 +27,7 @@
 import android.content.ComponentName;
 import android.content.Intent;
 import android.graphics.Rect;
+import android.os.Build;
 import android.os.CancellationSignal;
 import android.os.Handler;
 import android.os.IBinder;
@@ -67,9 +68,8 @@
 
     private static final String TAG = AugmentedAutofillService.class.getSimpleName();
 
-    // TODO(b/123100811): STOPSHIP use dynamic value, or change to false
-    static final boolean DEBUG = true;
-    static final boolean VERBOSE = false;
+    static boolean sDebug = Build.IS_USER ? false : true;
+    static boolean sVerbose = false;
 
     /**
      * The {@link Intent} that must be declared as handled by the service.
@@ -87,9 +87,9 @@
     private final IAugmentedAutofillService mInterface = new IAugmentedAutofillService.Stub() {
 
         @Override
-        public void onConnected() {
+        public void onConnected(boolean debug, boolean verbose) {
             mHandler.sendMessage(obtainMessage(AugmentedAutofillService::handleOnConnected,
-                    AugmentedAutofillService.this));
+                    AugmentedAutofillService.this, debug, verbose));
         }
 
         @Override
@@ -190,7 +190,12 @@
     public void onDisconnected() {
     }
 
-    private void handleOnConnected() {
+    private void handleOnConnected(boolean debug, boolean verbose) {
+        if (sDebug || debug) {
+            Log.d(TAG, "handleOnConnected(): debug=" + debug + ", verbose=" + verbose);
+        }
+        sDebug = debug;
+        sVerbose = verbose;
         onConnected();
     }
 
@@ -215,7 +220,7 @@
             mAutofillProxies.put(sessionId,  proxy);
         } else {
             // TODO(b/123099468): figure out if it's ok to reuse the proxy; add logging
-            if (DEBUG) Log.d(TAG, "Reusing proxy for session " + sessionId);
+            if (sDebug) Log.d(TAG, "Reusing proxy for session " + sessionId);
             proxy.update(focusedId, focusedValue, callback);
         }
 
@@ -248,11 +253,11 @@
 
     private void handleOnUnbind() {
         if (mAutofillProxies == null) {
-            if (DEBUG) Log.d(TAG, "onUnbind(): no proxy to destroy");
+            if (sDebug) Log.d(TAG, "onUnbind(): no proxy to destroy");
             return;
         }
         final int size = mAutofillProxies.size();
-        if (DEBUG) Log.d(TAG, "onUnbind(): destroying " + size + " proxies");
+        if (sDebug) Log.d(TAG, "onUnbind(): destroying " + size + " proxies");
         for (int i = 0; i < size; i++) {
             final AutofillProxy proxy = mAutofillProxies.valueAt(i);
             try {
@@ -373,7 +378,7 @@
                     return null;
                 }
                 if (rect == null) {
-                    if (DEBUG) Log.d(TAG, "getViewCoordinates(" + mFocusedId + ") returned null");
+                    if (sDebug) Log.d(TAG, "getViewCoordinates(" + mFocusedId + ") returned null");
                     return null;
                 }
                 mSmartSuggestion = new SystemPopupPresentationParams(this, rect);
@@ -410,7 +415,7 @@
         public void requestShowFillUi(int width, int height, Rect anchorBounds,
                 IAutofillWindowPresenter presenter) throws RemoteException {
             if (mCancellationSignal.isCanceled()) {
-                if (VERBOSE) {
+                if (sVerbose) {
                     Log.v(TAG, "requestShowFillUi() not showing because request is cancelled");
                 }
                 return;
@@ -462,7 +467,7 @@
                 case REPORT_EVENT_ON_SUCCESS:
                     if (mFirstOnSuccessTime == 0) {
                         mFirstOnSuccessTime = SystemClock.elapsedRealtime();
-                        if (DEBUG) {
+                        if (sDebug) {
                             Slog.d(TAG, "Service responded in " + TimeUtils.formatDuration(
                                     mFirstOnSuccessTime - mFirstRequestTime));
                         }
@@ -476,7 +481,7 @@
                 case REPORT_EVENT_UI_SHOWN:
                     if (mUiFirstShownTime == 0) {
                         mUiFirstShownTime = SystemClock.elapsedRealtime();
-                        if (DEBUG) {
+                        if (sDebug) {
                             Slog.d(TAG, "UI shown in " + TimeUtils.formatDuration(
                                     mUiFirstShownTime - mFirstRequestTime));
                         }
@@ -485,7 +490,7 @@
                 case REPORT_EVENT_UI_DESTROYED:
                     if (mUiFirstDestroyedTime == 0) {
                         mUiFirstDestroyedTime = SystemClock.elapsedRealtime();
-                        if (DEBUG) {
+                        if (sDebug) {
                             Slog.d(TAG, "UI destroyed in " + TimeUtils.formatDuration(
                                     mUiFirstDestroyedTime - mFirstRequestTime));
                         }
@@ -541,7 +546,7 @@
         private void destroy() {
             synchronized (mLock) {
                 if (mFillWindow != null) {
-                    if (DEBUG) Log.d(TAG, "destroying window");
+                    if (sDebug) Log.d(TAG, "destroying window");
                     mFillWindow.destroy();
                     mFillWindow = null;
                 }
diff --git a/core/java/android/service/autofill/augmented/FillCallback.java b/core/java/android/service/autofill/augmented/FillCallback.java
index b989dd9..33e6a8c 100644
--- a/core/java/android/service/autofill/augmented/FillCallback.java
+++ b/core/java/android/service/autofill/augmented/FillCallback.java
@@ -15,7 +15,7 @@
  */
 package android.service.autofill.augmented;
 
-import static android.service.autofill.augmented.AugmentedAutofillService.DEBUG;
+import static android.service.autofill.augmented.AugmentedAutofillService.sDebug;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -48,7 +48,7 @@
      * could not provide autofill for the request.
      */
     public void onSuccess(@Nullable FillResponse response) {
-        if (DEBUG) Log.d(TAG, "onSuccess(): " + response);
+        if (sDebug) Log.d(TAG, "onSuccess(): " + response);
 
         mProxy.report(AutofillProxy.REPORT_EVENT_ON_SUCCESS);
         if (response == null) return;
diff --git a/core/java/android/service/autofill/augmented/FillController.java b/core/java/android/service/autofill/augmented/FillController.java
index 67f23d5..63ec2d8 100644
--- a/core/java/android/service/autofill/augmented/FillController.java
+++ b/core/java/android/service/autofill/augmented/FillController.java
@@ -15,7 +15,7 @@
  */
 package android.service.autofill.augmented;
 
-import static android.service.autofill.augmented.AugmentedAutofillService.DEBUG;
+import static android.service.autofill.augmented.AugmentedAutofillService.sDebug;
 
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
@@ -56,7 +56,7 @@
     public void autofill(@NonNull List<Pair<AutofillId, AutofillValue>> values) {
         Preconditions.checkNotNull(values);
 
-        if (DEBUG) {
+        if (sDebug) {
             Log.d(TAG, "autofill() with " + values.size() + " values");
         }
 
diff --git a/core/java/android/service/autofill/augmented/FillWindow.java b/core/java/android/service/autofill/augmented/FillWindow.java
index bd532a3..6a29d48 100644
--- a/core/java/android/service/autofill/augmented/FillWindow.java
+++ b/core/java/android/service/autofill/augmented/FillWindow.java
@@ -15,8 +15,8 @@
  */
 package android.service.autofill.augmented;
 
-import static android.service.autofill.augmented.AugmentedAutofillService.DEBUG;
-import static android.service.autofill.augmented.AugmentedAutofillService.VERBOSE;
+import static android.service.autofill.augmented.AugmentedAutofillService.sDebug;
+import static android.service.autofill.augmented.AugmentedAutofillService.sVerbose;
 
 import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
 
@@ -100,7 +100,7 @@
      * @throws IllegalArgumentException if the area is not compatible with this window
      */
     public boolean update(@NonNull Area area, @NonNull View rootView, long flags) {
-        if (DEBUG) {
+        if (sDebug) {
             Log.d(TAG, "Updating " + area + " + with " + rootView);
         }
         // TODO(b/123100712): add test case for null
@@ -141,7 +141,7 @@
             mFillView.setOnTouchListener(
                     (view, motionEvent) -> {
                         if (motionEvent.getAction() == MotionEvent.ACTION_OUTSIDE) {
-                            if (VERBOSE) Log.v(TAG, "Outside touch detected, hiding the window");
+                            if (sVerbose) Log.v(TAG, "Outside touch detected, hiding the window");
                             hide();
                         }
                         return false;
@@ -149,7 +149,7 @@
             );
             mShowing = false;
             mBounds = new Rect(area.getBounds());
-            if (DEBUG) {
+            if (sDebug) {
                 Log.d(TAG, "Created FillWindow: params= " + smartSuggestion + " view=" + rootView);
             }
             mUpdateCalled = true;
@@ -162,7 +162,7 @@
     /** @hide */
     void show() {
         // TODO(b/123100712): check if updated first / throw exception
-        if (DEBUG) Log.d(TAG, "show()");
+        if (sDebug) Log.d(TAG, "show()");
         synchronized (mLock) {
             checkNotDestroyedLocked();
             if (mWm == null || mFillView == null) {
@@ -187,7 +187,7 @@
      * <p>The window is not destroyed and can be shown again
      */
     private void hide() {
-        if (DEBUG) Log.d(TAG, "hide()");
+        if (sDebug) Log.d(TAG, "hide()");
         synchronized (mLock) {
             checkNotDestroyedLocked();
             if (mWm == null || mFillView == null) {
@@ -204,7 +204,7 @@
     }
 
     private void handleShow(WindowManager.LayoutParams p) {
-        if (DEBUG) Log.d(TAG, "handleShow()");
+        if (sDebug) Log.d(TAG, "handleShow()");
         synchronized (mLock) {
             if (mWm != null && mFillView != null) {
                 p.flags |= WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
@@ -219,7 +219,7 @@
     }
 
     private void handleHide() {
-        if (DEBUG) Log.d(TAG, "handleHide()");
+        if (sDebug) Log.d(TAG, "handleHide()");
         synchronized (mLock) {
             if (mWm != null && mFillView != null && mShowing) {
                 mWm.removeView(mFillView);
@@ -234,7 +234,7 @@
      * <p>Once destroyed, this window cannot be used anymore
      */
     public void destroy() {
-        if (DEBUG) {
+        if (sDebug) {
             Log.d(TAG,
                     "destroy(): mDestroyed=" + mDestroyed + " mShowing=" + mShowing + " mFillView="
                             + mFillView);
@@ -296,13 +296,13 @@
         @Override
         public void show(WindowManager.LayoutParams p, Rect transitionEpicenter,
                 boolean fitsSystemWindows, int layoutDirection) {
-            if (DEBUG) Log.d(TAG, "FillWindowPresenter.show()");
+            if (sDebug) Log.d(TAG, "FillWindowPresenter.show()");
             mUiThreadHandler.sendMessage(obtainMessage(FillWindow::handleShow, FillWindow.this, p));
         }
 
         @Override
         public void hide(Rect transitionEpicenter) {
-            if (DEBUG) Log.d(TAG, "FillWindowPresenter.hide()");
+            if (sDebug) Log.d(TAG, "FillWindowPresenter.hide()");
             mUiThreadHandler.sendMessage(obtainMessage(FillWindow::handleHide, FillWindow.this));
         }
     }
diff --git a/core/java/android/service/autofill/augmented/IAugmentedAutofillService.aidl b/core/java/android/service/autofill/augmented/IAugmentedAutofillService.aidl
index 5096811..103fc4d 100644
--- a/core/java/android/service/autofill/augmented/IAugmentedAutofillService.aidl
+++ b/core/java/android/service/autofill/augmented/IAugmentedAutofillService.aidl
@@ -31,7 +31,7 @@
  * @hide
  */
 oneway interface IAugmentedAutofillService {
-    void onConnected();
+    void onConnected(boolean debug, boolean verbose);
     void onDisconnected();
     void onFillRequest(int sessionId, in IBinder autofillManagerClient, int taskId,
                        in ComponentName activityComponent, in AutofillId focusedId,
diff --git a/core/java/android/service/contentcapture/ContentCaptureService.java b/core/java/android/service/contentcapture/ContentCaptureService.java
index d8614a9..02ce873 100644
--- a/core/java/android/service/contentcapture/ContentCaptureService.java
+++ b/core/java/android/service/contentcapture/ContentCaptureService.java
@@ -86,11 +86,28 @@
      * <code>&lt;{@link
      * android.R.styleable#ContentCaptureService content-capture-service}&gt;</code> tag.
      *
-     * <p>This is a a sample XML file configuring a ContentCaptureService:
-     * <pre> &lt;content-capture-service
-     *     android:settingsActivity="foo.bar.SettingsActivity"
-     *     . . .
-     * /&gt;</pre>
+     * <p>Here's an example of how to use it on {@code AndroidManifest.xml}:
+     *
+     * <pre>
+     * &lt;service android:name=".MyContentCaptureService"
+     *     android:permission="android.permission.BIND_CONTENT_CAPTURE_SERVICE"&gt;
+     *   &lt;intent-filter&gt;
+     *     &lt;action android:name="android.service.contentcapture.ContentCaptureService" /&gt;
+     *   &lt;/intent-filter&gt;
+     *
+     *   &lt;meta-data
+     *       android:name="android.content_capture"
+     *       android:resource="@xml/my_content_capture_service"/&gt;
+     * &lt;/service&gt;
+     * </pre>
+     *
+     * <p>And then on {@code res/xml/my_content_capture_service.xml}:
+     *
+     * <pre>
+     *   &lt;content-capture-service xmlns:android="http://schemas.android.com/apk/res/android"
+     *       android:settingsActivity="my.package.MySettingsActivity"&gt;
+     *   &lt;/content-capture-service&gt;
+     * </pre>
      */
     public static final String SERVICE_META_DATA = "android.content_capture";
 
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index feff9db..f2aaead 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -63,7 +63,6 @@
         DEFAULT_FLAGS.put(FORCE_GLOBAL_ACTIONS_GRID_ENABLED, "false");
         DEFAULT_FLAGS.put(GLOBAL_ACTIONS_PANEL_ENABLED, "true");
         DEFAULT_FLAGS.put(PIXEL_WALLPAPER_CATEGORY_SWITCH, "false");
-        DEFAULT_FLAGS.put("settings_wifi_details_saved_screen", "true");
         DEFAULT_FLAGS.put("settings_wifi_details_datausage_header", "false");
     }
 
diff --git a/core/java/android/view/GestureExclusionTracker.java b/core/java/android/view/GestureExclusionTracker.java
index 8eccc04..6fcdd71 100644
--- a/core/java/android/view/GestureExclusionTracker.java
+++ b/core/java/android/view/GestureExclusionTracker.java
@@ -20,6 +20,8 @@
 import android.annotation.Nullable;
 import android.graphics.Rect;
 
+import com.android.internal.util.Preconditions;
+
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.Collections;
@@ -31,6 +33,8 @@
  */
 class GestureExclusionTracker {
     private boolean mGestureExclusionViewsChanged = false;
+    private boolean mRootGestureExclusionRectsChanged = false;
+    private List<Rect> mRootGestureExclusionRects = Collections.emptyList();
     private List<GestureExclusionViewInfo> mGestureExclusionViewInfos = new ArrayList<>();
     private List<Rect> mGestureExclusionRects = Collections.emptyList();
 
@@ -59,9 +63,9 @@
 
     @Nullable
     public List<Rect> computeChangedRects() {
-        boolean changed = false;
+        boolean changed = mRootGestureExclusionRectsChanged;
         final Iterator<GestureExclusionViewInfo> i = mGestureExclusionViewInfos.iterator();
-        final List<Rect> rects = new ArrayList<>();
+        final List<Rect> rects = new ArrayList<>(mRootGestureExclusionRects);
         while (i.hasNext()) {
             final GestureExclusionViewInfo info = i.next();
             switch (info.update()) {
@@ -79,6 +83,7 @@
         }
         if (changed || mGestureExclusionViewsChanged) {
             mGestureExclusionViewsChanged = false;
+            mRootGestureExclusionRectsChanged = false;
             if (!mGestureExclusionRects.equals(rects)) {
                 mGestureExclusionRects = rects;
                 return rects;
@@ -87,6 +92,17 @@
         return null;
     }
 
+    public void setRootSystemGestureExclusionRects(@NonNull List<Rect> rects) {
+        Preconditions.checkNotNull(rects, "rects must not be null");
+        mRootGestureExclusionRects = rects;
+        mRootGestureExclusionRectsChanged = true;
+    }
+
+    @NonNull
+    public List<Rect> getRootSystemGestureExclusionRects() {
+        return mRootGestureExclusionRects;
+    }
+
     private static class GestureExclusionViewInfo {
         public static final int CHANGED = 0;
         public static final int UNCHANGED = 1;
diff --git a/core/java/android/view/ImeInsetsSourceConsumer.java b/core/java/android/view/ImeInsetsSourceConsumer.java
index 2ba1e01..d415387 100644
--- a/core/java/android/view/ImeInsetsSourceConsumer.java
+++ b/core/java/android/view/ImeInsetsSourceConsumer.java
@@ -85,6 +85,7 @@
     @Override
     public void onWindowFocusLost() {
         mHasWindowFocus = false;
+        getImm().unregisterImeConsumer(this);
     }
 
     /**
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index c3a9465..096c988 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -11648,14 +11648,11 @@
     }
 
     /**
-     * When screen readers (one type of accessibility tool) decide what should be read to the
-     * user, they typically look for input focusable ({@link #isFocusable()}) parents of
-     * non-focusable text items, and read those focusable parents and their non-focusable children
-     * as a unit. In some situations, this behavior is desirable for views that should not take
-     * input focus. Setting an item to be screen reader focusable requests that the view be
-     * treated as a unit by screen readers without any effect on input focusability. The default
-     * value of {@code false} lets screen readers use other signals, like focusable, to determine
-     * how to group items.
+     * Sets whether this View should be a focusable element for screen readers
+     * and include non-focusable Views from its subtree when providing feedback.
+     * <p>
+     * Note: this is similar to using <a href="#attr_android:focusable">{@code android:focusable},
+     * but does not impact input focus behavior.
      *
      * @param screenReaderFocusable Whether the view should be treated as a unit by screen reader
      *                              accessibility tools.
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 5ca70ba..7ad118e 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -3829,6 +3829,24 @@
     }
 
     /**
+     * Set the root-level system gesture exclusion rects. These are added to those provided by
+     * the root's view hierarchy.
+     */
+    public void setRootSystemGestureExclusionRects(@NonNull List<Rect> rects) {
+        mGestureExclusionTracker.setRootSystemGestureExclusionRects(rects);
+        mHandler.sendEmptyMessage(MSG_SYSTEM_GESTURE_EXCLUSION_CHANGED);
+    }
+
+    /**
+     * Returns the root-level system gesture exclusion rects. These do not include those provided by
+     * the root's view hierarchy.
+     */
+    @NonNull
+    public List<Rect> getRootSystemGestureExclusionRects() {
+        return mGestureExclusionTracker.getRootSystemGestureExclusionRects();
+    }
+
+    /**
      * Requests that the root render node is invalidated next time we perform a draw, such that
      * {@link WindowCallbacks#onPostDraw} gets called.
      */
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index fc9d8c2..b0ec621 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -48,6 +48,7 @@
 import android.transition.TransitionManager;
 import android.view.accessibility.AccessibilityEvent;
 
+import java.util.Collections;
 import java.util.List;
 
 /**
@@ -2397,6 +2398,53 @@
         return false;
     }
 
+    /**
+     * Sets a list of areas within this window's coordinate space where the system should not
+     * intercept touch or other pointing device gestures.
+     *
+     * <p>This method should be used by apps that make use of
+     * {@link #takeSurface(SurfaceHolder.Callback2)} and do not have a view hierarchy available.
+     * Apps that do have a view hierarchy should use
+     * {@link View#setSystemGestureExclusionRects(List)} instead. This method does not modify or
+     * replace the gesture exclusion rects populated by individual views in this window's view
+     * hierarchy using {@link View#setSystemGestureExclusionRects(List)}.</p>
+     *
+     * <p>Use this to tell the system which specific sub-areas of a view need to receive gesture
+     * input in order to function correctly in the presence of global system gestures that may
+     * conflict. For example, if the system wishes to capture swipe-in-from-screen-edge gestures
+     * to provide system-level navigation functionality, a view such as a navigation drawer
+     * container can mark the left (or starting) edge of itself as requiring gesture capture
+     * priority using this API. The system may then choose to relax its own gesture recognition
+     * to allow the app to consume the user's gesture. It is not necessary for an app to register
+     * exclusion rects for broadly spanning regions such as the entirety of a
+     * <code>ScrollView</code> or for simple press and release click targets such as
+     * <code>Button</code>. Mark an exclusion rect when interacting with a view requires
+     * a precision touch gesture in a small area in either the X or Y dimension, such as
+     * an edge swipe or dragging a <code>SeekBar</code> thumb.</p>
+     *
+     * <p>Do not modify the provided list after this method is called.</p>
+     *
+     * @param rects A list of precision gesture regions that this window needs to function correctly
+     */
+    @SuppressWarnings("unused")
+    public void setSystemGestureExclusionRects(@NonNull List<Rect> rects) {
+        throw new UnsupportedOperationException("window does not support gesture exclusion rects");
+    }
+
+    /**
+     * Retrieve the list of areas within this window's coordinate space where the system should not
+     * intercept touch or other pointing device gestures. This is the list as set by
+     * {@link #setSystemGestureExclusionRects(List)} or an empty list if
+     * {@link #setSystemGestureExclusionRects(List)} has not been called. It does not include
+     * exclusion rects set by this window's view hierarchy.
+     *
+     * @return a list of system gesture exclusion rects specific to this window
+     */
+    @NonNull
+    public List<Rect> getSystemGestureExclusionRects() {
+        return Collections.emptyList();
+    }
+
     /** @hide */
     public void setTheme(int resId) {
     }
diff --git a/core/java/android/view/autofill/AutofillManagerInternal.java b/core/java/android/view/autofill/AutofillManagerInternal.java
index 3de1a03..a07d46d 100644
--- a/core/java/android/view/autofill/AutofillManagerInternal.java
+++ b/core/java/android/view/autofill/AutofillManagerInternal.java
@@ -45,4 +45,12 @@
     @Nullable
     public abstract AutofillOptions getAutofillOptions(@NonNull String packageName,
             long versionCode, @UserIdInt int userId);
+
+    /**
+     * Checks whether the given {@code uid} owns the
+     * {@link android.service.autofill.augmented.AugmentedAutofillService} implementation associated
+     * with the given {@code userId}.
+     */
+    public abstract boolean isAugmentedAutofillServiceForUser(@NonNull int callingUid,
+            @UserIdInt int userId);
 }
diff --git a/core/java/android/view/contentcapture/ContentCaptureCondition.java b/core/java/android/view/contentcapture/ContentCaptureCondition.java
index 6f9d4d3..54ebf55 100644
--- a/core/java/android/view/contentcapture/ContentCaptureCondition.java
+++ b/core/java/android/view/contentcapture/ContentCaptureCondition.java
@@ -35,7 +35,8 @@
 public final class ContentCaptureCondition implements Parcelable {
 
     /**
-     * When set, package should use the {@link LocusId#getId()} as a regular expression.
+     * When set, package should use the {@link LocusId#getId()} as a regular expression (using the
+     * {@link java.util.regex.Pattern} format).
      */
     public static final int FLAG_IS_REGEX = 0x2;
 
diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
index 7a6e2ad..26454c0 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -343,15 +343,6 @@
     private MainContentCaptureSession mMainSession;
 
     /** @hide */
-    public interface ContentCaptureClient {
-        /**
-         * Gets the component name of the client.
-         */
-        @NonNull
-        ComponentName contentCaptureClientGetComponentName();
-    }
-
-    /** @hide */
     public ContentCaptureManager(@NonNull Context context,
             @NonNull IContentCaptureManager service, @NonNull ContentCaptureOptions options) {
         mContext = Preconditions.checkNotNull(context, "context cannot be null");
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index 5e00425..fd73856 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -1951,6 +1951,23 @@
     }
 
     /**
+     * Unregister for IME state callbacks and applying visibility in
+     * {@link android.view.ImeInsetsSourceConsumer}.
+     * @hide
+     */
+    public void unregisterImeConsumer(@NonNull ImeInsetsSourceConsumer imeInsetsConsumer) {
+        if (imeInsetsConsumer == null) {
+            throw new IllegalStateException("ImeInsetsSourceConsumer cannot be null.");
+        }
+
+        synchronized (mH) {
+            if (mImeInsetsConsumer == imeInsetsConsumer) {
+                mImeInsetsConsumer = null;
+            }
+        }
+    }
+
+    /**
      * Call showSoftInput with currently focused view.
      * @return {@code true} if IME can be shown.
      * @hide
diff --git a/core/java/android/view/textclassifier/ExtrasUtils.java b/core/java/android/view/textclassifier/ExtrasUtils.java
index 7b23674..11e0e2c 100644
--- a/core/java/android/view/textclassifier/ExtrasUtils.java
+++ b/core/java/android/view/textclassifier/ExtrasUtils.java
@@ -36,6 +36,7 @@
 // TODO: Make this a TestApi for CTS testing.
 public final class ExtrasUtils {
 
+    // Keys for response objects.
     private static final String SERIALIZED_ENTITIES_DATA = "serialized-entities-data";
     private static final String ENTITIES_EXTRAS = "entities-extras";
     private static final String ACTION_INTENT = "action-intent";
@@ -48,6 +49,10 @@
     private static final String TEXT_LANGUAGES = "text-languages";
     private static final String ENTITIES = "entities";
 
+    // Keys for request objects.
+    private static final String IS_SERIALIZED_ENTITY_DATA_ENABLED =
+            "is-serialized-entity-data-enabled";
+
     private ExtrasUtils() {}
 
     /**
@@ -308,7 +313,23 @@
     /**
      * Returns a list of entities contained in the {@code extra}.
      */
+    @Nullable
     public static List<Bundle> getEntities(Bundle container) {
         return container.getParcelableArrayList(ENTITIES);
     }
+
+    /**
+     * Whether the annotator should populate serialized entity data into the result object.
+     */
+    public static boolean isSerializedEntityDataEnabled(TextLinks.Request request) {
+        return request.getExtras().getBoolean(IS_SERIALIZED_ENTITY_DATA_ENABLED);
+    }
+
+    /**
+     * To indicate whether the annotator should populate serialized entity data in the result
+     * object.
+     */
+    public static void putIsSerializedEntityDataEnabled(Bundle bundle, boolean isEnabled) {
+        bundle.putBoolean(IS_SERIALIZED_ENTITY_DATA_ENABLED, isEnabled);
+    }
 }
diff --git a/core/java/android/view/textclassifier/TextClassifierEvent.java b/core/java/android/view/textclassifier/TextClassifierEvent.java
index 236f89b..d3d61a7 100644
--- a/core/java/android/view/textclassifier/TextClassifierEvent.java
+++ b/core/java/android/view/textclassifier/TextClassifierEvent.java
@@ -19,6 +19,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.icu.util.ULocale;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -30,54 +31,65 @@
 import java.util.Arrays;
 
 /**
- * A text classifier event.
+ * This class represents events that are sent by components to the {@link TextClassifier} to report
+ * something of note that relates to a feature powered by the TextClassifier. The TextClassifier may
+ * log these events or use them to improve future responses to queries.
+ * <p>
+ * Each categories of the events have their own subclass. Events of each types has an associated
+ * set of related properties. You can find the specification of them in the subclasses.
  */
-// TODO: Comprehensive javadoc.
-public final class TextClassifierEvent implements Parcelable {
+public abstract class TextClassifierEvent implements Parcelable {
 
-    public static final @android.annotation.NonNull Creator<TextClassifierEvent> CREATOR = new Creator<TextClassifierEvent>() {
-        @Override
-        public TextClassifierEvent createFromParcel(Parcel in) {
-            return readFromParcel(in);
-        }
-
-        @Override
-        public TextClassifierEvent[] newArray(int size) {
-            return new TextClassifierEvent[size];
-        }
-    };
+    private static final int PARCEL_TOKEN_TEXT_SELECTION_EVENT = 1;
+    private static final int PARCEL_TOKEN_TEXT_LINKIFY_EVENT = 2;
+    private static final int PARCEL_TOKEN_CONVERSATION_ACTION_EVENT = 3;
+    private static final int PARCEL_TOKEN_LANGUAGE_DETECTION_EVENT = 4;
 
     /** @hide **/
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef({CATEGORY_UNDEFINED, CATEGORY_SELECTION, CATEGORY_LINKIFY,
+    @IntDef({CATEGORY_SELECTION, CATEGORY_LINKIFY,
             CATEGORY_CONVERSATION_ACTIONS, CATEGORY_LANGUAGE_DETECTION})
     public @interface Category {
         // For custom event categories, use range 1000+.
     }
-    /** Undefined category */
-    public static final int CATEGORY_UNDEFINED = 0;
-    /** Smart selection */
+
+    /**
+     * Smart selection
+     *
+     * @see TextSelectionEvent
+     */
     public static final int CATEGORY_SELECTION = 1;
-    /** Linkify */
+    /**
+     * Linkify
+     *
+     * @see TextLinkifyEvent
+     */
     public static final int CATEGORY_LINKIFY = 2;
-    /** Conversation actions */
+    /**
+     *  Conversation actions
+     *
+     * @see ConversationActionsEvent
+     */
     public static final int CATEGORY_CONVERSATION_ACTIONS = 3;
-    /** Language detection */
+    /**
+     * Language detection
+     *
+     * @see LanguageDetectionEvent
+     */
     public static final int CATEGORY_LANGUAGE_DETECTION = 4;
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef({TYPE_UNDEFINED, TYPE_SELECTION_STARTED, TYPE_SELECTION_MODIFIED,
-             TYPE_SMART_SELECTION_SINGLE, TYPE_SMART_SELECTION_MULTI, TYPE_AUTO_SELECTION,
-             TYPE_ACTIONS_SHOWN, TYPE_LINK_CLICKED, TYPE_OVERTYPE, TYPE_COPY_ACTION,
-             TYPE_PASTE_ACTION, TYPE_CUT_ACTION, TYPE_SHARE_ACTION, TYPE_SMART_ACTION,
-             TYPE_SELECTION_DRAG, TYPE_SELECTION_DESTROYED, TYPE_OTHER_ACTION, TYPE_SELECT_ALL,
-             TYPE_SELECTION_RESET, TYPE_MANUAL_REPLY, TYPE_ACTIONS_GENERATED})
+    @IntDef({TYPE_SELECTION_STARTED, TYPE_SELECTION_MODIFIED,
+            TYPE_SMART_SELECTION_SINGLE, TYPE_SMART_SELECTION_MULTI, TYPE_AUTO_SELECTION,
+            TYPE_ACTIONS_SHOWN, TYPE_LINK_CLICKED, TYPE_OVERTYPE, TYPE_COPY_ACTION,
+            TYPE_PASTE_ACTION, TYPE_CUT_ACTION, TYPE_SHARE_ACTION, TYPE_SMART_ACTION,
+            TYPE_SELECTION_DRAG, TYPE_SELECTION_DESTROYED, TYPE_OTHER_ACTION, TYPE_SELECT_ALL,
+            TYPE_SELECTION_RESET, TYPE_MANUAL_REPLY, TYPE_ACTIONS_GENERATED})
     public @interface Type {
         // For custom event types, use range 1,000,000+.
     }
-    /** User started a new selection. */
-    public static final int TYPE_UNDEFINED = 0;
+
     /** User started a new selection. */
     public static final int TYPE_SELECTION_STARTED = 1;
     /** User modified an existing selection. */
@@ -119,63 +131,49 @@
     /** TextClassifier generated some actions */
     public static final int TYPE_ACTIONS_GENERATED = 20;
 
-    @Category private final int mEventCategory;
-    @Type private final int mEventType;
-    @Nullable private final String[] mEntityTypes;
-    @Nullable private final TextClassificationContext mEventContext;
-    @Nullable private final String mResultId;
+    @Category
+    private final int mEventCategory;
+    @Type
+    private final int mEventType;
+    @Nullable
+    private final String[] mEntityTypes;
+    @Nullable
+    private final TextClassificationContext mEventContext;
+    @Nullable
+    private final String mResultId;
     private final int mEventIndex;
-    private final long mEventTime;
+    private final float[] mScores;
+    @Nullable
+    private final String mModelName;
+    private final int[] mActionIndices;
     private final Bundle mExtras;
 
-    // Smart selection.
-    private final int mRelativeWordStartIndex;
-    private final int mRelativeWordEndIndex;
-    private final int mRelativeSuggestedWordStartIndex;
-    private final int mRelativeSuggestedWordEndIndex;
+    private TextClassifierEvent(Builder builder) {
+        mEventCategory = builder.mEventCategory;
+        mEventType = builder.mEventType;
+        mEntityTypes = builder.mEntityTypes;
+        mEventContext = builder.mEventContext;
+        mResultId = builder.mResultId;
+        mEventIndex = builder.mEventIndex;
+        mScores = builder.mScores;
+        mModelName = builder.mModelName;
+        mActionIndices = builder.mActionIndices;
+        mExtras = builder.mExtras == null ? Bundle.EMPTY : builder.mExtras;
+    }
 
-    // Smart action.
-    private final int[] mActionIndices;
-
-    // Language detection.
-    @Nullable private final String mLanguage;
-    private final float mScore;
-
-    @Nullable private final String mModelName;
-
-    private TextClassifierEvent(
-            int eventCategory,
-            int eventType,
-            String[] entityTypes,
-            TextClassificationContext eventContext,
-            String resultId,
-            int eventIndex,
-            long eventTime,
-            Bundle extras,
-            int relativeWordStartIndex,
-            int relativeWordEndIndex,
-            int relativeSuggestedWordStartIndex,
-            int relativeSuggestedWordEndIndex,
-            int[] actionIndex,
-            String language,
-            float score,
-            String modelVersion) {
-        mEventCategory = eventCategory;
-        mEventType = eventType;
-        mEntityTypes = entityTypes;
-        mEventContext = eventContext;
-        mResultId = resultId;
-        mEventIndex = eventIndex;
-        mEventTime = eventTime;
-        mExtras = extras;
-        mRelativeWordStartIndex = relativeWordStartIndex;
-        mRelativeWordEndIndex = relativeWordEndIndex;
-        mRelativeSuggestedWordStartIndex = relativeSuggestedWordStartIndex;
-        mRelativeSuggestedWordEndIndex = relativeSuggestedWordEndIndex;
-        mActionIndices = actionIndex;
-        mLanguage = language;
-        mScore = score;
-        mModelName = modelVersion;
+    private TextClassifierEvent(Parcel in) {
+        mEventCategory = in.readInt();
+        mEventType = in.readInt();
+        mEntityTypes = in.readStringArray();
+        mEventContext = in.readParcelable(null);
+        mResultId = in.readString();
+        mEventIndex = in.readInt();
+        int scoresLength = in.readInt();
+        mScores = new float[scoresLength];
+        in.readFloatArray(mScores);
+        mModelName = in.readString();
+        mActionIndices = in.createIntArray();
+        mExtras = in.readBundle();
     }
 
     @Override
@@ -183,44 +181,62 @@
         return 0;
     }
 
+    @NonNull
+    public static final Creator<TextClassifierEvent> CREATOR = new Creator<TextClassifierEvent>() {
+        @Override
+        public TextClassifierEvent createFromParcel(Parcel in) {
+            int token = in.readInt();
+            if (token == PARCEL_TOKEN_TEXT_SELECTION_EVENT) {
+                return new TextSelectionEvent(in);
+            }
+            if (token == PARCEL_TOKEN_TEXT_LINKIFY_EVENT) {
+                return new TextLinkifyEvent(in);
+            }
+            if (token == PARCEL_TOKEN_LANGUAGE_DETECTION_EVENT) {
+                return new LanguageDetectionEvent(in);
+            }
+            if (token == PARCEL_TOKEN_CONVERSATION_ACTION_EVENT) {
+                return new ConversationActionsEvent(in);
+            }
+            throw new IllegalStateException("Unexpected input event type token in parcel.");
+        }
+
+        @Override
+        public TextClassifierEvent[] newArray(int size) {
+            return new TextClassifierEvent[size];
+        }
+    };
+
     @Override
     public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(getParcelToken());
         dest.writeInt(mEventCategory);
         dest.writeInt(mEventType);
         dest.writeStringArray(mEntityTypes);
         dest.writeParcelable(mEventContext, flags);
         dest.writeString(mResultId);
         dest.writeInt(mEventIndex);
-        dest.writeLong(mEventTime);
-        dest.writeBundle(mExtras);
-        dest.writeInt(mRelativeWordStartIndex);
-        dest.writeInt(mRelativeWordEndIndex);
-        dest.writeInt(mRelativeSuggestedWordStartIndex);
-        dest.writeInt(mRelativeSuggestedWordEndIndex);
-        dest.writeIntArray(mActionIndices);
-        dest.writeString(mLanguage);
-        dest.writeFloat(mScore);
+        dest.writeInt(mScores.length);
+        dest.writeFloatArray(mScores);
         dest.writeString(mModelName);
+        dest.writeIntArray(mActionIndices);
+        dest.writeBundle(mExtras);
     }
 
-    private static TextClassifierEvent readFromParcel(Parcel in) {
-        return new TextClassifierEvent(
-                /* eventCategory= */ in.readInt(),
-                /* eventType= */ in.readInt(),
-                /* entityTypes=*/ in.readStringArray(),
-                /* eventContext= */ in.readParcelable(null),
-                /* resultId= */ in.readString(),
-                /* eventIndex= */ in.readInt(),
-                /* eventTime= */ in.readLong(),
-                /* extras= */ in.readBundle(),
-                /* relativeWordStartIndex= */ in.readInt(),
-                /* relativeWordEndIndex= */ in.readInt(),
-                /* relativeSuggestedWordStartIndex= */ in.readInt(),
-                /* relativeSuggestedWordEndIndex= */ in.readInt(),
-                /* actionIndices= */ in.createIntArray(),
-                /* language= */ in.readString(),
-                /* score= */ in.readFloat(),
-                /* modelVersion= */ in.readString());
+    private int getParcelToken() {
+        if (this instanceof TextSelectionEvent) {
+            return PARCEL_TOKEN_TEXT_SELECTION_EVENT;
+        }
+        if (this instanceof TextLinkifyEvent) {
+            return PARCEL_TOKEN_TEXT_LINKIFY_EVENT;
+        }
+        if (this instanceof LanguageDetectionEvent) {
+            return PARCEL_TOKEN_LANGUAGE_DETECTION_EVENT;
+        }
+        if (this instanceof ConversationActionsEvent) {
+            return PARCEL_TOKEN_CONVERSATION_ACTION_EVENT;
+        }
+        throw new IllegalArgumentException("Unexpected type: " + this.getClass().getSimpleName());
     }
 
     /**
@@ -241,6 +257,8 @@
 
     /**
      * Returns an array of entity types. e.g. {@link TextClassifier#TYPE_ADDRESS}.
+     *
+     * @see Builder#setEntityTypes(String...) for supported types.
      */
     @NonNull
     public String[] getEntityTypes() {
@@ -270,13 +288,33 @@
         return mEventIndex;
     }
 
-    // TODO: Remove this API.
     /**
-     * Returns the time this event occurred. This is the number of milliseconds since
-     * January 1, 1970, 00:00:00 GMT. 0 indicates not set.
+     * Returns the scores of the suggestions.
      */
-    public long getEventTime() {
-        return mEventTime;
+    @NonNull
+    public float[] getScores() {
+        return mScores;
+    }
+
+    /**
+     * Returns the model name.
+     */
+    @Nullable
+    public String getModelName() {
+        return mModelName;
+    }
+
+    /**
+     * Returns the indices of the actions relating to this event.
+     * Actions are usually returned by the text classifier in priority order with the most
+     * preferred action at index 0. This list gives an indication of the position of the actions
+     * that are being reported.
+     *
+     * @see Builder#setActionIndices(int...)
+     */
+    @NonNull
+    public int[] getActionIndices() {
+        return mActionIndices;
     }
 
     /**
@@ -289,151 +327,149 @@
         return mExtras;
     }
 
-    /**
-     * For smart selection. Returns the relative word index of the start of the selection.
-     */
-    public int getRelativeWordStartIndex() {
-        return mRelativeWordStartIndex;
-    }
-
-    /**
-     * For smart selection. Returns the relative word (exclusive) index of the end of the selection.
-     */
-    public int getRelativeWordEndIndex() {
-        return mRelativeWordEndIndex;
-    }
-
-    /**
-     * For smart selection. Returns the relative word index of the start of the smart selection.
-     */
-    public int getRelativeSuggestedWordStartIndex() {
-        return mRelativeSuggestedWordStartIndex;
-    }
-
-    /**
-     * For smart selection. Returns the relative word (exclusive) index of the end of the
-     * smart selection.
-     */
-    public int getRelativeSuggestedWordEndIndex() {
-        return mRelativeSuggestedWordEndIndex;
-    }
-
-    /**
-     * Returns the indices of the actions relating to this event.
-     * Actions are usually returned by the text classifier in priority order with the most
-     * preferred action at index 0. This list gives an indication of the position of the actions
-     * that are being reported.
-     */
-    @NonNull
-    public int[] getActionIndices() {
-        return mActionIndices;
-    }
-
-    /**
-     * For language detection. Returns the language tag for the detected locale.
-     * @see java.util.Locale#forLanguageTag(String).
-     */
-    @Nullable
-    public String getLanguage() {
-        return mLanguage;
-    }
-
-    /**
-     * Returns the score of the suggestion.
-     */
-    public float getScore() {
-        return mScore;
-    }
-
-    /**
-     * Returns the model name.
-     * @hide
-     */
-    @Nullable
-    public String getModelName() {
-        return mModelName;
+    @Override
+    public String toString() {
+        StringBuilder out = new StringBuilder(128);
+        out.append(this.getClass().getSimpleName());
+        out.append("{");
+        out.append("mEventCategory=").append(mEventCategory);
+        out.append(", mEventTypes=").append(Arrays.toString(mEntityTypes));
+        out.append(", mEventContext=").append(mEventContext);
+        out.append(", mResultId=").append(mResultId);
+        out.append(", mEventIndex=").append(mEventIndex);
+        out.append(", mExtras=").append(mExtras);
+        out.append(", mScores=").append(Arrays.toString(mScores));
+        out.append(", mModelName=").append(mModelName);
+        out.append(", mActionIndices=").append(Arrays.toString(mActionIndices));
+        out.append("}");
+        return out.toString();
     }
 
     /**
      * Builder to build a text classifier event.
+     *
+     * @param <T> The subclass to be built.
      */
-    public static final class Builder {
+    public abstract static class Builder<T extends Builder<T>> {
 
         private final int mEventCategory;
         private final int mEventType;
         private String[] mEntityTypes = new String[0];
-        @Nullable private TextClassificationContext mEventContext;
-        @Nullable private String mResultId;
+        @Nullable
+        private TextClassificationContext mEventContext;
+        @Nullable
+        private String mResultId;
         private int mEventIndex;
-        private long mEventTime;
-        @Nullable private Bundle mExtras;
-        private int mRelativeWordStartIndex;
-        private int mRelativeWordEndIndex;
-        private int mRelativeSuggestedWordStartIndex;
-        private int mRelativeSuggestedWordEndIndex;
-        private int[] mActionIndices = new int[0];
-        @Nullable private String mLanguage;
-        private float mScore;
-
+        private float[] mScores = new float[0];
+        @Nullable
         private String mModelName;
+        private int[] mActionIndices = new int[0];
+        @Nullable
+        private Bundle mExtras;
 
         /**
          * Creates a builder for building {@link TextClassifierEvent}s.
          *
          * @param eventCategory The event category. e.g. {@link #CATEGORY_SELECTION}
-         * @param eventType The event type. e.g. {@link #TYPE_SELECTION_STARTED}
+         * @param eventType     The event type. e.g. {@link #TYPE_SELECTION_STARTED}
          */
-        public Builder(@Category int eventCategory, @Type int eventType) {
+        private Builder(@Category int eventCategory, @Type int eventType) {
             mEventCategory = eventCategory;
             mEventType = eventType;
         }
 
         /**
          * Sets the entity types. e.g. {@link TextClassifier#TYPE_ADDRESS}.
+         * <p>
+         * Supported types:
+         * <p>See {@link TextClassifier.EntityType}
+         * <p>See {@link ConversationAction.ActionType}
+         * <p>See {@link ULocale#toLanguageTag()}
          */
         @NonNull
-        public Builder setEntityTypes(@NonNull String... entityTypes) {
+        public T setEntityTypes(@NonNull String... entityTypes) {
+            Preconditions.checkNotNull(entityTypes);
             mEntityTypes = new String[entityTypes.length];
             System.arraycopy(entityTypes, 0, mEntityTypes, 0, entityTypes.length);
-            return this;
+            return self();
         }
 
         /**
          * Sets the event context.
          */
         @NonNull
-        public Builder setEventContext(@Nullable TextClassificationContext eventContext) {
+        public T setEventContext(@Nullable TextClassificationContext eventContext) {
             mEventContext = eventContext;
-            return this;
+            return self();
         }
 
         /**
          * Sets the id of the text classifier result related to this event.
          */
         @NonNull
-        public Builder setResultId(@Nullable String resultId) {
+        public T setResultId(@Nullable String resultId) {
             mResultId = resultId;
-            return this;
+            return self();
         }
 
         /**
-         * Sets the index of this events in the series of events it belongs to.
+         * Sets the index of this event in the series of events it belongs to.
          */
         @NonNull
-        public Builder setEventIndex(int eventIndex) {
+        public T setEventIndex(int eventIndex) {
             mEventIndex = eventIndex;
-            return this;
+            return self();
         }
 
-        // TODO: Remove this API.
         /**
-         * Sets the time this event occurred. This is the number of milliseconds since
-         * January 1, 1970, 00:00:00 GMT. 0 indicates not set.
+         * Sets the scores of the suggestions.
          */
         @NonNull
-        public Builder setEventTime(long eventTime) {
-            mEventTime = eventTime;
-            return this;
+        public T setScores(@NonNull float... scores) {
+            Preconditions.checkNotNull(scores);
+            mScores = new float[scores.length];
+            System.arraycopy(scores, 0, mScores, 0, scores.length);
+            return self();
+        }
+
+        /**
+         * Sets the model name string.
+         */
+        @NonNull
+        public T setModelName(@Nullable String modelVersion) {
+            mModelName = modelVersion;
+            return self();
+        }
+
+        /**
+         * Sets the indices of the actions involved in this event. Actions are usually returned by
+         * the text classifier in priority order with the most preferred action at index 0.
+         * These indices give an indication of the position of the actions that are being reported.
+         * <p>
+         * E.g.
+         * <pre>
+         *   // 3 smart actions are shown at index 0, 1, 2 respectively in response to a link click.
+         *   new TextClassifierEvent.Builder(CATEGORY_LINKIFY, TYPE_ACTIONS_SHOWN)
+         *       .setEventIndex(0, 1, 2)
+         *       ...
+         *       .build();
+         *
+         *   ...
+         *
+         *   // Smart action at index 1 is activated.
+         *   new TextClassifierEvent.Builder(CATEGORY_LINKIFY, TYPE_SMART_ACTION)
+         *       .setEventIndex(1)
+         *       ...
+         *       .build();
+         * </pre>
+         *
+         * @see TextClassification#getActions()
+         */
+        @NonNull
+        public T setActionIndices(@NonNull int... actionIndices) {
+            mActionIndices = new int[actionIndices.length];
+            System.arraycopy(actionIndices, 0, mActionIndices, 0, actionIndices.length);
+            return self();
         }
 
         /**
@@ -445,136 +481,545 @@
          * objects in this bundle.
          */
         @NonNull
-        public Builder setExtras(@NonNull Bundle extras) {
+        public T setExtras(@NonNull Bundle extras) {
             mExtras = Preconditions.checkNotNull(extras);
-            return this;
+            return self();
         }
 
-        /**
-         * For smart selection. Sets the relative word index of the start of the selection.
-         */
-        @NonNull
-        public Builder setRelativeWordStartIndex(int relativeWordStartIndex) {
-            mRelativeWordStartIndex = relativeWordStartIndex;
-            return this;
-        }
-
-        /**
-         * For smart selection. Sets the relative word (exclusive) index of the end of the
-         * selection.
-         */
-        @NonNull
-        public Builder setRelativeWordEndIndex(int relativeWordEndIndex) {
-            mRelativeWordEndIndex = relativeWordEndIndex;
-            return this;
-        }
-
-        /**
-         * For smart selection. Sets the relative word index of the start of the smart selection.
-         */
-        @NonNull
-        public Builder setRelativeSuggestedWordStartIndex(int relativeSuggestedWordStartIndex) {
-            mRelativeSuggestedWordStartIndex = relativeSuggestedWordStartIndex;
-            return this;
-        }
-
-        /**
-         * For smart selection. Sets the relative word (exclusive) index of the end of the
-         * smart selection.
-         */
-        @NonNull
-        public Builder setRelativeSuggestedWordEndIndex(int relativeSuggestedWordEndIndex) {
-            mRelativeSuggestedWordEndIndex = relativeSuggestedWordEndIndex;
-            return this;
-        }
-
-        /**
-         * Sets the indices of the actions involved in this event. Actions are usually returned by
-         * the text classifier in priority order with the most preferred action at index 0.
-         * This index gives an indication of the position of the action that is being reported.
-         */
-        @NonNull
-        public Builder setActionIndices(@NonNull int... actionIndices) {
-            mActionIndices = new int[actionIndices.length];
-            System.arraycopy(actionIndices, 0, mActionIndices, 0, actionIndices.length);
-            return this;
-        }
-
-        /**
-         * For language detection. Sets the language tag for the detected locale.
-         * @see java.util.Locale#forLanguageTag(String).
-         */
-        @NonNull
-        public Builder setLanguage(@Nullable String language) {
-            mLanguage = language;
-            return this;
-        }
-
-        /**
-         * Sets the score of the suggestion.
-         */
-        @NonNull
-        public Builder setScore(float score) {
-            mScore = score;
-            return this;
-        }
-
-        /**
-         * Sets the model name string.
-         * @hide
-         */
-        public Builder setModelName(@Nullable String modelVersion) {
-            mModelName = modelVersion;
-            return this;
-        }
-
-        /**
-         * Builds and returns a text classifier event.
-         */
-        @NonNull
-        public TextClassifierEvent build() {
-            mExtras = mExtras == null ? Bundle.EMPTY : mExtras;
-            return new TextClassifierEvent(
-                    mEventCategory,
-                    mEventType,
-                    mEntityTypes,
-                    mEventContext,
-                    mResultId,
-                    mEventIndex,
-                    mEventTime,
-                    mExtras,
-                    mRelativeWordStartIndex,
-                    mRelativeWordEndIndex,
-                    mRelativeSuggestedWordStartIndex,
-                    mRelativeSuggestedWordEndIndex,
-                    mActionIndices,
-                    mLanguage,
-                    mScore,
-                    mModelName);
-        }
-        // TODO: Add build(boolean validate).
+        abstract T self();
     }
 
-    @Override
-    public String toString() {
-        StringBuilder out = new StringBuilder(128);
-        out.append("TextClassifierEvent{");
-        out.append("mEventCategory=").append(mEventCategory);
-        out.append(", mEventTypes=").append(Arrays.toString(mEntityTypes));
-        out.append(", mEventContext=").append(mEventContext);
-        out.append(", mResultId=").append(mResultId);
-        out.append(", mEventIndex=").append(mEventIndex);
-        out.append(", mEventTime=").append(mEventTime);
-        out.append(", mExtras=").append(mExtras);
-        out.append(", mRelativeWordStartIndex=").append(mRelativeWordStartIndex);
-        out.append(", mRelativeWordEndIndex=").append(mRelativeWordEndIndex);
-        out.append(", mRelativeSuggestedWordStartIndex=").append(mRelativeSuggestedWordStartIndex);
-        out.append(", mRelativeSuggestedWordEndIndex=").append(mRelativeSuggestedWordEndIndex);
-        out.append(", mActionIndices=").append(Arrays.toString(mActionIndices));
-        out.append(", mLanguage=").append(mLanguage);
-        out.append(", mScore=").append(mScore);
-        out.append(", mModelName=").append(mModelName);
-        out.append("}");
-        return out.toString();
+    /**
+     * This class represents events that are related to the smart text selection feature.
+     * <p>
+     * <pre>
+     *     // User started a selection. e.g. "York" in text "New York City, NY".
+     *     new TextSelectionEvent.Builder(TYPE_SELECTION_STARTED)
+     *         .setEventContext(classificationContext)
+     *         .setEventIndex(0)
+     *         .build();
+     *
+     *     // System smart-selects a recognized entity. e.g. "New York City".
+     *     new TextSelectionEvent.Builder(TYPE_SMART_SELECTION_MULTI)
+     *         .setEventContext(classificationContext)
+     *         .setResultId(textSelection.getId())
+     *         .setRelativeWordStartIndex(-1) // Goes back one word to "New" from "York".
+     *         .setRelativeWordEndIndex(2)    // Goes forward 2 words from "York" to start of ",".
+     *         .setEntityTypes(textClassification.getEntity(0))
+     *         .setScore(textClassification.getConfidenceScore(entityType))
+     *         .setEventIndex(1)
+     *         .build();
+     *
+     *     // User resets the selection to the original selection. i.e. "York".
+     *     new TextSelectionEvent.Builder(TYPE_SELECTION_RESET)
+     *         .setEventContext(classificationContext)
+     *         .setResultId(textSelection.getId())
+     *         .setRelativeSuggestedWordStartIndex(-1) // Repeated from above.
+     *         .setRelativeSuggestedWordEndIndex(2)    // Repeated from above.
+     *         .setRelativeWordStartIndex(0)           // Original selection is always at (0, 1].
+     *         .setRelativeWordEndIndex(1)
+     *         .setEntityTypes(textClassification.getEntity(0))
+     *         .setScore(textClassification.getConfidenceScore(entityType))
+     *         .setEventIndex(2)
+     *         .build();
+     *
+     *     // User modified the selection. e.g. "New".
+     *     new TextSelectionEvent.Builder(TYPE_SELECTION_MODIFIED)
+     *         .setEventContext(classificationContext)
+     *         .setResultId(textSelection.getId())
+     *         .setRelativeSuggestedWordStartIndex(-1) // Repeated from above.
+     *         .setRelativeSuggestedWordEndIndex(2)    // Repeated from above.
+     *         .setRelativeWordStartIndex(-1)          // Goes backward one word from "York" to
+     *         "New".
+     *         .setRelativeWordEndIndex(0)             // Goes backward one word to exclude "York".
+     *         .setEntityTypes(textClassification.getEntity(0))
+     *         .setScore(textClassification.getConfidenceScore(entityType))
+     *         .setEventIndex(3)
+     *         .build();
+     *
+     *     // Smart (contextual) actions (at indices, 0, 1, 2) presented to the user.
+     *     // e.g. "Map", "Ride share", "Explore".
+     *     new TextSelectionEvent.Builder(TYPE_ACTIONS_SHOWN)
+     *         .setEventContext(classificationContext)
+     *         .setResultId(textClassification.getId())
+     *         .setEntityTypes(textClassification.getEntity(0))
+     *         .setScore(textClassification.getConfidenceScore(entityType))
+     *         .setActionIndices(0, 1, 2)
+     *         .setEventIndex(4)
+     *         .build();
+     *
+     *     // User chooses the "Copy" action.
+     *     new TextSelectionEvent.Builder(TYPE_COPY_ACTION)
+     *         .setEventContext(classificationContext)
+     *         .setResultId(textClassification.getId())
+     *         .setEntityTypes(textClassification.getEntity(0))
+     *         .setScore(textClassification.getConfidenceScore(entityType))
+     *         .setEventIndex(5)
+     *         .build();
+     *
+     *     // User chooses smart action at index 1. i.e. "Ride share".
+     *     new TextSelectionEvent.Builder(TYPE_SMART_ACTION)
+     *         .setEventContext(classificationContext)
+     *         .setResultId(textClassification.getId())
+     *         .setEntityTypes(textClassification.getEntity(0))
+     *         .setScore(textClassification.getConfidenceScore(entityType))
+     *         .setActionIndices(1)
+     *         .setEventIndex(5)
+     *         .build();
+     *
+     *     // Selection dismissed.
+     *     new TextSelectionEvent.Builder(TYPE_SELECTION_DESTROYED)
+     *         .setEventContext(classificationContext)
+     *         .setResultId(textClassification.getId())
+     *         .setEntityTypes(textClassification.getEntity(0))
+     *         .setScore(textClassification.getConfidenceScore(entityType))
+     *         .setEventIndex(6)
+     *         .build();
+     * </pre>
+     * <p>
+     */
+    public static final class TextSelectionEvent extends TextClassifierEvent implements Parcelable {
+
+        @NonNull
+        public static final Creator<TextSelectionEvent> CREATOR =
+                new Creator<TextSelectionEvent>() {
+                    @Override
+                    public TextSelectionEvent createFromParcel(Parcel in) {
+                        in.readInt(); // skip token, we already know this is a TextSelectionEvent
+                        return new TextSelectionEvent(in);
+                    }
+
+                    @Override
+                    public TextSelectionEvent[] newArray(int size) {
+                        return new TextSelectionEvent[size];
+                    }
+                };
+
+        final int mRelativeWordStartIndex;
+        final int mRelativeWordEndIndex;
+        final int mRelativeSuggestedWordStartIndex;
+        final int mRelativeSuggestedWordEndIndex;
+
+        private TextSelectionEvent(TextSelectionEvent.Builder builder) {
+            super(builder);
+            mRelativeWordStartIndex = builder.mRelativeWordStartIndex;
+            mRelativeWordEndIndex = builder.mRelativeWordEndIndex;
+            mRelativeSuggestedWordStartIndex = builder.mRelativeSuggestedWordStartIndex;
+            mRelativeSuggestedWordEndIndex = builder.mRelativeSuggestedWordEndIndex;
+        }
+
+        private TextSelectionEvent(Parcel in) {
+            super(in);
+            mRelativeWordStartIndex = in.readInt();
+            mRelativeWordEndIndex = in.readInt();
+            mRelativeSuggestedWordStartIndex = in.readInt();
+            mRelativeSuggestedWordEndIndex = in.readInt();
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            super.writeToParcel(dest, flags);
+            dest.writeInt(mRelativeWordStartIndex);
+            dest.writeInt(mRelativeWordEndIndex);
+            dest.writeInt(mRelativeSuggestedWordStartIndex);
+            dest.writeInt(mRelativeSuggestedWordEndIndex);
+        }
+
+        /**
+         * Returns the relative word index of the start of the selection.
+         */
+        public int getRelativeWordStartIndex() {
+            return mRelativeWordStartIndex;
+        }
+
+        /**
+         * Returns the relative word (exclusive) index of the end of the selection.
+         */
+        public int getRelativeWordEndIndex() {
+            return mRelativeWordEndIndex;
+        }
+
+        /**
+         * Returns the relative word index of the start of the smart selection.
+         */
+        public int getRelativeSuggestedWordStartIndex() {
+            return mRelativeSuggestedWordStartIndex;
+        }
+
+        /**
+         * Returns the relative word (exclusive) index of the end of the
+         * smart selection.
+         */
+        public int getRelativeSuggestedWordEndIndex() {
+            return mRelativeSuggestedWordEndIndex;
+        }
+
+        /**
+         * Builder class for {@link TextSelectionEvent}.
+         */
+        public static final class Builder extends
+                TextClassifierEvent.Builder<TextSelectionEvent.Builder> {
+            int mRelativeWordStartIndex;
+            int mRelativeWordEndIndex;
+            int mRelativeSuggestedWordStartIndex;
+            int mRelativeSuggestedWordEndIndex;
+
+            /**
+             * Creates a builder for building {@link TextSelectionEvent}s.
+             *
+             * @param eventType     The event type. e.g. {@link #TYPE_SELECTION_STARTED}
+             */
+            public Builder(@Type int eventType) {
+                super(CATEGORY_SELECTION, eventType);
+            }
+
+            /**
+             * Sets the relative word index of the start of the selection.
+             */
+            @NonNull
+            public Builder setRelativeWordStartIndex(int relativeWordStartIndex) {
+                mRelativeWordStartIndex = relativeWordStartIndex;
+                return this;
+            }
+
+            /**
+             * Sets the relative word (exclusive) index of the end of the
+             * selection.
+             */
+            @NonNull
+            public Builder setRelativeWordEndIndex(int relativeWordEndIndex) {
+                mRelativeWordEndIndex = relativeWordEndIndex;
+                return this;
+            }
+
+            /**
+             * Sets the relative word index of the start of the smart
+             * selection.
+             */
+            @NonNull
+            public Builder setRelativeSuggestedWordStartIndex(int relativeSuggestedWordStartIndex) {
+                mRelativeSuggestedWordStartIndex = relativeSuggestedWordStartIndex;
+                return this;
+            }
+
+            /**
+             * Sets the relative word (exclusive) index of the end of the
+             * smart selection.
+             */
+            @NonNull
+            public Builder setRelativeSuggestedWordEndIndex(int relativeSuggestedWordEndIndex) {
+                mRelativeSuggestedWordEndIndex = relativeSuggestedWordEndIndex;
+                return this;
+            }
+
+            @Override
+            TextSelectionEvent.Builder self() {
+                return this;
+            }
+
+            /**
+             * Builds and returns a {@link TextSelectionEvent}.
+             */
+            @NonNull
+            public TextSelectionEvent build() {
+                return new TextSelectionEvent(this);
+            }
+        }
+    }
+
+    /**
+     * This class represents events that are related to the smart linkify feature.
+     * <p>
+     * <pre>
+     *     // User clicked on a link.
+     *     new TextLinkifyEvent.Builder(TYPE_LINK_CLICKED)
+     *         .setEventContext(classificationContext)
+     *         .setResultId(textClassification.getId())
+     *         .setEntityTypes(textClassification.getEntity(0))
+     *         .setScore(textClassification.getConfidenceScore(entityType))
+     *         .setEventIndex(0)
+     *         .build();
+     *
+     *     // Smart (contextual) actions presented to the user in response to a link click.
+     *     new TextLinkifyEvent.Builder(TYPE_ACTIONS_SHOWN)
+     *         .setEventContext(classificationContext)
+     *         .setResultId(textClassification.getId())
+     *         .setEntityTypes(textClassification.getEntity(0))
+     *         .setScore(textClassification.getConfidenceScore(entityType))
+     *         .setActionIndices(range(textClassification.getActions().size()))
+     *         .setEventIndex(1)
+     *         .build();
+     *
+     *     // User chooses smart action at index 0.
+     *     new TextLinkifyEvent.Builder(TYPE_SMART_ACTION)
+     *         .setEventContext(classificationContext)
+     *         .setResultId(textClassification.getId())
+     *         .setEntityTypes(textClassification.getEntity(0))
+     *         .setScore(textClassification.getConfidenceScore(entityType))
+     *         .setActionIndices(0)
+     *         .setEventIndex(2)
+     *         .build();
+     * </pre>
+     */
+    public static final class TextLinkifyEvent extends TextClassifierEvent implements Parcelable {
+
+        @NonNull
+        public static final Creator<TextLinkifyEvent> CREATOR =
+                new Creator<TextLinkifyEvent>() {
+                    @Override
+                    public TextLinkifyEvent createFromParcel(Parcel in) {
+                        in.readInt(); // skip token, we already know this is a TextLinkifyEvent
+                        return new TextLinkifyEvent(in);
+                    }
+
+                    @Override
+                    public TextLinkifyEvent[] newArray(int size) {
+                        return new TextLinkifyEvent[size];
+                    }
+                };
+
+        private TextLinkifyEvent(Parcel in) {
+            super(in);
+        }
+
+        private TextLinkifyEvent(TextLinkifyEvent.Builder builder) {
+            super(builder);
+        }
+
+        /**
+         * Builder class for {@link TextLinkifyEvent}.
+         */
+        public static final class Builder
+                extends TextClassifierEvent.Builder<TextLinkifyEvent.Builder> {
+            /**
+             * Creates a builder for building {@link TextLinkifyEvent}s.
+             *
+             * @param eventType The event type. e.g. {@link #TYPE_SMART_ACTION}
+             */
+            public Builder(@Type int eventType) {
+                super(TextClassifierEvent.CATEGORY_LINKIFY, eventType);
+            }
+
+            @Override
+            Builder self() {
+                return this;
+            }
+
+            /**
+             * Builds and returns a {@link TextLinkifyEvent}.
+             */
+            @NonNull
+            public TextLinkifyEvent build() {
+                return new TextLinkifyEvent(this);
+            }
+        }
+    }
+
+    /**
+     * This class represents events that are related to the language detection feature.
+     * <p>
+     * <pre>
+     *     // Translate action shown for foreign text.
+     *     new LanguageDetectionEvent.Builder(TYPE_ACTIONS_SHOWN)
+     *         .setEventContext(classificationContext)
+     *         .setResultId(textClassification.getId())
+     *         .setEntityTypes(language)
+     *         .setScore(score)
+     *         .setActionIndices(textClassification.getActions().indexOf(translateAction))
+     *         .setEventIndex(0)
+     *         .build();
+     *
+     *     // Translate action selected.
+     *     new LanguageDetectionEvent.Builder(TYPE_SMART_ACTION)
+     *         .setEventContext(classificationContext)
+     *         .setResultId(textClassification.getId())
+     *         .setEntityTypes(language)
+     *         .setScore(score)
+     *         .setActionIndices(textClassification.getActions().indexOf(translateAction))
+     *         .setEventIndex(1)
+     *         .build();
+     */
+    public static final class LanguageDetectionEvent extends TextClassifierEvent
+            implements Parcelable {
+
+        @NonNull
+        public static final Creator<LanguageDetectionEvent> CREATOR =
+                new Creator<LanguageDetectionEvent>() {
+                    @Override
+                    public LanguageDetectionEvent createFromParcel(Parcel in) {
+                        // skip token, we already know this is a LanguageDetectionEvent.
+                        in.readInt();
+                        return new LanguageDetectionEvent(in);
+                    }
+
+                    @Override
+                    public LanguageDetectionEvent[] newArray(int size) {
+                        return new LanguageDetectionEvent[size];
+                    }
+                };
+
+        @Nullable
+        private final ULocale mLocale;
+
+        private LanguageDetectionEvent(Parcel in) {
+            super(in);
+            final String languageTag = in.readString();
+            mLocale = languageTag == null ? null : ULocale.forLanguageTag(languageTag);
+        }
+
+        private LanguageDetectionEvent(LanguageDetectionEvent.Builder builder) {
+            super(builder);
+            mLocale = builder.mLocale;
+        }
+
+        /**
+         * Returns the detected locale.
+         */
+        @Nullable
+        public ULocale getLocale() {
+            return mLocale;
+        }
+
+        /**
+         * Builder class for {@link LanguageDetectionEvent}.
+         */
+        public static final class Builder
+                extends TextClassifierEvent.Builder<LanguageDetectionEvent.Builder> {
+            @Nullable
+            private ULocale mLocale;
+
+            /**
+             * Creates a builder for building {@link TextSelectionEvent}s.
+             *
+             * @param eventType The event type. e.g. {@link #TYPE_SMART_ACTION}
+             */
+            public Builder(@Type int eventType) {
+                super(TextClassifierEvent.CATEGORY_LANGUAGE_DETECTION, eventType);
+            }
+
+            /**
+             * Sets the detected locale.
+             */
+            @NonNull
+            public Builder setLocale(@Nullable ULocale locale) {
+                mLocale = locale;
+                return this;
+            }
+
+            @Override
+            Builder self() {
+                return this;
+            }
+
+            /**
+             * Builds and returns a {@link LanguageDetectionEvent}.
+             */
+            @NonNull
+            public LanguageDetectionEvent build() {
+                return new LanguageDetectionEvent(this);
+            }
+        }
+
+        @Override
+        public void writeToParcel(Parcel dest, int flags) {
+            super.writeToParcel(dest, flags);
+            dest.writeString(mLocale == null ? null : mLocale.toLanguageTag());
+        }
+    }
+
+    /**
+     * This class represents events that are related to the conversation actions feature.
+     * <p>
+     * <pre>
+     *     // Conversation (contextual) actions/replies generated.
+     *     new ConversationActionsEvent.Builder(TYPE_ACTIONS_GENERATED)
+     *         .setEventContext(classificationContext)
+     *         .setResultId(conversationActions.getId())
+     *         .setEntityTypes(getTypes(conversationActions))
+     *         .setActionIndices(range(conversationActions.getActions().size()))
+     *         .setEventIndex(0)
+     *         .build();
+     *
+     *     // Conversation actions/replies presented to user.
+     *     new ConversationActionsEvent.Builder(TYPE_ACTIONS_SHOWN)
+     *         .setEventContext(classificationContext)
+     *         .setResultId(conversationActions.getId())
+     *         .setEntityTypes(getTypes(conversationActions))
+     *         .setActionIndices(range(conversationActions.getActions().size()))
+     *         .setEventIndex(1)
+     *         .build();
+     *
+     *     // User clicked the "Reply" button to compose their custom reply.
+     *     new ConversationActionsEvent.Builder(TYPE_MANUAL_REPLY)
+     *         .setEventContext(classificationContext)
+     *         .setResultId(conversationActions.getId())
+     *         .setEventIndex(2)
+     *         .build();
+     *
+     *     // User selected a smart (contextual) action/reply.
+     *     new ConversationActionsEvent.Builder(TYPE_SMART_ACTION)
+     *         .setEventContext(classificationContext)
+     *         .setResultId(conversationActions.getId())
+     *         .setEntityTypes(conversationActions.get(1).getType())
+     *         .setScore(conversationAction.get(1).getConfidenceScore())
+     *         .setActionIndices(1)
+     *         .setEventIndex(2)
+     *         .build();
+     * </pre>
+     */
+    public static final class ConversationActionsEvent extends TextClassifierEvent
+            implements Parcelable {
+
+        @NonNull
+        public static final Creator<ConversationActionsEvent> CREATOR =
+                new Creator<ConversationActionsEvent>() {
+                    @Override
+                    public ConversationActionsEvent createFromParcel(Parcel in) {
+                        // skip token, we already know this is a ConversationActionsEvent.
+                        in.readInt();
+                        return new ConversationActionsEvent(in);
+                    }
+
+                    @Override
+                    public ConversationActionsEvent[] newArray(int size) {
+                        return new ConversationActionsEvent[size];
+                    }
+                };
+
+        private ConversationActionsEvent(Parcel in) {
+            super(in);
+        }
+
+        private ConversationActionsEvent(ConversationActionsEvent.Builder builder) {
+            super(builder);
+        }
+
+        /**
+         * Builder class for {@link ConversationActionsEvent}.
+         */
+        public static final class Builder
+                extends TextClassifierEvent.Builder<ConversationActionsEvent.Builder> {
+            /**
+             * Creates a builder for building {@link TextSelectionEvent}s.
+             *
+             * @param eventType The event type. e.g. {@link #TYPE_SMART_ACTION}
+             */
+            public Builder(@Type int eventType) {
+                super(TextClassifierEvent.CATEGORY_CONVERSATION_ACTIONS, eventType);
+            }
+
+            @Override
+            Builder self() {
+                return this;
+            }
+
+            /**
+             * Builds and returns a {@link ConversationActionsEvent}.
+             */
+            @NonNull
+            public ConversationActionsEvent build() {
+                return new ConversationActionsEvent(this);
+            }
+        }
     }
 }
diff --git a/core/java/android/view/textclassifier/TextClassifierEventTronLogger.java b/core/java/android/view/textclassifier/TextClassifierEventTronLogger.java
index 6a12250..3e088b8 100644
--- a/core/java/android/view/textclassifier/TextClassifierEventTronLogger.java
+++ b/core/java/android/view/textclassifier/TextClassifierEventTronLogger.java
@@ -65,9 +65,10 @@
         final LogMaker log = new LogMaker(category)
                 .setSubtype(getLogType(event))
                 .addTaggedData(FIELD_TEXT_CLASSIFIER_SESSION_ID, event.getResultId())
-                .addTaggedData(FIELD_TEXTCLASSIFIER_MODEL, getModelName(event))
-                .addTaggedData(FIELD_TEXT_CLASSIFIER_SCORE, event.getScore());
-
+                .addTaggedData(FIELD_TEXTCLASSIFIER_MODEL, getModelName(event));
+        if (event.getScores().length >= 1) {
+            log.addTaggedData(FIELD_TEXT_CLASSIFIER_SCORE, event.getScores()[0]);
+        }
         String[] entityTypes = event.getEntityTypes();
         // The old logger does not support a field of list type, and thus workaround by store them
         // in three separate fields. This is not an issue with the new logger.
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index 323bf59..3297523 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -307,6 +307,8 @@
             final String detectLanguageTags = detectLanguageTagsFromText(request.getText());
             final AnnotatorModel annotatorImpl =
                     getAnnotatorImpl(request.getDefaultLocales());
+            final boolean isSerializedEntityDataEnabled =
+                    ExtrasUtils.isSerializedEntityDataEnabled(request);
             final AnnotatorModel.AnnotatedSpan[] annotations =
                     annotatorImpl.annotate(
                             textString,
@@ -314,7 +316,10 @@
                                     refTime.toInstant().toEpochMilli(),
                                     refTime.getZone().getId(),
                                     localesString,
-                                    detectLanguageTags));
+                                    detectLanguageTags,
+                                    entitiesToIdentify,
+                                    AnnotatorModel.AnnotationUsecase.SMART.getValue(),
+                                    isSerializedEntityDataEnabled));
             for (AnnotatorModel.AnnotatedSpan span : annotations) {
                 final AnnotatorModel.ClassificationResult[] results =
                         span.getClassification();
@@ -326,7 +331,11 @@
                 for (int i = 0; i < results.length; i++) {
                     entityScores.put(results[i].getCollection(), results[i].getScore());
                 }
-                builder.addLink(span.getStartIndex(), span.getEndIndex(), entityScores);
+                Bundle extras = new Bundle();
+                if (isSerializedEntityDataEnabled) {
+                    ExtrasUtils.putEntities(extras, results);
+                }
+                builder.addLink(span.getStartIndex(), span.getEndIndex(), entityScores, extras);
             }
             final TextLinks links = builder.build();
             final long endTimeMs = System.currentTimeMillis();
@@ -451,10 +460,6 @@
         Collection<String> expectedTypes = resolveActionTypesFromRequest(request);
         List<ConversationAction> conversationActions = new ArrayList<>();
         for (ActionsSuggestionsModel.ActionSuggestion nativeSuggestion : nativeSuggestions) {
-            if (request.getMaxSuggestions() >= 0
-                    && conversationActions.size() == request.getMaxSuggestions()) {
-                break;
-            }
             String actionType = nativeSuggestion.getActionType();
             if (!expectedTypes.contains(actionType)) {
                 continue;
@@ -484,6 +489,10 @@
         }
         conversationActions =
                 ActionsSuggestionsHelper.removeActionsWithDuplicates(conversationActions);
+        if (request.getMaxSuggestions() >= 0
+                && conversationActions.size() > request.getMaxSuggestions()) {
+            conversationActions = conversationActions.subList(0, request.getMaxSuggestions());
+        }
         String resultId = ActionsSuggestionsHelper.createResultId(
                 mContext,
                 request.getConversation(),
diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
index 564cfdd..51ca805 100644
--- a/core/java/android/widget/SelectionActionModeHelper.java
+++ b/core/java/android/widget/SelectionActionModeHelper.java
@@ -933,12 +933,11 @@
             final String language = ExtrasUtils.getEntityType(foreignLanguageExtra);
             final float score = ExtrasUtils.getScore(foreignLanguageExtra);
             final String model = ExtrasUtils.getModelName(foreignLanguageExtra);
-            return new TextClassifierEvent.Builder(
-                    TextClassifierEvent.CATEGORY_LANGUAGE_DETECTION, eventType)
+            return new TextClassifierEvent.LanguageDetectionEvent.Builder(eventType)
                     .setEventContext(classificationContext)
                     .setResultId(classification.getId())
                     .setEntityTypes(language)
-                    .setScore(score)
+                    .setScores(score)
                     .setActionIndices(classification.getActions().indexOf(translateAction))
                     .setModelName(model)
                     .build();
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 1597ab7..54338bf 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -84,6 +84,7 @@
 import android.service.chooser.ChooserTargetService;
 import android.service.chooser.IChooserTargetResult;
 import android.service.chooser.IChooserTargetService;
+import android.text.SpannableStringBuilder;
 import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.HashedStringCache;
@@ -1546,6 +1547,29 @@
         float getModifiedScore();
 
         ChooserTarget getChooserTarget();
+
+        /**
+          * Do not label as 'equals', since this doesn't quite work
+          * as intended with java 8.
+          */
+        default boolean isSimilar(ChooserTargetInfo other) {
+            if (other == null) return false;
+
+            ChooserTarget ct1 = getChooserTarget();
+            ChooserTarget ct2 = other.getChooserTarget();
+
+            // If either is null, there is not enough info to make an informed decision
+            // about equality, so just exit
+            if (ct1 == null || ct2 == null) return false;
+
+            if (ct1.getComponentName().equals(ct2.getComponentName())
+                    && TextUtils.equals(getDisplayLabel(), other.getDisplayLabel())
+                    && TextUtils.equals(getExtendedInfo(), other.getExtendedInfo())) {
+                return true;
+            }
+
+            return false;
+        }
     }
 
     /**
@@ -1624,6 +1648,7 @@
         private final DisplayResolveInfo mSourceInfo;
         private final ResolveInfo mBackupResolveInfo;
         private final ChooserTarget mChooserTarget;
+        private final String mDisplayLabel;
         private Drawable mBadgeIcon = null;
         private CharSequence mBadgeContentDescription;
         private Drawable mDisplayIcon;
@@ -1661,6 +1686,8 @@
 
             mFillInIntent = null;
             mFillInFlags = 0;
+
+            mDisplayLabel = sanitizeDisplayLabel(chooserTarget.getTitle());
         }
 
         private SelectableTargetInfo(SelectableTargetInfo other, Intent fillInIntent, int flags) {
@@ -1673,6 +1700,14 @@
             mFillInIntent = fillInIntent;
             mFillInFlags = flags;
             mModifiedScore = other.mModifiedScore;
+
+            mDisplayLabel = sanitizeDisplayLabel(mChooserTarget.getTitle());
+        }
+
+        private String sanitizeDisplayLabel(CharSequence label) {
+            SpannableStringBuilder sb = new SpannableStringBuilder(label);
+            sb.clearSpans();
+            return sb.toString();
         }
 
         public boolean isSuspended() {
@@ -1811,7 +1846,7 @@
 
         @Override
         public CharSequence getDisplayLabel() {
-            return mChooserTarget.getTitle();
+            return mDisplayLabel;
         }
 
         @Override
@@ -2229,8 +2264,6 @@
             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++) {
@@ -2305,8 +2338,15 @@
                 return false;
             }
 
-            final float newScore = chooserTargetInfo.getModifiedScore();
+            // Check for duplicates and abort if found
+            for (ChooserTargetInfo otherTargetInfo : mServiceTargets) {
+                if (chooserTargetInfo.isSimilar(otherTargetInfo)) {
+                    return false;
+                }
+            }
+
             int currentSize = mServiceTargets.size();
+            final float newScore = chooserTargetInfo.getModifiedScore();
             for (int i = 0; i < Math.min(currentSize, MAX_SERVICE_TARGETS); i++) {
                 final ChooserTargetInfo serviceTarget = mServiceTargets.get(i);
                 if (serviceTarget == null) {
@@ -2393,15 +2433,11 @@
          * @return true if the view width has changed
          */
         public boolean calculateChooserTargetWidth(int width) {
-            int targetMinWidth = getResources().getDimensionPixelSize(
-                    R.dimen.chooser_target_width);
-
             if (width == 0) {
                 return false;
             }
 
-            int targetWidth =  width / getMaxTargetsPerRow();
-            int newWidth = Math.max(targetWidth, targetMinWidth);
+            int newWidth =  width / getMaxTargetsPerRow();
             if (newWidth != mChooserTargetWidth) {
                 mChooserTargetWidth = newWidth;
                 return true;
@@ -2622,12 +2658,24 @@
             }
         }
 
+        /**
+         * Need to merge CALLER + ranked STANDARD into a single row. All other types
+         * are placed into their own row as determined by their target type, and dividers
+         * are added in the list to separate each type.
+         */
+        int getRowType(int rowPosition) {
+            int positionType = mChooserListAdapter.getPositionTargetType(rowPosition);
+            if (positionType == ChooserListAdapter.TARGET_CALLER) {
+                return ChooserListAdapter.TARGET_STANDARD;
+            }
+
+            return positionType;
+        }
+
         void bindViewHolder(int rowPosition, RowViewHolder holder) {
             final int start = getFirstRowPosition(rowPosition);
-            final int startType = mChooserListAdapter.getPositionTargetType(start);
-
-            final int lastStartType = mChooserListAdapter.getPositionTargetType(
-                    getFirstRowPosition(rowPosition - 1));
+            final int startType = getRowType(start);
+            final int lastStartType = getRowType(getFirstRowPosition(rowPosition - 1));
 
             final ViewGroup row = holder.getViewGroup();
 
@@ -2639,7 +2687,7 @@
 
             int columnCount = holder.getColumnCount();
             int end = start + columnCount - 1;
-            while (mChooserListAdapter.getPositionTargetType(end) != startType && end >= start) {
+            while (getRowType(end) != startType && end >= start) {
                 end--;
             }
 
@@ -2691,14 +2739,15 @@
                 return row * getMaxTargetsPerRow();
             }
 
-            final int callerCount = mChooserListAdapter.getCallerTargetCount();
-            final int callerRows = (int) Math.ceil((float) callerCount / getMaxTargetsPerRow());
-            if (row < callerRows + serviceRows) {
+            final int callerAndRankedCount = mChooserListAdapter.getCallerTargetCount()
+                                                 + mChooserListAdapter.getRankedTargetCount();
+            final int callerAndRankedRows = getCallerAndRankedTargetRowCount();
+            if (row < callerAndRankedRows + serviceRows) {
                 return serviceCount + (row - serviceRows) * getMaxTargetsPerRow();
             }
 
-            return callerCount + serviceCount
-                    + (row - callerRows - serviceRows) * getMaxTargetsPerRow();
+            return callerAndRankedCount + serviceCount
+                    + (row - callerAndRankedRows - serviceRows) * getMaxTargetsPerRow();
         }
 
         public void handleScroll(View v, int y, int oldy) {
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index fd75f4f..21f8d87 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -45,6 +45,7 @@
 import android.content.res.Resources.Theme;
 import android.content.res.TypedArray;
 import android.graphics.Color;
+import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.media.AudioManager;
 import android.media.session.MediaController;
@@ -115,6 +116,7 @@
 
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
+import java.util.List;
 
 /**
  * Android-specific Window.
@@ -3926,4 +3928,15 @@
     public WindowInsetsController getInsetsController() {
         return mDecor.getWindowInsetsController();
     }
+
+    @Override
+    public void setSystemGestureExclusionRects(@NonNull List<Rect> rects) {
+        getViewRootImpl().setRootSystemGestureExclusionRects(rects);
+    }
+
+    @Override
+    @NonNull
+    public List<Rect> getSystemGestureExclusionRects() {
+        return getViewRootImpl().getRootSystemGestureExclusionRects();
+    }
 }
diff --git a/core/java/com/android/internal/util/TrafficStatsConstants.java b/core/java/com/android/internal/util/TrafficStatsConstants.java
new file mode 100644
index 0000000..2806ae2
--- /dev/null
+++ b/core/java/com/android/internal/util/TrafficStatsConstants.java
@@ -0,0 +1,43 @@
+/*
+ * 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.internal.util;
+
+/**
+ * Constants for traffic stats.
+ * @hide
+ */
+public class TrafficStatsConstants {
+    // These tags are used by the network stack to do traffic for its own purposes. Traffic
+    // tagged with these will be counted toward the network stack and must stay inside the
+    // range defined by
+    // {@link android.net.TrafficStats#TAG_NETWORK_STACK_RANGE_START} and
+    // {@link android.net.TrafficStats#TAG_NETWORK_STACK_RANGE_END}.
+    public static final int TAG_SYSTEM_DHCP = 0xFFFFFE01;
+    public static final int TAG_SYSTEM_NEIGHBOR = 0xFFFFFE02;
+    public static final int TAG_SYSTEM_DHCP_SERVER = 0xFFFFFE03;
+
+    public static final int TAG_SYSTEM_NTP = 0xFFFFFF41;
+    public static final int TAG_SYSTEM_GPS = 0xFFFFFF44;
+    public static final int TAG_SYSTEM_PAC = 0xFFFFFF45;
+
+    // These tags are used by the network stack to do traffic on behalf of apps. Traffic
+    // tagged with these will be counted toward the app on behalf of which the network
+    // stack is doing this traffic. These values must stay inside the range defined by
+    // {@link android.net.TrafficStats#TAG_NETWORK_STACK_IMPERSONATION_RANGE_START} and
+    // {@link android.net.TrafficStats#TAG_NETWORK_STACK_IMPERSONATION_RANGE_END}.
+    public static final int TAG_SYSTEM_PROBE = 0xFFFFFF81;
+}
diff --git a/core/jni/android_nio_utils.cpp b/core/jni/android_nio_utils.cpp
index a62dd7c..1e6d49e 100644
--- a/core/jni/android_nio_utils.cpp
+++ b/core/jni/android_nio_utils.cpp
@@ -18,51 +18,29 @@
 
 #include "core_jni_helpers.h"
 
-namespace {
+namespace android {
 
-void* getPointer(JNIEnv *_env, jobject buffer, jarray *array, void** elements) {
-    assert(array);
-    jint position;
-    jint limit;
-    jint elementSizeShift;
-    jlong pointer = jniGetNioBufferFields(_env, buffer, &position, &limit, &elementSizeShift);
+AutoBufferPointer::AutoBufferPointer(JNIEnv* env, jobject nioBuffer, jboolean commit)
+        : fEnv(env), fCommit(commit) {
+    jlong pointer = jniGetNioBufferPointer(fEnv, nioBuffer);
     if (pointer != 0L) {
-        *array = nullptr;
-        *elements = nullptr;
-        pointer += position << elementSizeShift;
-        return reinterpret_cast<void*>(pointer);
+        // Buffer is backed by a direct buffer.
+        fArray = nullptr;
+        fElements = nullptr;
+        fPointer = reinterpret_cast<void*>(pointer);
+    } else {
+        // Buffer is backed by a managed array.
+        jint byteOffset = jniGetNioBufferBaseArrayOffset(fEnv, nioBuffer);
+        fArray = jniGetNioBufferBaseArray(fEnv, nioBuffer);
+        fElements = fEnv->GetPrimitiveArrayCritical(fArray, /* isCopy= */ nullptr);
+        fPointer = reinterpret_cast<void*>(reinterpret_cast<char*>(fElements) + byteOffset);
     }
-    jint offset = jniGetNioBufferBaseArrayOffset(_env, buffer);
-    *array = jniGetNioBufferBaseArray(_env, buffer);
-    *elements = _env->GetPrimitiveArrayCritical(*array, (jboolean *) 0);
-    return reinterpret_cast<void*>(reinterpret_cast<char*>(*elements) + offset);
 }
 
-void releasePointer(JNIEnv *_env, jarray array, void *elements, jboolean commit) {
-    _env->ReleasePrimitiveArrayCritical(array, elements, commit ? 0 : JNI_ABORT);
-}
-
-}  // namespace
-
-void* android::nio_getPointer(JNIEnv *_env, jobject buffer, jarray *array) {
-    void* elements;
-    return getPointer(_env, buffer, array, &elements);
-}
-
-void android::nio_releasePointer(JNIEnv *_env, jarray array, void *data, jboolean commit) {
-    releasePointer(_env, array, data, commit);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-
-android::AutoBufferPointer::AutoBufferPointer(JNIEnv* env, jobject nioBuffer, jboolean commit) {
-    fEnv = env;
-    fCommit = commit;
-    fPointer = getPointer(env, nioBuffer, &fArray, &fElements);
-}
-
-android::AutoBufferPointer::~AutoBufferPointer() {
+AutoBufferPointer::~AutoBufferPointer() {
     if (nullptr != fArray) {
-        releasePointer(fEnv, fArray, fElements, fCommit);
+        fEnv->ReleasePrimitiveArrayCritical(fArray, fElements, fCommit ? 0 : JNI_ABORT);
     }
 }
+
+}  // namespace android
diff --git a/core/jni/android_nio_utils.h b/core/jni/android_nio_utils.h
index 7c9acd2..aa75dd0 100644
--- a/core/jni/android_nio_utils.h
+++ b/core/jni/android_nio_utils.h
@@ -22,51 +22,58 @@
 namespace android {
 
 /**
- * Given an nio.Buffer, return a pointer to it, beginning at its current
- * position. The returned pointer is only valid for the current JNI stack-frame.
- * For performance, it does not create any global references, so the getPointer
- * (and releasePointer if array is returned non-null) must be done in the
- * same JNI stack-frame.
+ * Class providing scoped access to the memory backing a java.nio.Buffer instance.
  *
- * @param env   The current JNI env
- * @param buffer    The nio.Buffer object
- * @param array     REQUIRED. Output. If on return it is set to non-null, then
- *                  nio_releasePointer must be called with the array
- *                  and the returned pointer when the caller is through with it.
- *                  If on return it is set to null, do not call
- *                  nio_releasePointer.
- * @return The pointer to the memory in the buffer object
- */
-void* nio_getPointer(JNIEnv *env, jobject buffer, jarray *array);
-
-/**
- * Call this if android_nio_getPointer returned non-null in its array parameter.
- * Pass that array and the returned pointer when you are done accessing the
- * pointer. If called (i.e. array is non-null), it must be called in the same
- * JNI stack-frame as getPointer
+ * Instances of this class should only be allocated on the stack as heap allocation is not
+ * supported.
  *
- * @param env   The current JNI env
- * @param buffer    The array returned from android_nio_getPointer (!= null)
- * @param pointer   The pointer returned by android_nio_getPointer
- * @param commit    JNI_FALSE if the pointer was just read, and JNI_TRUE if
- *                  the pointer was written to.
+ * Instances of this class do not create any global references for performance reasons.
  */
-void nio_releasePointer(JNIEnv *env, jarray array, void *pointer,
-                                jboolean commit);
-
-class AutoBufferPointer {
+class AutoBufferPointer final {
 public:
+    /** Constructor for an AutoBufferPointer instance.
+     *
+     * @param env          The current JNI env
+     * @param nioBuffer    Instance of a java.nio.Buffer whose memory will be accessed.
+     * @param commit       JNI_TRUE if the underlying memory will be updated and should be
+     *                     copied back to the managed heap. JNI_FALSE if the data will
+     *                     not be modified or the modifications may be discarded.
+     *
+     * The commit parameter is only applicable if the buffer is backed by a managed heap
+     * array and the runtime had to provide a copy of the data rather than the original data.
+     */
     AutoBufferPointer(JNIEnv* env, jobject nioBuffer, jboolean commit);
+
+    /** Destructor for an AutoBufferPointer instance.
+     *
+     * Releases critical managed heap array pointer if acquired.
+     */
     ~AutoBufferPointer();
 
+    /**
+     * Returns a pointer to the current position of the buffer provided to the constructor.  This
+     * pointer is only valid whilst the AutoBufferPointer instance remains in scope.
+     */
     void* pointer() const { return fPointer; }
 
 private:
-    JNIEnv* fEnv;
-    void*   fPointer;   // pointer to current buffer position.
-    void*   fElements;  // pointer to array element 0 (may be directly in fArray or a copy).
-    jarray  fArray;     // pointer to array on managed heap.
-    jboolean fCommit;   // commit data to source if required (when fElements is a copy of fArray).
+    JNIEnv* const fEnv;
+    void* fPointer;   // Pointer to current buffer position when constructed.
+    void* fElements;  // Pointer to array element 0 (null if buffer is direct, may be
+                      // within fArray or point to a copy of the array).
+    jarray fArray;    // Pointer to array on managed heap.
+    const jboolean fCommit;  // Flag to commit data to source (when fElements is a copy of fArray).
+
+    // Unsupported constructors and operators.
+    AutoBufferPointer() = delete;
+    AutoBufferPointer(AutoBufferPointer&) = delete;
+    AutoBufferPointer& operator=(AutoBufferPointer&) = delete;
+    static void* operator new(std::size_t);
+    static void* operator new[](std::size_t);
+    static void* operator new(std::size_t, void*);
+    static void* operator new[](std::size_t, void*);
+    static void operator delete(void*, std::size_t);
+    static void operator delete[](void*, std::size_t);
 };
 
 }   /* namespace android */
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index f599913..e2214d1 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -73,6 +73,7 @@
 #include <android-base/stringprintf.h>
 #include <android-base/strings.h>
 #include <android-base/unique_fd.h>
+#include <bionic_malloc.h>
 #include <cutils/ashmem.h>
 #include <cutils/fs.h>
 #include <cutils/multiuser.h>
@@ -499,12 +500,9 @@
   }
 }
 
-// The debug malloc library needs to know whether it's the zygote or a child.
-extern "C" int gMallocLeakZygoteChild;
-
 static void PreApplicationInit() {
   // The child process sets this to indicate it's not the zygote.
-  gMallocLeakZygoteChild = 1;
+  android_mallopt(M_SET_ZYGOTE_CHILD, nullptr, 0);
 
   // Set the jemalloc decay time to 1.
   mallopt(M_DECAY_TIME, 1);
diff --git a/core/proto/android/os/enums.proto b/core/proto/android/os/enums.proto
index c357065..566861b 100644
--- a/core/proto/android/os/enums.proto
+++ b/core/proto/android/os/enums.proto
@@ -78,6 +78,41 @@
     TEMPERATURE_TYPE_NPU = 9;
 }
 
+// Device throttling severity
+// These constants are defined in hardware/interfaces/thermal/2.0/types.hal.
+// Any change to the types in the thermal hal should be made here as well.
+enum ThrottlingSeverityEnum {
+    // Not under throttling.
+    NONE = 0;
+    // Light throttling where UX is not impacted.
+    LIGHT = 1;
+    // Moderate throttling where UX is not largely impacted.
+    MODERATE = 2;
+    // Severe throttling where UX is largely impacted.
+    // Similar to 1.0 throttlingThreshold.
+    SEVERE = 3;
+    // Platform has done everything to reduce power.
+    CRITICAL = 4;
+    // Key components in platform are shutting down due to thermal condition.
+    // Device functionalities will be limited.
+    EMERGENCY = 5;
+    // Need shutdown immediately.
+    SHUTDOWN = 6;
+};
+
+// Device cooling device types.
+// These constants are defined in hardware/interfaces/thermal/2.0/types.hal.
+// Any change to the types in the thermal hal should be made here as well.
+enum CoolingTypeEnum {
+    FAN = 0;
+    BATTERY = 1;
+    CPU = 2;
+    GPU = 3;
+    MODEM = 4;
+    NPU = 5;
+    COMPONENT = 6;
+};
+
 // Wakelock types, primarily used by android/os/PowerManager.java.
 enum WakeLockLevelEnum {
     // NOTE: Wake lock levels were previously defined as a bit field, except
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index cc3b3a4..8714bf2 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -828,6 +828,7 @@
         android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_sdcardRead"
         android:description="@string/permdesc_sdcardRead"
+        android:permissionFlags="softRestricted|immutablyRestricted"
         android:protectionLevel="dangerous" />
 
     <!-- Allows an application to write to external storage.
@@ -848,6 +849,7 @@
         android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_sdcardWrite"
         android:description="@string/permdesc_sdcardWrite"
+        android:permissionFlags="softRestricted|immutablyRestricted"
         android:protectionLevel="dangerous" />
 
     <!-- Allows an application to access any geographic locations persisted in the
diff --git a/core/res/res/drawable/chooser_row_layer_list.xml b/core/res/res/drawable/chooser_row_layer_list.xml
index 0fb26e1..0800815 100644
--- a/core/res/res/drawable/chooser_row_layer_list.xml
+++ b/core/res/res/drawable/chooser_row_layer_list.xml
@@ -17,7 +17,7 @@
 */
 -->
 <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:bottom="-2dp" android:left="-2dp" android:right="-2dp">
+    <item android:bottom="-5dp" android:left="-5dp" android:right="-5dp">
         <shape android:shape="rectangle">
             <stroke android:width="1dp" android:color="@color/chooser_row_divider"/>
         </shape>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index bfa57e4..bbc784a 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -328,6 +328,12 @@
              would be granted. The weak grant depends on the permission.
         -->
         <flag name="softRestricted" value="0x8" />
+        <!-- This permission is restricted immutably which means that its
+             restriction state may be specified only on the first install of
+             the app and will stay in this initial whitelist state until
+             the app is uninstalled.
+        -->
+        <flag name="immutablyRestricted" value="0x10" />
     </attr>
 
     <!-- Specified the name of a group that this permission is associated
@@ -1707,17 +1713,18 @@
              See {@link android.media.AudioPlaybackCaptureConfiguration} for more detail.
              -->
         <attr name="allowAudioPlaybackCapture" format="boolean" />
-        <!-- If {@code true} this app allows shared/external storage media to be
-             a sandboxed view that only contains files owned by the app.
-             <p>
-             Sandboxed apps can continue to discover and read media belonging to other
-             apps via {@code MediaStore}.
+        <!-- If {@code true} this app would like to run under the legacy storage
+             model. Note that this may not always be respected due to policy or
+             backwards compatibility reasons.
+
+             <p>Apps not requesting legacy storage can continue to discover and
+             read media belonging to other apps via {@code MediaStore}.
              <p>
              The default value is:
-                 - {@code true} for apps with targetSdkVersion >= 29 (Q).
-                 - {@code false} for apps with targetSdkVersion < 29.
+                 - {@code false} for apps with targetSdkVersion >= 29 (Q).
+                 - {@code true} for apps with targetSdkVersion < 29.
              -->
-        <attr name="allowExternalStorageSandbox" format="boolean" />
+        <attr name="requestLegacyExternalStorage" format="boolean" />
     </declare-styleable>
     <!-- The <code>permission</code> tag declares a security permission that can be
          used to control access from other packages to specific components or
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 5268189..4d6fda9 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3483,6 +3483,12 @@
         <item>com.android.messaging</item>
     </string-array>
 
+    <!-- An array of packages that can make sound on the ringer stream in priority-only DND
+     mode -->
+    <string-array translatable="false" name="config_priorityOnlyDndExemptPackages">
+        <item>com.android.dialer</item>
+    </string-array>
+
     <!-- An array of packages which can listen for notifications on low ram devices. -->
     <string-array translatable="false" name="config_allowedManagedServicesOnLowRamDevices" />
 
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index b7d61c8..a7af144 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2942,7 +2942,7 @@
         <public name="allowClearUserDataOnFailedRestore"/>
         <public name="allowAudioPlaybackCapture"/>
         <public name="secureElementName" />
-        <public name="allowExternalStorageSandbox"/>
+        <public name="requestLegacyExternalStorage"/>
         <public name="ensuringStatusBarContrastWhenTransparent" />
         <public name="ensuringNavigationBarContrastWhenTransparent" />
         <public name="identifier" />
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 94b5da6..924b036 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3188,6 +3188,7 @@
   <java-symbol type="array" name="config_convert_to_emergency_number_map" />
 
   <java-symbol type="array" name="config_nonBlockableNotificationPackages" />
+  <java-symbol type="array" name="config_priorityOnlyDndExemptPackages" />
 
   <java-symbol type="array" name="config_allowedManagedServicesOnLowRamDevices" />
 
diff --git a/core/tests/coretests/src/android/graphics/BitmapTest.java b/core/tests/coretests/src/android/graphics/BitmapTest.java
index 4bee243..2280cf1 100644
--- a/core/tests/coretests/src/android/graphics/BitmapTest.java
+++ b/core/tests/coretests/src/android/graphics/BitmapTest.java
@@ -23,6 +23,8 @@
 import junit.framework.TestCase;
 
 import java.nio.ByteBuffer;
+import java.nio.IntBuffer;
+import java.nio.ShortBuffer;
 
 public class BitmapTest extends TestCase {
 
@@ -266,10 +268,11 @@
     }
 
     @SmallTest
-    public void testCopyWithDirectBuffer() {
+    public void testCopyWithDirectByteBuffer() {
         // Initialize Bitmap
         final int width = 2;
         final int height = 2;
+        final int bytesPerPixel = 2;
         Bitmap bm1 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
         bm1.setPixels(new int[] { 0xff, 0xeeee, 0xdddddd, 0xcccccccc }, 0, 2, 0, 0, 2, 2);
 
@@ -277,7 +280,8 @@
         // of bitmap.
         final int pad = 1;
         final byte padValue = 0x5a;
-        final int bufferSize = pad + width * height * 2 + pad;
+        final int bytesPerElement = 1;
+        final int bufferSize = pad + width * height * bytesPerPixel / bytesPerElement + pad;
         ByteBuffer directBuffer = ByteBuffer.allocateDirect(bufferSize);
 
         // Write padding
@@ -287,7 +291,8 @@
         // Copy bitmap
         directBuffer.position(pad);
         bm1.copyPixelsToBuffer(directBuffer);
-        assertEquals(directBuffer.position(), pad + width * height * 2);
+        assertEquals(directBuffer.position(),
+                     pad + width * height * bytesPerPixel / bytesPerElement);
 
         // Check padding
         assertEquals(directBuffer.get(0), padValue);
@@ -301,10 +306,89 @@
     }
 
     @SmallTest
-    public void testCopyWithHeapBuffer() {
+    public void testCopyWithDirectShortBuffer() {
         // Initialize Bitmap
         final int width = 2;
         final int height = 2;
+        final int bytesPerPixel = 2;
+        Bitmap bm1 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
+        bm1.setPixels(new int[] { 0xff, 0xeeee, 0xdddddd, 0xcccccccc }, 0, 2, 0, 0, 2, 2);
+
+        // Copy bytes to heap buffer, buffer is padded by fixed amount (pad bytes) either side
+        // of bitmap.
+        final int pad = 1;
+        final short padValue = 0x55aa;
+        final int bytesPerElement = 2;
+        final int bufferSize = pad + width * height * bytesPerPixel / bytesPerElement + pad;
+        ShortBuffer directBuffer =
+                ByteBuffer.allocateDirect(bufferSize * bytesPerElement).asShortBuffer();
+
+        // Write padding
+        directBuffer.put(0, padValue);
+        directBuffer.put(directBuffer.limit() - 1, padValue);
+
+        // Copy bitmap
+        directBuffer.position(pad);
+        bm1.copyPixelsToBuffer(directBuffer);
+        assertEquals(directBuffer.position(),
+                     pad + width * height * bytesPerPixel / bytesPerElement);
+
+        // Check padding
+        assertEquals(directBuffer.get(0), padValue);
+        assertEquals(directBuffer.get(directBuffer.limit() - 1), padValue);
+
+        // Create bitmap from heap buffer and check match.
+        directBuffer.position(pad);
+        Bitmap bm2 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
+        bm2.copyPixelsFromBuffer(directBuffer);
+        assertTrue(bm2.sameAs(bm1));
+    }
+
+    @SmallTest
+    public void testCopyWithDirectIntBuffer() {
+        // Initialize Bitmap
+        final int width = 2;
+        final int height = 2;
+        final int bytesPerPixel = 2;
+        Bitmap bm1 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
+        bm1.setPixels(new int[] { 0xff, 0xeeee, 0xdddddd, 0xcccccccc }, 0, 2, 0, 0, 2, 2);
+
+        // Copy bytes to heap buffer, buffer is padded by fixed amount (pad bytes) either side
+        // of bitmap.
+        final int pad = 1;
+        final int padValue = 0x55aa5a5a;
+        final int bytesPerElement = 4;
+        final int bufferSize = pad + width * height * bytesPerPixel / bytesPerElement + pad;
+        IntBuffer directBuffer =
+                ByteBuffer.allocateDirect(bufferSize * bytesPerElement).asIntBuffer();
+
+        // Write padding
+        directBuffer.put(0, padValue);
+        directBuffer.put(directBuffer.limit() - 1, padValue);
+
+        // Copy bitmap
+        directBuffer.position(pad);
+        bm1.copyPixelsToBuffer(directBuffer);
+        assertEquals(directBuffer.position(),
+                     pad + width * height * bytesPerPixel / bytesPerElement);
+
+        // Check padding
+        assertEquals(directBuffer.get(0), padValue);
+        assertEquals(directBuffer.get(directBuffer.limit() - 1), padValue);
+
+        // Create bitmap from heap buffer and check match.
+        directBuffer.position(pad);
+        Bitmap bm2 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
+        bm2.copyPixelsFromBuffer(directBuffer);
+        assertTrue(bm2.sameAs(bm1));
+    }
+
+    @SmallTest
+    public void testCopyWithHeapByteBuffer() {
+        // Initialize Bitmap
+        final int width = 2;
+        final int height = 2;
+        final int bytesPerPixel = 2;
         Bitmap bm1 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
         bm1.setPixels(new int[] { 0xff, 0xeeee, 0xdddddd, 0xcccccccc }, 0, 2, 0, 0, 2, 2);
 
@@ -312,7 +396,8 @@
         // of bitmap.
         final int pad = 1;
         final byte padValue = 0x5a;
-        final int bufferSize = pad + width * height * 2 + pad;
+        final int bytesPerElement = 1;
+        final int bufferSize = pad + width * height * bytesPerPixel / bytesPerElement + pad;
         ByteBuffer heapBuffer = ByteBuffer.allocate(bufferSize);
 
         // Write padding
@@ -322,7 +407,81 @@
         // Copy bitmap
         heapBuffer.position(pad);
         bm1.copyPixelsToBuffer(heapBuffer);
-        assertEquals(heapBuffer.position(), pad + width * height * 2);
+        assertEquals(heapBuffer.position(), pad + width * height * bytesPerPixel / bytesPerElement);
+
+        // Check padding
+        assertEquals(heapBuffer.get(0), padValue);
+        assertEquals(heapBuffer.get(heapBuffer.limit() - 1), padValue);
+
+        // Create bitmap from heap buffer and check match.
+        heapBuffer.position(pad);
+        Bitmap bm2 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
+        bm2.copyPixelsFromBuffer(heapBuffer);
+        assertTrue(bm2.sameAs(bm1));
+    }
+
+    @SmallTest
+    public void testCopyWithHeapShortBuffer() {
+        // Initialize Bitmap
+        final int width = 2;
+        final int height = 2;
+        final int bytesPerPixel = 2;
+        Bitmap bm1 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
+        bm1.setPixels(new int[] { 0xff, 0xeeee, 0xdddddd, 0xcccccccc }, 0, 2, 0, 0, 2, 2);
+
+        // Copy bytes to heap buffer, buffer is padded by fixed amount (pad bytes) either side
+        // of bitmap.
+        final int pad = 1;
+        final short padValue = 0x55aa;
+        final int bytesPerElement = 2;
+        final int bufferSize = pad + width * height * bytesPerPixel / bytesPerElement + pad;
+        ShortBuffer heapBuffer = ShortBuffer.allocate(bufferSize);
+
+        // Write padding
+        heapBuffer.put(0, padValue);
+        heapBuffer.put(heapBuffer.limit() - 1, padValue);
+
+        // Copy bitmap
+        heapBuffer.position(pad);
+        bm1.copyPixelsToBuffer(heapBuffer);
+        assertEquals(heapBuffer.position(), pad + width * height * bytesPerPixel / bytesPerElement);
+
+        // Check padding
+        assertEquals(heapBuffer.get(0), padValue);
+        assertEquals(heapBuffer.get(heapBuffer.limit() - 1), padValue);
+
+        // Create bitmap from heap buffer and check match.
+        heapBuffer.position(pad);
+        Bitmap bm2 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
+        bm2.copyPixelsFromBuffer(heapBuffer);
+        assertTrue(bm2.sameAs(bm1));
+    }
+
+    @SmallTest
+    public void testCopyWithHeapIntBuffer() {
+        // Initialize Bitmap
+        final int width = 2;
+        final int height = 2;
+        final int bytesPerPixel = 2;
+        Bitmap bm1 = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
+        bm1.setPixels(new int[] { 0xff, 0xeeee, 0xdddddd, 0xcccccccc }, 0, 2, 0, 0, 2, 2);
+
+        // Copy bytes to heap buffer, buffer is padded by fixed amount (pad bytes) either side
+        // of bitmap.
+        final int pad = 1;
+        final int padValue = 0x55aa5a5a;
+        final int bytesPerElement = 4;
+        final int bufferSize = pad + width * height * bytesPerPixel / bytesPerElement + pad;
+        IntBuffer heapBuffer = IntBuffer.allocate(bufferSize);
+
+        // Write padding
+        heapBuffer.put(0, padValue);
+        heapBuffer.put(heapBuffer.limit() - 1, padValue);
+
+        // Copy bitmap
+        heapBuffer.position(pad);
+        bm1.copyPixelsToBuffer(heapBuffer);
+        assertEquals(heapBuffer.position(), pad + width * height * bytesPerPixel / bytesPerElement);
 
         // Check padding
         assertEquals(heapBuffer.get(0), padValue);
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
index 433991e..aeb8949 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
@@ -362,6 +362,38 @@
     }
 
     @Test
+    public void testGenerateLinks_entityData() {
+        if (isTextClassifierDisabled()) return;
+        String text = "The number is +12122537077.";
+        Bundle extras = new Bundle();
+        ExtrasUtils.putIsSerializedEntityDataEnabled(extras, true);
+        TextLinks.Request request = new TextLinks.Request.Builder(text).setExtras(extras).build();
+
+        TextLinks textLinks = mClassifier.generateLinks(request);
+
+        Truth.assertThat(textLinks.getLinks()).hasSize(1);
+        TextLinks.TextLink textLink = textLinks.getLinks().iterator().next();
+        List<Bundle> entities = ExtrasUtils.getEntities(textLink.getExtras());
+        Truth.assertThat(entities).hasSize(1);
+        Bundle entity = entities.get(0);
+        Truth.assertThat(ExtrasUtils.getEntityType(entity)).isEqualTo(TextClassifier.TYPE_PHONE);
+    }
+
+    @Test
+    public void testGenerateLinks_entityData_disabled() {
+        if (isTextClassifierDisabled()) return;
+        String text = "The number is +12122537077.";
+        TextLinks.Request request = new TextLinks.Request.Builder(text).build();
+
+        TextLinks textLinks = mClassifier.generateLinks(request);
+
+        Truth.assertThat(textLinks.getLinks()).hasSize(1);
+        TextLinks.TextLink textLink = textLinks.getLinks().iterator().next();
+        List<Bundle> entities = ExtrasUtils.getEntities(textLink.getExtras());
+        Truth.assertThat(entities).isNull();
+    }
+
+    @Test
     public void testDetectLanguage() {
         if (isTextClassifierDisabled()) return;
         String text = "This is English text";
@@ -380,7 +412,7 @@
     }
 
     @Test
-    public void testSuggestConversationActions_textReplyOnly_maxThree() {
+    public void testSuggestConversationActions_textReplyOnly_maxOne() {
         if (isTextClassifierDisabled()) return;
         ConversationActions.Message message =
                 new ConversationActions.Message.Builder(
@@ -399,12 +431,11 @@
                         .build();
 
         ConversationActions conversationActions = mClassifier.suggestConversationActions(request);
-        assertTrue(conversationActions.getConversationActions().size() > 0);
-        for (ConversationAction conversationAction :
-                conversationActions.getConversationActions()) {
-            assertThat(conversationAction,
-                    isConversationAction(ConversationAction.TYPE_TEXT_REPLY));
-        }
+        Truth.assertThat(conversationActions.getConversationActions()).hasSize(1);
+        ConversationAction conversationAction = conversationActions.getConversationActions().get(0);
+        Truth.assertThat(conversationAction.getType()).isEqualTo(
+                ConversationAction.TYPE_TEXT_REPLY);
+        Truth.assertThat(conversationAction.getTextReply()).isNotNull();
     }
 
     @Test
@@ -493,6 +524,24 @@
                 ExtrasUtils.getSerializedEntityData(conversationAction.getExtras())).isNotEmpty();
     }
 
+    @Test
+    public void testSuggetsConversationActions_deduplicate() {
+        if (isTextClassifierDisabled()) return;
+        ConversationActions.Message message =
+                new ConversationActions.Message.Builder(
+                        ConversationActions.Message.PERSON_USER_OTHERS)
+                        .setText("a@android.com b@android.com")
+                        .build();
+        ConversationActions.Request request =
+                new ConversationActions.Request.Builder(Collections.singletonList(message))
+                        .setMaxSuggestions(3)
+                        .build();
+
+        ConversationActions conversationActions = mClassifier.suggestConversationActions(request);
+
+        Truth.assertThat(conversationActions.getConversationActions()).isEmpty();
+    }
+
     private boolean isTextClassifierDisabled() {
         return mClassifier == null || mClassifier == TextClassifier.NO_OP;
     }
diff --git a/core/tests/coretests/src/android/view/textclassifier/logging/TextClassifierEventTronLoggerTest.java b/core/tests/coretests/src/android/view/textclassifier/logging/TextClassifierEventTronLoggerTest.java
index 1980a60..2c540e5 100644
--- a/core/tests/coretests/src/android/view/textclassifier/logging/TextClassifierEventTronLoggerTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/logging/TextClassifierEventTronLoggerTest.java
@@ -49,8 +49,6 @@
 public class TextClassifierEventTronLoggerTest {
     private static final String WIDGET_TYPE = "notification";
     private static final String PACKAGE_NAME = "pkg";
-    private static final long EVENT_TIME = System.currentTimeMillis();
-
 
     @Mock
     private MetricsLogger mMetricsLogger;
@@ -68,13 +66,11 @@
         TextClassificationContext textClassificationContext =
                 new TextClassificationContext.Builder(PACKAGE_NAME, WIDGET_TYPE)
                         .build();
-        TextClassifierEvent textClassifierEvent =
-                new TextClassifierEvent.Builder(
-                        TextClassifierEvent.CATEGORY_CONVERSATION_ACTIONS,
+        TextClassifierEvent.ConversationActionsEvent textClassifierEvent =
+                new TextClassifierEvent.ConversationActionsEvent.Builder(
                         TextClassifierEvent.TYPE_SMART_ACTION)
                         .setEntityTypes(ConversationAction.TYPE_CALL_PHONE)
-                        .setScore(0.5f)
-                        .setEventTime(EVENT_TIME)
+                        .setScores(0.5f)
                         .setEventContext(textClassificationContext)
                         .build();
 
@@ -83,10 +79,8 @@
         ArgumentCaptor<LogMaker> captor = ArgumentCaptor.forClass(LogMaker.class);
         Mockito.verify(mMetricsLogger).write(captor.capture());
         LogMaker logMaker = captor.getValue();
-        assertThat(logMaker.getCategory()).isEqualTo(
-                CONVERSATION_ACTIONS);
-        assertThat(logMaker.getSubtype()).isEqualTo(
-                ACTION_TEXT_SELECTION_SMART_SHARE);
+        assertThat(logMaker.getCategory()).isEqualTo(CONVERSATION_ACTIONS);
+        assertThat(logMaker.getSubtype()).isEqualTo(ACTION_TEXT_SELECTION_SMART_SHARE);
         assertThat(logMaker.getTaggedData(FIELD_TEXT_CLASSIFIER_FIRST_ENTITY_TYPE))
                 .isEqualTo(ConversationAction.TYPE_CALL_PHONE);
         assertThat((float) logMaker.getTaggedData(FIELD_TEXT_CLASSIFIER_SCORE))
@@ -101,9 +95,8 @@
 
     @Test
     public void testWriteEvent_unsupportedCategory() {
-        TextClassifierEvent textClassifierEvent =
-                new TextClassifierEvent.Builder(
-                        TextClassifierEvent.CATEGORY_SELECTION,
+        TextClassifierEvent.TextSelectionEvent textClassifierEvent =
+                new TextClassifierEvent.TextSelectionEvent.Builder(
                         TextClassifierEvent.TYPE_SMART_ACTION)
                         .build();
 
diff --git a/core/tests/mockingcoretests/Android.bp b/core/tests/mockingcoretests/Android.bp
new file mode 100644
index 0000000..ae3ff86
--- /dev/null
+++ b/core/tests/mockingcoretests/Android.bp
@@ -0,0 +1,53 @@
+//
+// 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.
+//
+
+android_test {
+    name: "FrameworksMockingCoreTests",
+
+    srcs: [
+        "src/**/*.java",
+    ],
+
+    static_libs: [
+        "frameworks-base-testutils",
+        "services.core",
+        "androidx.test.runner",
+        "androidx.test.rules",
+        "androidx.test.ext.junit",
+        "mockito-target-extended-minus-junit4",
+        "platform-test-annotations",
+        "truth-prebuilt",
+        "testables",
+        "ub-uiautomator",
+    ],
+
+    libs: [
+        "android.test.base",
+        "android.test.mock",
+        "android.test.runner",
+    ],
+
+    // These are not normally accessible from apps so they must be explicitly included.
+    jni_libs: [
+        "libdexmakerjvmtiagent",
+        "libstaticjvmtiagent",
+    ],
+
+    platform_apis: true,
+    test_suites: ["device-tests"],
+
+    certificate: "platform",
+}
diff --git a/core/tests/mockingcoretests/AndroidManifest.xml b/core/tests/mockingcoretests/AndroidManifest.xml
new file mode 100644
index 0000000..b9ee085
--- /dev/null
+++ b/core/tests/mockingcoretests/AndroidManifest.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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
+  -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+          android:installLocation="internalOnly"
+          package="com.android.frameworks.mockingcoretests"
+          android:sharedUserId="com.android.uid.test">
+
+    <application android:supportsRtl="true" android:debuggable="true">
+        <uses-library android:name="android.test.runner" />
+
+        <activity android:name="android.app.activity.ActivityThreadClientTest$TestActivity"
+            android:exported="true">
+        </activity>
+
+    </application>
+
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
+            android:targetPackage="com.android.frameworks.mockingcoretests"
+            android:label="Frameworks Mocking Core Tests" />
+</manifest>
diff --git a/core/tests/mockingcoretests/AndroidTest.xml b/core/tests/mockingcoretests/AndroidTest.xml
new file mode 100644
index 0000000..47aa410
--- /dev/null
+++ b/core/tests/mockingcoretests/AndroidTest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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
+  -->
+<configuration description="Runs Frameworks Mocking Core Tests.">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-instrumentation" />
+
+    <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
+        <option name="cleanup-apks" value="true" />
+        <option name="test-file-name" value="FrameworksMockingCoreTests.apk" />
+    </target_preparer>
+    <option name="test-tag" value="FrameworksMockingCoreTests" />
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
+        <option name="package" value="com.android.frameworks.mockingcoretests" />
+        <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
+        <option name="hidden-api-checks" value="false"/>
+    </test>
+</configuration>
diff --git a/core/tests/mockingcoretests/README b/core/tests/mockingcoretests/README
new file mode 100644
index 0000000..c0f65c2
--- /dev/null
+++ b/core/tests/mockingcoretests/README
@@ -0,0 +1,33 @@
+* 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.
+
+
+INTRODUCTION
+
+The Android platform core tests that require additional mocking capabilities and use Extended
+Mockito, such as the ability to stub static methods. ExtendedMockito is not fully compatible with
+regular Mockito library, so tests that use it have to be verified and adapted. For that reason a
+separate module is used instead of adding to FrameworksCoreTests.
+
+For more information about ExtendedMockito see documentation of
+com.android.dx.mockito.inline.extended.ExtendedMockito class.
+
+See ../coretests/README for more information on FrameworksCoreTests.
+
+
+INSTRUCTIONS
+
+To build, install and run:
+
+  atest FrameworksMockingCoreTests
diff --git a/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
new file mode 100644
index 0000000..86d55ea
--- /dev/null
+++ b/core/tests/mockingcoretests/src/android/app/activity/ActivityThreadClientTest.java
@@ -0,0 +1,362 @@
+/*
+ * 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.app.activity;
+
+import static android.app.servertransaction.ActivityLifecycleItem.ON_CREATE;
+import static android.app.servertransaction.ActivityLifecycleItem.ON_DESTROY;
+import static android.app.servertransaction.ActivityLifecycleItem.ON_PAUSE;
+import static android.app.servertransaction.ActivityLifecycleItem.ON_RESUME;
+import static android.app.servertransaction.ActivityLifecycleItem.ON_START;
+import static android.app.servertransaction.ActivityLifecycleItem.ON_STOP;
+
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.when;
+
+import android.app.Activity;
+import android.app.ActivityTaskManager;
+import android.app.ActivityThread;
+import android.app.ActivityThread.ActivityClientRecord;
+import android.app.IActivityTaskManager;
+import android.app.servertransaction.PendingTransactionActions;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.res.CompatibilityInfo;
+import android.content.res.Configuration;
+import android.os.Binder;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.view.WindowManagerGlobal;
+
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.MediumTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mockito;
+import org.mockito.MockitoSession;
+import org.mockito.quality.Strictness;
+
+/**
+ * Test for verifying {@link android.app.ActivityThread} class.
+ *
+ * <p>Build/Install/Run:
+ *  atest FrameworksMockingCoreTests:android.app.activity.ActivityThreadClientTest
+ *
+ * <p>This test class is a part of Window Manager Service tests and specified in
+ * {@link com.android.server.wm.test.filters.FrameworksTestsFilter}.
+ */
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+public class ActivityThreadClientTest {
+
+    @Test
+    @UiThreadTest
+    public void testWindowVisibilityChange_OnCreate() throws Exception {
+        try (ClientMockSession clientSession = new ClientMockSession()) {
+            ActivityClientRecord r = clientSession.stubActivityRecord();
+
+            clientSession.launchActivity(r);
+            assertEquals(ON_CREATE, r.getLifecycleState());
+
+            clientSession.changeVisibility(r, true);
+            assertEquals(ON_CREATE, r.getLifecycleState());
+
+            clientSession.changeVisibility(r, false);
+            assertEquals(ON_CREATE, r.getLifecycleState());
+        }
+    }
+
+    @Test
+    @UiThreadTest
+    public void testWindowVisibilityChange_OnCreate_Finished() throws Exception {
+        try (ClientMockSession clientSession = new ClientMockSession()) {
+            ActivityClientRecord r = clientSession.stubActivityRecord();
+
+            Activity activity = clientSession.launchActivity(r);
+            activity.finish();
+            assertEquals(ON_CREATE, r.getLifecycleState());
+
+            clientSession.changeVisibility(r, true);
+            assertEquals(ON_CREATE, r.getLifecycleState());
+
+            clientSession.changeVisibility(r, false);
+            assertEquals(ON_CREATE, r.getLifecycleState());
+        }
+    }
+
+    @Test
+    @UiThreadTest
+    public void testWindowVisibilityChange_OnStart() throws Exception {
+        try (ClientMockSession clientSession = new ClientMockSession()) {
+            ActivityClientRecord r = clientSession.stubActivityRecord();
+
+            clientSession.launchActivity(r);
+            clientSession.startActivity(r);
+            assertEquals(ON_START, r.getLifecycleState());
+
+            clientSession.changeVisibility(r, false);
+            assertEquals(ON_STOP, r.getLifecycleState());
+
+            clientSession.changeVisibility(r, true);
+            assertEquals(ON_START, r.getLifecycleState());
+        }
+    }
+
+    @Test
+    @UiThreadTest
+    public void testWindowVisibilityChange_OnStart_Finished() throws Exception {
+        try (ClientMockSession clientSession = new ClientMockSession()) {
+            ActivityClientRecord r = clientSession.stubActivityRecord();
+
+            Activity activity = clientSession.launchActivity(r);
+            clientSession.startActivity(r);
+            activity.finish();
+            assertEquals(ON_START, r.getLifecycleState());
+
+            clientSession.changeVisibility(r, false);
+            assertEquals(ON_STOP, r.getLifecycleState());
+
+            clientSession.changeVisibility(r, true);
+            assertEquals(ON_START, r.getLifecycleState());
+        }
+    }
+
+    @Test
+    @UiThreadTest
+    public void testWindowVisibilityChange_OnResume() throws Exception {
+        try (ClientMockSession clientSession = new ClientMockSession()) {
+            ActivityClientRecord r = clientSession.stubActivityRecord();
+
+            clientSession.launchActivity(r);
+            clientSession.startActivity(r);
+            clientSession.resumeActivity(r);
+            assertEquals(ON_RESUME, r.getLifecycleState());
+
+            clientSession.changeVisibility(r, false);
+            assertEquals(ON_STOP, r.getLifecycleState());
+
+            clientSession.changeVisibility(r, true);
+            assertEquals(ON_START, r.getLifecycleState());
+        }
+    }
+
+    @Test
+    @UiThreadTest
+    public void testWindowVisibilityChange_OnPause() throws Exception {
+        try (ClientMockSession clientSession = new ClientMockSession()) {
+            ActivityClientRecord r = clientSession.stubActivityRecord();
+
+            clientSession.launchActivity(r);
+            clientSession.startActivity(r);
+            clientSession.resumeActivity(r);
+            clientSession.pauseActivity(r);
+            assertEquals(ON_PAUSE, r.getLifecycleState());
+
+            clientSession.changeVisibility(r, false);
+            assertEquals(ON_STOP, r.getLifecycleState());
+
+            clientSession.changeVisibility(r, true);
+            assertEquals(ON_START, r.getLifecycleState());
+        }
+    }
+
+    @Test
+    @UiThreadTest
+    public void testWindowVisibilityChange_OnStop() throws Exception {
+        try (ClientMockSession clientSession = new ClientMockSession()) {
+            ActivityClientRecord r = clientSession.stubActivityRecord();
+
+            clientSession.launchActivity(r);
+            clientSession.startActivity(r);
+            clientSession.resumeActivity(r);
+            clientSession.pauseActivity(r);
+            clientSession.stopActivity(r);
+            assertEquals(ON_STOP, r.getLifecycleState());
+
+            clientSession.changeVisibility(r, true);
+            assertEquals(ON_START, r.getLifecycleState());
+
+            clientSession.changeVisibility(r, false);
+            assertEquals(ON_STOP, r.getLifecycleState());
+        }
+    }
+
+    @Test
+    @UiThreadTest
+    public void testLifecycleAfterFinished_OnCreate() throws Exception {
+        try (ClientMockSession clientSession = new ClientMockSession()) {
+            ActivityClientRecord r = clientSession.stubActivityRecord();
+
+            Activity activity = clientSession.launchActivity(r);
+            activity.finish();
+            assertEquals(ON_CREATE, r.getLifecycleState());
+
+            clientSession.startActivity(r);
+            assertEquals(ON_CREATE, r.getLifecycleState());
+
+            clientSession.resumeActivity(r);
+            assertEquals(ON_CREATE, r.getLifecycleState());
+
+            clientSession.pauseActivity(r);
+            assertEquals(ON_CREATE, r.getLifecycleState());
+
+            clientSession.stopActivity(r);
+            assertEquals(ON_CREATE, r.getLifecycleState());
+
+            clientSession.destroyActivity(r);
+            assertEquals(ON_DESTROY, r.getLifecycleState());
+        }
+    }
+
+    @Test
+    @UiThreadTest
+    public void testLifecycleAfterFinished_OnStart() throws Exception {
+        try (ClientMockSession clientSession = new ClientMockSession()) {
+            ActivityClientRecord r = clientSession.stubActivityRecord();
+
+            Activity activity = clientSession.launchActivity(r);
+            clientSession.startActivity(r);
+            activity.finish();
+            assertEquals(ON_START, r.getLifecycleState());
+
+            clientSession.resumeActivity(r);
+            assertEquals(ON_START, r.getLifecycleState());
+
+            clientSession.pauseActivity(r);
+            assertEquals(ON_START, r.getLifecycleState());
+
+            clientSession.stopActivity(r);
+            assertEquals(ON_STOP, r.getLifecycleState());
+
+            clientSession.destroyActivity(r);
+            assertEquals(ON_DESTROY, r.getLifecycleState());
+        }
+    }
+
+    @Test
+    @UiThreadTest
+    public void testLifecycleAfterFinished_OnResume() throws Exception {
+        try (ClientMockSession clientSession = new ClientMockSession()) {
+            ActivityClientRecord r = clientSession.stubActivityRecord();
+
+            Activity activity = clientSession.launchActivity(r);
+            clientSession.startActivity(r);
+            clientSession.resumeActivity(r);
+            activity.finish();
+            assertEquals(ON_RESUME, r.getLifecycleState());
+
+            clientSession.pauseActivity(r);
+            assertEquals(ON_PAUSE, r.getLifecycleState());
+
+            clientSession.stopActivity(r);
+            assertEquals(ON_STOP, r.getLifecycleState());
+
+            clientSession.destroyActivity(r);
+            assertEquals(ON_DESTROY, r.getLifecycleState());
+        }
+    }
+
+    private class ClientMockSession implements AutoCloseable {
+        private MockitoSession mMockSession;
+        private ActivityThread mThread;
+
+        private ClientMockSession() throws RemoteException {
+            mThread = ActivityThread.currentActivityThread();
+            mMockSession = mockitoSession()
+                    .strictness(Strictness.LENIENT)
+                    .spyStatic(ActivityTaskManager.class)
+                    .spyStatic(WindowManagerGlobal.class)
+                    .startMocking();
+            doReturn(Mockito.mock(WindowManagerGlobal.class))
+                    .when(WindowManagerGlobal::getInstance);
+            IActivityTaskManager mockAtm = Mockito.mock(IActivityTaskManager.class);
+            doReturn(mockAtm).when(ActivityTaskManager::getService);
+            when(mockAtm.finishActivity(any(), anyInt(), any(), anyInt())).thenReturn(true);
+        }
+
+        private Activity launchActivity(ActivityClientRecord r) {
+            return mThread.handleLaunchActivity(r, null /* pendingActions */,
+                    null /* customIntent */);
+        }
+
+        private void startActivity(ActivityClientRecord r) {
+            mThread.handleStartActivity(r, null /* pendingActions */);
+        }
+
+        private void resumeActivity(ActivityClientRecord r) {
+            mThread.handleResumeActivity(r.token, true /* finalStateRequest */,
+                    true /* isForward */, "test");
+        }
+
+        private void pauseActivity(ActivityClientRecord r) {
+            mThread.handlePauseActivity(r.token, false /* finished */,
+                    false /* userLeaving */, 0 /* configChanges */, null /* pendingActions */,
+                    "test");
+        }
+
+        private void stopActivity(ActivityClientRecord r) {
+            mThread.handleStopActivity(r.token, false /* show */, 0 /* configChanges */,
+                    new PendingTransactionActions(), false /* finalStateRequest */, "test");
+        }
+
+        private void destroyActivity(ActivityClientRecord r) {
+            mThread.handleDestroyActivity(r.token, true /* finishing */, 0 /* configChanges */,
+                    false /* getNonConfigInstance */, "test");
+        }
+
+        private void changeVisibility(ActivityClientRecord r, boolean show) {
+            mThread.handleWindowVisibility(r.token, show);
+        }
+
+        private ActivityClientRecord stubActivityRecord() {
+            ComponentName component = new ComponentName(
+                    InstrumentationRegistry.getInstrumentation().getContext(), TestActivity.class);
+            ActivityInfo info = new ActivityInfo();
+            info.packageName = component.getPackageName();
+            info.name = component.getClassName();
+            info.exported = true;
+            info.applicationInfo = new ApplicationInfo();
+            info.applicationInfo.packageName = info.packageName;
+            info.applicationInfo.uid = UserHandle.myUserId();
+
+            return new ActivityClientRecord(new Binder(), Intent.makeMainActivity(component),
+                    0 /* ident */, info, new Configuration(),
+                    CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null /* referrer */,
+                    null /* voiceInteractor */, null /* state */, null /* persistentState */,
+                    null /* pendingResults */, null /* pendingNewIntents */, true /* isForward */,
+                    null /* profilerInfo */,  mThread /* client */);
+        }
+
+        @Override
+        public void close() {
+            mMockSession.finishMocking();
+        }
+    }
+
+    // Test activity
+    public static class TestActivity extends Activity {
+    }
+}
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index 0e957df..c54208b 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -180,6 +180,9 @@
     <assign-permission name="android.permission.STATSCOMPANION" uid="statsd" />
     <assign-permission name="android.permission.UPDATE_APP_OPS_STATS" uid="statsd" />
 
+    <split-permission name="android.permission.ACCESS_FINE_LOCATION">
+        <new-permission name="android.permission.ACCESS_COARSE_LOCATION" />
+    </split-permission>
     <split-permission name="android.permission.WRITE_EXTERNAL_STORAGE">
         <new-permission name="android.permission.READ_EXTERNAL_STORAGE" />
     </split-permission>
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 11e4cb8..2ad2e76 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -3510,6 +3510,7 @@
     ResStringPool                   keyStrings;
 
     size_t                          typeIdOffset;
+    bool                            definesOverlayable = false;
 };
 
 // A group of objects describing a particular resource package.
@@ -6861,6 +6862,10 @@
                 ALOGW("Found multiple library tables, ignoring...");
             }
         } else {
+            if (ctype == RES_TABLE_OVERLAYABLE_TYPE) {
+                package->definesOverlayable = true;
+            }
+
             status_t err = validate_chunk(chunk, sizeof(ResChunk_header),
                                           endPos, "ResTable_package:unknown");
             if (err != NO_ERROR) {
@@ -7138,6 +7143,11 @@
         return UNKNOWN_ERROR;
     }
 
+    // Idmap is not aware of overlayable, exit since policy checks can't be done
+    if (targetResTable.mPackageGroups[0]->packages[0]->definesOverlayable) {
+        return UNKNOWN_ERROR;
+    }
+
     const ResTable_package* targetPackageStruct =
         targetResTable.mPackageGroups[0]->packages[0]->package;
     const size_t tmpNameSize = arraysize(targetPackageStruct->name);
diff --git a/media/Android.bp b/media/Android.bp
index 5b7b26c..70dacb2 100644
--- a/media/Android.bp
+++ b/media/Android.bp
@@ -20,10 +20,6 @@
         ],
     },
 
-    static_libs: [
-        "mediaplayer2-protos",
-    ],
-
     permitted_packages: [
         "android.media",
     ],
@@ -43,7 +39,6 @@
     name: "updatable-media-srcs",
     srcs: [
         ":mediasession2-srcs",
-        ":mediaplayer2-srcs",
     ],
 }
 
@@ -51,7 +46,6 @@
     name: "updatable-media-srcs-without-aidls",
     srcs : [
         ":mediasession2-srcs-without-aidls",
-        ":mediaplayer2-srcs",
     ],
 }
 
@@ -109,8 +103,7 @@
     "--hide MissingPermission --hide BroadcastBehavior " +
     "--hide HiddenSuperclass --hide DeprecationMismatch --hide UnavailableSymbol " +
     "--hide SdkConstant --hide HiddenTypeParameter --hide Todo --hide Typo " +
-    "--hide HiddenTypedefConstant --show-annotation android.annotation.SystemApi " +
-    " --show-annotation android.annotation.TestApi "
+    "--hide HiddenTypedefConstant --show-annotation android.annotation.SystemApi "
 
 droidstubs {
     name: "updatable-media-stubs",
diff --git a/media/apex/java/android/media/BufferingParams.java b/media/apex/java/android/media/BufferingParams.java
index 83594d4..943f142 100644
--- a/media/apex/java/android/media/BufferingParams.java
+++ b/media/apex/java/android/media/BufferingParams.java
@@ -17,7 +17,6 @@
 package android.media;
 
 import android.annotation.IntDef;
-import android.annotation.TestApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
@@ -64,7 +63,6 @@
  * <p>Users should use {@link Builder} to change {@link BufferingParams}.
  * @hide
  */
-@TestApi
 public final class BufferingParams implements Parcelable {
     private static final int BUFFERING_NO_MARK = -1;
 
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index d347137..f8e43437 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -4523,6 +4523,7 @@
      */
 
     /** @hide */
+    @TestApi
     @SystemApi
     public static final int SUCCESS = AudioSystem.SUCCESS;
     /**
diff --git a/media/java/android/media/MiniThumbFile.java b/media/java/android/media/MiniThumbFile.java
deleted file mode 100644
index f704acd..0000000
--- a/media/java/android/media/MiniThumbFile.java
+++ /dev/null
@@ -1,334 +0,0 @@
-/*
- * Copyright (C) 2009 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.media;
-
-import android.annotation.UnsupportedAppUsage;
-import android.net.Uri;
-import android.os.Build;
-import android.os.Environment;
-import android.util.Log;
-
-import dalvik.system.VMRuntime;
-
-import java.io.File;
-import java.io.IOException;
-import java.io.RandomAccessFile;
-import java.nio.ByteBuffer;
-import java.nio.channels.FileChannel;
-import java.nio.channels.FileLock;
-import java.util.Hashtable;
-
-/**
- * This class handles the mini-thumb file. A mini-thumb file consists
- * of blocks, indexed by id. Each block has BYTES_PER_MINTHUMB bytes in the
- * following format:
- *
- * 1 byte status (0 = empty, 1 = mini-thumb available)
- * 8 bytes magic (a magic number to match what's in the database)
- * 4 bytes data length (LEN)
- * LEN bytes jpeg data
- * (the remaining bytes are unused)
- *
- * @hide This file is shared between MediaStore and MediaProvider and should remained internal use
- *       only.
- * @deprecated thumbnails are now maintained in separate files, and this file
- *             format is no longer used.
- */
-@Deprecated
-public class MiniThumbFile {
-    private static final String TAG = "MiniThumbFile";
-    private static final int MINI_THUMB_DATA_FILE_VERSION = 4;
-    public static final int BYTES_PER_MINTHUMB = 10000;
-    private static final int HEADER_SIZE = 1 + 8 + 4;
-    private Uri mUri;
-    private RandomAccessFile mMiniThumbFile;
-    private FileChannel mChannel;
-    private ByteBuffer mBuffer;
-    private ByteBuffer mEmptyBuffer;
-    private static final Hashtable<String, MiniThumbFile> sThumbFiles =
-        new Hashtable<String, MiniThumbFile>();
-
-    /**
-     * We store different types of thumbnails in different files. To remain backward compatibility,
-     * we should hashcode of content://media/external/images/media remains the same.
-     */
-    @UnsupportedAppUsage
-    public static synchronized void reset() {
-        for (MiniThumbFile file : sThumbFiles.values()) {
-            file.deactivate();
-        }
-        sThumbFiles.clear();
-    }
-
-    public static synchronized MiniThumbFile instance(Uri uri) {
-        if (VMRuntime.getRuntime().getTargetSdkVersion() >= Build.VERSION_CODES.Q) {
-            throw new UnsupportedOperationException();
-        }
-        String type = uri.getPathSegments().get(1);
-        MiniThumbFile file = sThumbFiles.get(type);
-        // Log.v(TAG, "get minithumbfile for type: "+type);
-        if (file == null) {
-            file = new MiniThumbFile(
-                    Uri.parse("content://media/external/" + type + "/media"));
-            sThumbFiles.put(type, file);
-        }
-
-        return file;
-    }
-
-    private String randomAccessFilePath(int version) {
-        String directoryName =
-                Environment.getExternalStorageDirectory().toString()
-                + "/DCIM/.thumbnails";
-        return directoryName + "/.thumbdata" + version + "-" + mUri.hashCode();
-    }
-
-    private void removeOldFile() {
-        String oldPath = randomAccessFilePath(MINI_THUMB_DATA_FILE_VERSION - 1);
-        File oldFile = new File(oldPath);
-        if (oldFile.exists()) {
-            try {
-                oldFile.delete();
-            } catch (SecurityException ex) {
-                // ignore
-            }
-        }
-    }
-
-    private RandomAccessFile miniThumbDataFile() {
-        if (mMiniThumbFile == null) {
-            removeOldFile();
-            String path = randomAccessFilePath(MINI_THUMB_DATA_FILE_VERSION);
-            File directory = new File(path).getParentFile();
-            if (!directory.isDirectory()) {
-                if (!directory.mkdirs()) {
-                    Log.e(TAG, "Unable to create .thumbnails directory "
-                            + directory.toString());
-                }
-            }
-            File f = new File(path);
-            try {
-                mMiniThumbFile = new RandomAccessFile(f, "rw");
-            } catch (IOException ex) {
-                // Open as read-only so we can at least read the existing
-                // thumbnails.
-                try {
-                    mMiniThumbFile = new RandomAccessFile(f, "r");
-                } catch (IOException ex2) {
-                    // ignore exception
-                }
-            }
-            if (mMiniThumbFile != null) {
-                mChannel = mMiniThumbFile.getChannel();
-            }
-        }
-        return mMiniThumbFile;
-    }
-
-    private MiniThumbFile(Uri uri) {
-        mUri = uri;
-        mBuffer = ByteBuffer.allocateDirect(BYTES_PER_MINTHUMB);
-        mEmptyBuffer = ByteBuffer.allocateDirect(BYTES_PER_MINTHUMB);
-    }
-
-    public synchronized void deactivate() {
-        if (mMiniThumbFile != null) {
-            try {
-                mMiniThumbFile.close();
-                mMiniThumbFile = null;
-            } catch (IOException ex) {
-                // ignore exception
-            }
-        }
-    }
-
-    // Get the magic number for the specified id in the mini-thumb file.
-    // Returns 0 if the magic is not available.
-    public synchronized long getMagic(long id) {
-        // check the mini thumb file for the right data.  Right is
-        // defined as having the right magic number at the offset
-        // reserved for this "id".
-        RandomAccessFile r = miniThumbDataFile();
-        if (r != null) {
-            long pos = id * BYTES_PER_MINTHUMB;
-            FileLock lock = null;
-            try {
-                mBuffer.clear();
-                mBuffer.limit(1 + 8);
-
-                lock = mChannel.lock(pos, 1 + 8, true);
-                // check that we can read the following 9 bytes
-                // (1 for the "status" and 8 for the long)
-                if (mChannel.read(mBuffer, pos) == 9) {
-                    mBuffer.position(0);
-                    if (mBuffer.get() == 1) {
-                        return mBuffer.getLong();
-                    }
-                }
-            } catch (IOException ex) {
-                Log.v(TAG, "Got exception checking file magic: ", ex);
-            } catch (RuntimeException ex) {
-                // Other NIO related exception like disk full, read only channel..etc
-                Log.e(TAG, "Got exception when reading magic, id = " + id +
-                        ", disk full or mount read-only? " + ex.getClass());
-            } finally {
-                try {
-                    if (lock != null) lock.release();
-                }
-                catch (IOException ex) {
-                    // ignore it.
-                }
-            }
-        }
-        return 0;
-    }
-
-    public synchronized void eraseMiniThumb(long id) {
-        RandomAccessFile r = miniThumbDataFile();
-        if (r != null) {
-            long pos = id * BYTES_PER_MINTHUMB;
-            FileLock lock = null;
-            try {
-                mBuffer.clear();
-                mBuffer.limit(1 + 8);
-
-                lock = mChannel.lock(pos, BYTES_PER_MINTHUMB, false);
-                // check that we can read the following 9 bytes
-                // (1 for the "status" and 8 for the long)
-                if (mChannel.read(mBuffer, pos) == 9) {
-                    mBuffer.position(0);
-                    if (mBuffer.get() == 1) {
-                        long currentMagic = mBuffer.getLong();
-                        if (currentMagic == 0) {
-                            // there is no thumbnail stored here
-                            Log.i(TAG, "no thumbnail for id " + id);
-                            return;
-                        }
-                        // zero out the thumbnail slot
-                        // Log.v(TAG, "clearing slot " + id + ", magic " + currentMagic
-                        //         + " at offset " + pos);
-                        mChannel.write(mEmptyBuffer, pos);
-                    }
-                } else {
-                    // Log.v(TAG, "No slot");
-                }
-            } catch (IOException ex) {
-                Log.v(TAG, "Got exception checking file magic: ", ex);
-            } catch (RuntimeException ex) {
-                // Other NIO related exception like disk full, read only channel..etc
-                Log.e(TAG, "Got exception when reading magic, id = " + id +
-                        ", disk full or mount read-only? " + ex.getClass());
-            } finally {
-                try {
-                    if (lock != null) lock.release();
-                }
-                catch (IOException ex) {
-                    // ignore it.
-                }
-            }
-        } else {
-            // Log.v(TAG, "No data file");
-        }
-    }
-
-    public synchronized void saveMiniThumbToFile(byte[] data, long id, long magic)
-            throws IOException {
-        RandomAccessFile r = miniThumbDataFile();
-        if (r == null) return;
-
-        long pos = id * BYTES_PER_MINTHUMB;
-        FileLock lock = null;
-        try {
-            if (data != null) {
-                if (data.length > BYTES_PER_MINTHUMB - HEADER_SIZE) {
-                    // not enough space to store it.
-                    return;
-                }
-                mBuffer.clear();
-                mBuffer.put((byte) 1);
-                mBuffer.putLong(magic);
-                mBuffer.putInt(data.length);
-                mBuffer.put(data);
-                mBuffer.flip();
-
-                lock = mChannel.lock(pos, BYTES_PER_MINTHUMB, false);
-                mChannel.write(mBuffer, pos);
-            }
-        } catch (IOException ex) {
-            Log.e(TAG, "couldn't save mini thumbnail data for "
-                    + id + "; ", ex);
-            throw ex;
-        } catch (RuntimeException ex) {
-            // Other NIO related exception like disk full, read only channel..etc
-            Log.e(TAG, "couldn't save mini thumbnail data for "
-                    + id + "; disk full or mount read-only? " + ex.getClass());
-        } finally {
-            try {
-                if (lock != null) lock.release();
-            }
-            catch (IOException ex) {
-                // ignore it.
-            }
-        }
-    }
-
-    /**
-     * Gallery app can use this method to retrieve mini-thumbnail. Full size
-     * images share the same IDs with their corresponding thumbnails.
-     *
-     * @param id the ID of the image (same of full size image).
-     * @param data the buffer to store mini-thumbnail.
-     */
-    public synchronized byte [] getMiniThumbFromFile(long id, byte [] data) {
-        RandomAccessFile r = miniThumbDataFile();
-        if (r == null) return null;
-
-        long pos = id * BYTES_PER_MINTHUMB;
-        FileLock lock = null;
-        try {
-            mBuffer.clear();
-            lock = mChannel.lock(pos, BYTES_PER_MINTHUMB, true);
-            int size = mChannel.read(mBuffer, pos);
-            if (size > 1 + 8 + 4) { // flag, magic, length
-                mBuffer.position(0);
-                byte flag = mBuffer.get();
-                long magic = mBuffer.getLong();
-                int length = mBuffer.getInt();
-
-                if (size >= 1 + 8 + 4 + length && length != 0 && magic != 0 && flag == 1 &&
-                        data.length >= length) {
-                    mBuffer.get(data, 0, length);
-                    return data;
-                }
-            }
-        } catch (IOException ex) {
-            Log.w(TAG, "got exception when reading thumbnail id=" + id + ", exception: " + ex);
-        } catch (RuntimeException ex) {
-            // Other NIO related exception like disk full, read only channel..etc
-            Log.e(TAG, "Got exception when reading thumbnail, id = " + id +
-                    ", disk full or mount read-only? " + ex.getClass());
-        } finally {
-            try {
-                if (lock != null) lock.release();
-            }
-            catch (IOException ex) {
-                // ignore it.
-            }
-        }
-        return null;
-    }
-}
diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java
index fefb0d7..e207721 100644
--- a/media/java/android/media/RingtoneManager.java
+++ b/media/java/android/media/RingtoneManager.java
@@ -495,15 +495,17 @@
         if (mCursor == null || !mCursor.moveToPosition(position)) {
             return null;
         }
-        
-        return getUriFromCursor(mCursor);
+
+        return getUriFromCursor(mContext, mCursor);
     }
 
-    private static Uri getUriFromCursor(Cursor cursor) {
-        return ContentUris.withAppendedId(Uri.parse(cursor.getString(URI_COLUMN_INDEX)), cursor
-                .getLong(ID_COLUMN_INDEX));
+    private static Uri getUriFromCursor(Context context, Cursor cursor) {
+        final Uri uri = ContentUris.withAppendedId(Uri.parse(cursor.getString(URI_COLUMN_INDEX)),
+                cursor.getLong(ID_COLUMN_INDEX));
+        final Uri canonicalized = context.getContentResolver().canonicalize(uri);
+        return (canonicalized != null) ? canonicalized : uri;
     }
-    
+
     /**
      * Gets the position of a {@link Uri} within this {@link RingtoneManager}.
      * 
@@ -569,7 +571,7 @@
             Uri uri = null;
             
             if (cursor.moveToFirst()) {
-                uri = getUriFromCursor(cursor);
+                uri = getUriFromCursor(context, cursor);
             }
             cursor.close();
             
diff --git a/media/java/android/media/audiopolicy/AudioPolicy.java b/media/java/android/media/audiopolicy/AudioPolicy.java
index 1cd60f7..39474e1 100644
--- a/media/java/android/media/audiopolicy/AudioPolicy.java
+++ b/media/java/android/media/audiopolicy/AudioPolicy.java
@@ -416,6 +416,7 @@
      * @param devices list of devices to which the audio stream of the application may be routed.
      * @return true if the change was successful, false otherwise.
      */
+    @TestApi
     @SystemApi
     public boolean setUidDeviceAffinity(int uid, @NonNull List<AudioDeviceInfo> devices) {
         if (devices == null) {
@@ -457,6 +458,7 @@
      * @param uid UID of the application affected.
      * @return true if the change was successful, false otherwise.
      */
+    @TestApi
     @SystemApi
     public boolean removeUidDeviceAffinity(int uid) {
         synchronized (mLock) {
diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java
index 6361fd8..4ac6d35 100755
--- a/media/java/android/mtp/MtpDatabase.java
+++ b/media/java/android/mtp/MtpDatabase.java
@@ -36,6 +36,7 @@
 import android.system.Os;
 import android.system.OsConstants;
 import android.util.Log;
+import android.util.SparseArray;
 import android.view.Display;
 import android.view.WindowManager;
 
@@ -69,8 +70,6 @@
 
     private final Context mContext;
     private final ContentProviderClient mMediaProvider;
-    private final String mVolumeName;
-    private final Uri mObjectsUri;
 
     private final AtomicBoolean mClosed = new AtomicBoolean();
     private final CloseGuard mCloseGuard = CloseGuard.get();
@@ -78,10 +77,10 @@
     private final HashMap<String, MtpStorage> mStorageMap = new HashMap<>();
 
     // cached property groups for single properties
-    private final HashMap<Integer, MtpPropertyGroup> mPropertyGroupsByProperty = new HashMap<>();
+    private final SparseArray<MtpPropertyGroup> mPropertyGroupsByProperty = new SparseArray<>();
 
     // cached property groups for all properties for a given format
-    private final HashMap<Integer, MtpPropertyGroup> mPropertyGroupsByFormat = new HashMap<>();
+    private final SparseArray<MtpPropertyGroup> mPropertyGroupsByFormat = new SparseArray<>();
 
     // SharedPreferences for writable MTP device properties
     private SharedPreferences mDeviceProperties;
@@ -271,14 +270,11 @@
         }
     };
 
-    public MtpDatabase(Context context, String volumeName,
-            String[] subDirectories) {
+    public MtpDatabase(Context context, String[] subDirectories) {
         native_setup();
         mContext = Objects.requireNonNull(context);
         mMediaProvider = context.getContentResolver()
                 .acquireContentProviderClient(MediaStore.AUTHORITY);
-        mVolumeName = volumeName;
-        mObjectsUri = Files.getMtpObjectsUri(volumeName);
         mManager = new MtpStorageManager(new MtpStorageManager.MtpNotifier() {
             @Override
             public void sendObjectAdded(int id) {
@@ -526,8 +522,7 @@
                 propertyGroup = mPropertyGroupsByFormat.get(format);
                 if (propertyGroup == null) {
                     final int[] propertyList = getSupportedObjectProperties(format);
-                    propertyGroup = new MtpPropertyGroup(mMediaProvider, mVolumeName,
-                            propertyList);
+                    propertyGroup = new MtpPropertyGroup(propertyList);
                     mPropertyGroupsByFormat.put(format, propertyGroup);
                 }
             } else {
@@ -535,12 +530,11 @@
                 propertyGroup = mPropertyGroupsByProperty.get(property);
                 if (propertyGroup == null) {
                     final int[] propertyList = new int[]{property};
-                    propertyGroup = new MtpPropertyGroup(mMediaProvider, mVolumeName,
-                            propertyList);
+                    propertyGroup = new MtpPropertyGroup(propertyList);
                     mPropertyGroupsByProperty.put(property, propertyGroup);
                 }
             }
-            int err = propertyGroup.getPropertyList(obj, ret);
+            int err = propertyGroup.getPropertyList(mMediaProvider, obj.getVolumeName(), obj, ret);
             if (err != MtpConstants.RESPONSE_OK) {
                 return new MtpPropertyList(err);
             }
@@ -581,7 +575,8 @@
         try {
             // note - we are relying on a special case in MediaProvider.update() to update
             // the paths for all children in the case where this is a directory.
-            mMediaProvider.update(mObjectsUri, values, PATH_WHERE, whereArgs);
+            final Uri objectsUri = MediaStore.Files.getMtpObjectsUri(obj.getVolumeName());
+            mMediaProvider.update(objectsUri, values, PATH_WHERE, whereArgs);
         } catch (RemoteException e) {
             Log.e(TAG, "RemoteException in mMediaProvider.update", e);
         }
@@ -640,12 +635,12 @@
         if (obj.getParent().isRoot()) {
             values.put(Files.FileColumns.PARENT, 0);
         } else {
-            int parentId = findInMedia(path.getParent());
+            int parentId = findInMedia(newParentObj, path.getParent());
             if (parentId != -1) {
                 values.put(Files.FileColumns.PARENT, parentId);
             } else {
                 // The new parent isn't in MediaProvider, so delete the object instead
-                deleteFromMedia(oldPath, obj.isDir());
+                deleteFromMedia(obj, oldPath, obj.isDir());
                 return;
             }
         }
@@ -655,13 +650,14 @@
         try {
             int parentId = -1;
             if (!oldParentObj.isRoot()) {
-                parentId = findInMedia(oldPath.getParent());
+                parentId = findInMedia(oldParentObj, oldPath.getParent());
             }
             if (oldParentObj.isRoot() || parentId != -1) {
                 // Old parent exists in MediaProvider - perform a move
                 // note - we are relying on a special case in MediaProvider.update() to update
                 // the paths for all children in the case where this is a directory.
-                mMediaProvider.update(mObjectsUri, values, PATH_WHERE, whereArgs);
+                final Uri objectsUri = MediaStore.Files.getMtpObjectsUri(obj.getVolumeName());
+                mMediaProvider.update(objectsUri, values, PATH_WHERE, whereArgs);
             } else {
                 // Old parent doesn't exist - add the object
                 MediaStore.scanFile(mContext, path.toFile());
@@ -823,14 +819,16 @@
         if (!mManager.endRemoveObject(obj, success))
             Log.e(TAG, "Failed to end remove object");
         if (success)
-            deleteFromMedia(obj.getPath(), obj.isDir());
+            deleteFromMedia(obj, obj.getPath(), obj.isDir());
     }
 
-    private int findInMedia(Path path) {
+    private int findInMedia(MtpStorageManager.MtpObject obj, Path path) {
+        final Uri objectsUri = MediaStore.Files.getMtpObjectsUri(obj.getVolumeName());
+
         int ret = -1;
         Cursor c = null;
         try {
-            c = mMediaProvider.query(mObjectsUri, ID_PROJECTION, PATH_WHERE,
+            c = mMediaProvider.query(objectsUri, ID_PROJECTION, PATH_WHERE,
                     new String[]{path.toString()}, null, null);
             if (c != null && c.moveToNext()) {
                 ret = c.getInt(0);
@@ -844,12 +842,13 @@
         return ret;
     }
 
-    private void deleteFromMedia(Path path, boolean isDir) {
+    private void deleteFromMedia(MtpStorageManager.MtpObject obj, Path path, boolean isDir) {
+        final Uri objectsUri = MediaStore.Files.getMtpObjectsUri(obj.getVolumeName());
         try {
             // Delete the object(s) from MediaProvider, but ignore errors.
             if (isDir) {
                 // recursive case - delete all children first
-                mMediaProvider.delete(mObjectsUri,
+                mMediaProvider.delete(objectsUri,
                         // the 'like' makes it use the index, the 'lower()' makes it correct
                         // when the path contains sqlite wildcard characters
                         "_data LIKE ?1 AND lower(substr(_data,1,?2))=lower(?3)",
@@ -858,7 +857,7 @@
             }
 
             String[] whereArgs = new String[]{path.toString()};
-            if (mMediaProvider.delete(mObjectsUri, PATH_WHERE, whereArgs) > 0) {
+            if (mMediaProvider.delete(objectsUri, PATH_WHERE, whereArgs) > 0) {
                 if (!isDir && path.toString().toLowerCase(Locale.US).endsWith(NO_MEDIA)) {
                     MediaStore.scanFile(mContext, path.getParent().toFile());
                 }
@@ -876,10 +875,10 @@
         if (obj == null)
             return null;
         // Translate this handle to the MediaProvider Handle
-        handle = findInMedia(obj.getPath());
+        handle = findInMedia(obj, obj.getPath());
         if (handle == -1)
             return null;
-        Uri uri = Files.getMtpReferencesUri(mVolumeName, handle);
+        Uri uri = Files.getMtpReferencesUri(obj.getVolumeName(), handle);
         Cursor c = null;
         try {
             c = mMediaProvider.query(uri, PATH_PROJECTION, null, null, null, null);
@@ -912,17 +911,17 @@
         if (obj == null)
             return MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE;
         // Translate this handle to the MediaProvider Handle
-        handle = findInMedia(obj.getPath());
+        handle = findInMedia(obj, obj.getPath());
         if (handle == -1)
             return MtpConstants.RESPONSE_GENERAL_ERROR;
-        Uri uri = Files.getMtpReferencesUri(mVolumeName, handle);
+        Uri uri = Files.getMtpReferencesUri(obj.getVolumeName(), handle);
         ArrayList<ContentValues> valuesList = new ArrayList<>();
         for (int id : references) {
             // Translate each reference id to the MediaProvider Id
             MtpStorageManager.MtpObject refObj = mManager.getObject(id);
             if (refObj == null)
                 continue;
-            int refHandle = findInMedia(refObj.getPath());
+            int refHandle = findInMedia(refObj, refObj.getPath());
             if (refHandle == -1)
                 continue;
             ContentValues values = new ContentValues();
diff --git a/media/java/android/mtp/MtpPropertyGroup.java b/media/java/android/mtp/MtpPropertyGroup.java
index 6d5be8e..5bb0c1b 100644
--- a/media/java/android/mtp/MtpPropertyGroup.java
+++ b/media/java/android/mtp/MtpPropertyGroup.java
@@ -46,9 +46,6 @@
         }
     }
 
-    private final ContentProviderClient mProvider;
-    private final String mVolumeName;
-
     // list of all properties in this group
     private final Property[] mProperties;
 
@@ -58,10 +55,7 @@
     private static final String PATH_WHERE = Files.FileColumns.DATA + "=?";
 
     // constructs a property group for a list of properties
-    public MtpPropertyGroup(ContentProviderClient provider, String volumeName, int[] properties) {
-        mProvider = provider;
-        mVolumeName = volumeName;
-
+    public MtpPropertyGroup(int[] properties) {
         int count = properties.length;
         ArrayList<String> columns = new ArrayList<>(count);
         columns.add(Files.FileColumns._ID);
@@ -175,7 +169,8 @@
      * object and adds them to the given property list.
      * @return Response_OK if the operation succeeded.
      */
-    public int getPropertyList(MtpStorageManager.MtpObject object, MtpPropertyList list) {
+    public int getPropertyList(ContentProviderClient provider, String volumeName,
+            MtpStorageManager.MtpObject object, MtpPropertyList list) {
         Cursor c = null;
         int id = object.getId();
         String path = object.getPath().toString();
@@ -184,8 +179,8 @@
                 try {
                     // Look up the entry in MediaProvider only if one of those properties is needed.
                     final Uri uri = MtpDatabase.getObjectPropertiesUri(object.getFormat(),
-                            mVolumeName);
-                    c = mProvider.query(uri, mColumns,
+                            volumeName);
+                    c = provider.query(uri, mColumns,
                             PATH_WHERE, new String[] {path}, null, null);
                     if (c != null && !c.moveToNext()) {
                         c.close();
diff --git a/media/java/android/mtp/MtpStorage.java b/media/java/android/mtp/MtpStorage.java
index c714b3c..65d0fef 100644
--- a/media/java/android/mtp/MtpStorage.java
+++ b/media/java/android/mtp/MtpStorage.java
@@ -18,6 +18,7 @@
 
 import android.annotation.UnsupportedAppUsage;
 import android.os.storage.StorageVolume;
+import android.provider.MediaStore;
 
 /**
  * This class represents a storage unit on an MTP device.
@@ -27,12 +28,12 @@
  * @hide
  */
 public class MtpStorage {
-
     private final int mStorageId;
     private final String mPath;
     private final String mDescription;
     private final boolean mRemovable;
     private final long mMaxFileSize;
+    private final String mVolumeName;
 
     public MtpStorage(StorageVolume volume, int storageId) {
         mStorageId = storageId;
@@ -40,6 +41,11 @@
         mDescription = volume.getDescription(null);
         mRemovable = volume.isRemovable();
         mMaxFileSize = volume.getMaxFileSize();
+        if (volume.isPrimary()) {
+            mVolumeName = MediaStore.VOLUME_EXTERNAL_PRIMARY;
+        } else {
+            mVolumeName = volume.getNormalizedUuid();
+        }
     }
 
     /**
@@ -88,4 +94,8 @@
     public long getMaxFileSize() {
         return mMaxFileSize;
     }
+
+    public String getVolumeName() {
+        return mVolumeName;
+    }
 }
diff --git a/media/java/android/mtp/MtpStorageManager.java b/media/java/android/mtp/MtpStorageManager.java
index f14e7d7..e783788 100644
--- a/media/java/android/mtp/MtpStorageManager.java
+++ b/media/java/android/mtp/MtpStorageManager.java
@@ -21,6 +21,8 @@
 import android.os.storage.StorageVolume;
 import android.util.Log;
 
+import com.android.internal.util.Preconditions;
+
 import java.io.IOException;
 import java.nio.file.DirectoryIteratorException;
 import java.nio.file.DirectoryStream;
@@ -131,6 +133,7 @@
 
     /** MtpObject represents either a file or directory in an associated storage. **/
     public static class MtpObject {
+        private MtpStorage mStorage;
         // null for root objects
         private MtpObject mParent;
 
@@ -147,9 +150,10 @@
         // null if not both a directory and visited
         private FileObserver mObserver;
 
-        MtpObject(String name, int id, MtpObject parent, boolean isDir) {
+        MtpObject(String name, int id, MtpStorage storage, MtpObject parent, boolean isDir) {
             mId = id;
             mName = name;
+            mStorage = Preconditions.checkNotNull(storage);
             mParent = parent;
             mObserver = null;
             mVisited = false;
@@ -206,6 +210,10 @@
             return mParent == null;
         }
 
+        public String getVolumeName() {
+            return mStorage.getVolumeName();
+        }
+
         /** For MtpStorageManager only **/
 
         private void setName(String name) {
@@ -278,7 +286,7 @@
         }
 
         private MtpObject copy(boolean recursive) {
-            MtpObject copy = new MtpObject(mName, mId, mParent, mIsDir);
+            MtpObject copy = new MtpObject(mName, mId, mStorage, mParent, mIsDir);
             copy.mIsDir = mIsDir;
             copy.mVisited = mVisited;
             copy.mState = mState;
@@ -408,7 +416,7 @@
     public synchronized MtpStorage addMtpStorage(StorageVolume volume) {
         int storageId = ((getNextStorageId() & 0x0000FFFF) << 16) + 1;
         MtpStorage storage = new MtpStorage(volume, storageId);
-        MtpObject root = new MtpObject(storage.getPath(), storageId, null, true);
+        MtpObject root = new MtpObject(storage.getPath(), storageId, storage, null, true);
         mRoots.put(storageId, root);
         return storage;
     }
@@ -608,7 +616,7 @@
             return null;
         }
 
-        MtpObject obj = new MtpObject(newName, getNextObjectId(), parent, isDir);
+        MtpObject obj = new MtpObject(newName, getNextObjectId(), parent.mStorage, parent, isDir);
         mObjects.put(obj.getId(), obj);
         parent.addChild(obj);
         return obj;
diff --git a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java
index 55c9361..81c5bcd 100644
--- a/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java
+++ b/packages/CarrierDefaultApp/src/com/android/carrierdefaultapp/CaptivePortalLoginActivity.java
@@ -52,6 +52,7 @@
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.telephony.TelephonyIntents;
 import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.TrafficStatsConstants;
 
 import java.io.IOException;
 import java.lang.reflect.Field;
@@ -238,7 +239,8 @@
                 if (isFinishing() || isDestroyed()) return;
                 HttpURLConnection urlConnection = null;
                 int httpResponseCode = 500;
-                int oldTag = TrafficStats.getAndSetThreadStatsTag(TrafficStats.TAG_SYSTEM_PROBE);
+                int oldTag = TrafficStats.getAndSetThreadStatsTag(
+                        TrafficStatsConstants.TAG_SYSTEM_PROBE);
                 try {
                     urlConnection = (HttpURLConnection) mNetwork.openConnection(
                             new URL(mCm.getCaptivePortalServerUrl()));
diff --git a/packages/ExtServices/src/android/ext/services/notification/Assistant.java b/packages/ExtServices/src/android/ext/services/notification/Assistant.java
index b2baff5..7860f36 100644
--- a/packages/ExtServices/src/android/ext/services/notification/Assistant.java
+++ b/packages/ExtServices/src/android/ext/services/notification/Assistant.java
@@ -238,7 +238,7 @@
         }
         mSingleThreadExecutor.submit(() -> {
             NotificationEntry entry =
-                    new NotificationEntry(mPackageManager, sbn, channel, mSmsHelper);
+                    new NotificationEntry(mPackageManager, sbn.cloneLight(), channel, mSmsHelper);
             SmartActionsHelper.SmartSuggestions suggestions = mSmartActionsHelper.suggest(entry);
             if (DEBUG) {
                 Log.d(TAG, String.format(
@@ -296,7 +296,7 @@
             Ranking ranking = getRanking(sbn.getKey(), rankingMap);
             if (ranking != null && ranking.getChannel() != null) {
                 NotificationEntry entry = new NotificationEntry(mPackageManager,
-                        sbn, ranking.getChannel(), mSmsHelper);
+                        sbn.cloneLight(), ranking.getChannel(), mSmsHelper);
                 String key = getKey(
                         sbn.getPackageName(), sbn.getUserId(), ranking.getChannel().getId());
                 ChannelImpressions ci = mkeyToImpressions.getOrDefault(key,
diff --git a/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java b/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java
index 0d687d4..10360a3 100644
--- a/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java
+++ b/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java
@@ -338,7 +338,7 @@
                 createTextClassifierEventBuilder(
                         TextClassifierEvent.TYPE_SMART_ACTION, session.resultId)
                         .setEntityTypes(ConversationAction.TYPE_TEXT_REPLY)
-                        .setScore(session.repliesScores.getOrDefault(reply, 0f))
+                        .setScores(session.repliesScores.getOrDefault(reply, 0f))
                         .build();
         mTextClassifier.onTextClassifierEvent(textClassifierEvent);
     }
@@ -381,11 +381,9 @@
                 .build();
     }
 
-    private TextClassifierEvent.Builder createTextClassifierEventBuilder(
+    private TextClassifierEvent.ConversationActionsEvent.Builder createTextClassifierEventBuilder(
             int eventType, String resultId) {
-        return new TextClassifierEvent.Builder(
-                TextClassifierEvent.CATEGORY_CONVERSATION_ACTIONS, eventType)
-                .setEventTime(System.currentTimeMillis())
+        return new TextClassifierEvent.ConversationActionsEvent.Builder(eventType)
                 .setEventContext(
                         new TextClassificationContext.Builder(
                                 mContext.getPackageName(), TextClassifier.WIDGET_TYPE_NOTIFICATION)
diff --git a/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionsHelperTest.java b/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionsHelperTest.java
index ebcaee8..dfa1ea0 100644
--- a/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionsHelperTest.java
+++ b/packages/ExtServices/tests/src/android/ext/services/notification/SmartActionsHelperTest.java
@@ -330,7 +330,9 @@
         List<TextClassifierEvent> events = argumentCaptor.getAllValues();
         assertTextClassifierEvent(events.get(0), TextClassifierEvent.TYPE_ACTIONS_GENERATED);
         assertTextClassifierEvent(events.get(1), TextClassifierEvent.TYPE_SMART_ACTION);
-        assertThat(events.get(1).getScore()).isEqualTo(SCORE);
+        float[] scores = events.get(1).getScores();
+        assertThat(scores).hasLength(1);
+        assertThat(scores[0]).isEqualTo(SCORE);
     }
 
     @Test
diff --git a/packages/NetworkStack/src/android/net/dhcp/DhcpClient.java b/packages/NetworkStack/src/android/net/dhcp/DhcpClient.java
index 64adc0d..af0e3bb 100644
--- a/packages/NetworkStack/src/android/net/dhcp/DhcpClient.java
+++ b/packages/NetworkStack/src/android/net/dhcp/DhcpClient.java
@@ -65,6 +65,7 @@
 import com.android.internal.util.MessageUtils;
 import com.android.internal.util.State;
 import com.android.internal.util.StateMachine;
+import com.android.internal.util.TrafficStatsConstants;
 import com.android.internal.util.WakeupMessage;
 
 import java.io.FileDescriptor;
@@ -329,7 +330,8 @@
     }
 
     private boolean initUdpSocket() {
-        final int oldTag = TrafficStats.getAndSetThreadStatsTag(TrafficStats.TAG_SYSTEM_DHCP);
+        final int oldTag = TrafficStats.getAndSetThreadStatsTag(
+                TrafficStatsConstants.TAG_SYSTEM_DHCP);
         try {
             mUdpSock = Os.socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
             SocketUtils.bindSocketToInterface(mUdpSock, mIfaceName);
diff --git a/packages/NetworkStack/src/android/net/dhcp/DhcpServer.java b/packages/NetworkStack/src/android/net/dhcp/DhcpServer.java
index 8832eaa..d21b5f7 100644
--- a/packages/NetworkStack/src/android/net/dhcp/DhcpServer.java
+++ b/packages/NetworkStack/src/android/net/dhcp/DhcpServer.java
@@ -16,7 +16,6 @@
 
 package android.net.dhcp;
 
-import static android.net.TrafficStats.TAG_SYSTEM_DHCP_SERVER;
 import static android.net.dhcp.DhcpPacket.DHCP_CLIENT;
 import static android.net.dhcp.DhcpPacket.DHCP_HOST_NAME;
 import static android.net.dhcp.DhcpPacket.DHCP_SERVER;
@@ -33,6 +32,7 @@
 import static android.system.OsConstants.SO_BROADCAST;
 import static android.system.OsConstants.SO_REUSEADDR;
 
+import static com.android.internal.util.TrafficStatsConstants.TAG_SYSTEM_DHCP_SERVER;
 import static com.android.server.util.NetworkStackConstants.INFINITE_LEASE;
 import static com.android.server.util.NetworkStackConstants.IPV4_ADDR_ALL;
 import static com.android.server.util.NetworkStackConstants.IPV4_ADDR_ANY;
diff --git a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
index 2a61250..27d4203 100644
--- a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
+++ b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
@@ -98,6 +98,7 @@
 import com.android.internal.util.RingBufferIndices;
 import com.android.internal.util.State;
 import com.android.internal.util.StateMachine;
+import com.android.internal.util.TrafficStatsConstants;
 import com.android.networkstack.R;
 import com.android.networkstack.metrics.DataStallDetectionStats;
 import com.android.networkstack.metrics.DataStallStatsUtils;
@@ -1478,7 +1479,8 @@
         int httpResponseCode = CaptivePortalProbeResult.FAILED_CODE;
         String redirectUrl = null;
         final Stopwatch probeTimer = new Stopwatch().start();
-        final int oldTag = TrafficStats.getAndSetThreadStatsTag(TrafficStats.TAG_SYSTEM_PROBE);
+        final int oldTag = TrafficStats.getAndSetThreadStatsTag(
+                TrafficStatsConstants.TAG_SYSTEM_PROBE);
         try {
             urlConnection = (HttpURLConnection) mNetwork.openConnection(url);
             urlConnection.setInstanceFollowRedirects(probeType == ValidationProbeEvent.PROBE_PAC);
diff --git a/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java b/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java
index 87b5b57..4f4aef0 100644
--- a/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java
+++ b/packages/SettingsLib/RestrictedLockUtils/src/com/android/settingslib/RestrictedLockUtils.java
@@ -76,11 +76,13 @@
     public static void sendShowAdminSupportDetailsIntent(Context context, EnforcedAdmin admin) {
         final Intent intent = getShowAdminSupportDetailsIntent(context, admin);
         int targetUserId = UserHandle.myUserId();
-        if (admin != null && admin.user != null
-                && isCurrentUserOrProfile(context, admin.user.getIdentifier())) {
-            targetUserId = admin.user.getIdentifier();
+        if (admin != null) {
+            if (admin.user != null
+                    && isCurrentUserOrProfile(context, admin.user.getIdentifier())) {
+                targetUserId = admin.user.getIdentifier();
+            }
+            intent.putExtra(DevicePolicyManager.EXTRA_RESTRICTION, admin.enforcedRestriction);
         }
-        intent.putExtra(DevicePolicyManager.EXTRA_RESTRICTION, admin.enforcedRestriction);
         context.startActivityAsUser(intent, UserHandle.of(targetUserId));
     }
 
diff --git a/packages/SettingsLib/res/layout/settings_dialog_title.xml b/packages/SettingsLib/res/layout/settings_dialog_title.xml
new file mode 100644
index 0000000..1e065e0
--- /dev/null
+++ b/packages/SettingsLib/res/layout/settings_dialog_title.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:id="@+id/settings_title_panel"
+              android:layout_width="match_parent"
+              android:layout_height="wrap_content"
+              android:orientation="vertical">
+
+    <LinearLayout
+        android:id="@+id/settings_title_template"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        android:gravity="center"
+        android:paddingStart="?android:attr/dialogPreferredPadding"
+        android:paddingEnd="?android:attr/dialogPreferredPadding"
+        android:paddingTop="@*android:dimen/dialog_padding_top_material">
+
+        <ImageView
+            android:id="@+id/settings_icon"
+            android:layout_width="24dip"
+            android:layout_height="24dip"
+            android:layout_marginBottom="12dip" />
+
+        <TextView
+            android:id="@+id/settings_title"
+            android:singleLine="true"
+            android:ellipsize="end"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:textAlignment="center"
+            style="?android:attr/windowTitleStyle" />
+    </LinearLayout>
+
+    <Space
+        android:id="@+id/settings_title_divider"
+        android:visibility="gone"
+        android:layout_width="match_parent"
+        android:layout_height="@*android:dimen/dialog_title_divider_material" />
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SettingsLib/src/com/android/settingslib/graph/ThemedBatteryDrawable.kt b/packages/SettingsLib/src/com/android/settingslib/graph/ThemedBatteryDrawable.kt
index eff02d2..257943e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/graph/ThemedBatteryDrawable.kt
+++ b/packages/SettingsLib/src/com/android/settingslib/graph/ThemedBatteryDrawable.kt
@@ -83,6 +83,8 @@
     // Dual tone implies that battery level is a clipped overlay over top of the whole shape
     private var dualTone = false
 
+    private var batteryLevel = 0
+
     private val invalidateRunnable: () -> Unit = {
         invalidateSelf()
     }
@@ -177,9 +179,9 @@
         unifiedPath.reset()
         levelPath.reset()
         levelRect.set(fillRect)
-        val fillFraction = level / 100f
+        val fillFraction = batteryLevel / 100f
         val fillTop =
-                if (level >= 95)
+                if (batteryLevel >= 95)
                     fillRect.top
                 else
                     fillRect.top + (fillRect.height() * (1 - fillFraction))
@@ -223,7 +225,7 @@
             fillPaint.color = levelColor
 
             // Show colorError below this level
-            if (level <= Companion.CRITICAL_LEVEL && !charging) {
+            if (batteryLevel <= Companion.CRITICAL_LEVEL && !charging) {
                 c.save()
                 c.clipPath(scaledFill)
                 c.drawPath(levelPath, fillPaint)
@@ -310,13 +312,13 @@
      */
     public open fun setBatteryLevel(l: Int) {
         invertFillIcon = if (l >= 67) true else if (l <= 33) false else invertFillIcon
-        level = l
-        levelColor = batteryColorForLevel(level)
+        batteryLevel = l
+        levelColor = batteryColorForLevel(batteryLevel)
         invalidateSelf()
     }
 
     public fun getBatteryLevel(): Int {
-        return level
+        return batteryLevel
     }
 
     override fun onBoundsChange(bounds: Rect?) {
@@ -343,7 +345,7 @@
         dualToneBackgroundFill.color = bgColor
 
         // Also update the level color, since fillColor may have changed
-        levelColor = batteryColorForLevel(level)
+        levelColor = batteryColorForLevel(batteryLevel)
 
         invalidateSelf()
     }
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index 1976ec4..d1e4fdf 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -337,6 +337,7 @@
         mContext = context;
         networkId = config.networkId;
         mConfig = config;
+        mFqdn = config.FQDN;
         setScanResultsPasspoint(homeScans, roamingScans);
         updateKey();
     }
@@ -673,6 +674,13 @@
         return mKey;
     }
 
+    /**
+     * Determines if the other AccessPoint represents the same network as this AccessPoint
+     */
+    public boolean matches(AccessPoint other) {
+        return getKey().equals(other.getKey());
+    }
+
     public boolean matches(WifiConfiguration config) {
         if (config.isPasspoint()) {
             return (isPasspoint() && config.FQDN.equals(mConfig.FQDN));
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java
index 2b5a4e0..11c799e 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/RestrictedLockUtilsTest.java
@@ -16,6 +16,7 @@
 
 package com.android.settingslib;
 
+import static android.app.admin.DevicePolicyManager.EXTRA_RESTRICTION;
 import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FEATURES_NONE;
 import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_FINGERPRINT;
 import static android.app.admin.DevicePolicyManager.KEYGUARD_DISABLE_REMOTE_INPUT;
@@ -28,11 +29,13 @@
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.app.admin.DevicePolicyManager;
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.pm.UserInfo;
 import android.os.UserHandle;
@@ -42,6 +45,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Answers;
+import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
@@ -283,6 +287,26 @@
         assertThat(profile).isNull();
     }
 
+    @Test
+    public void sendShowAdminSupportDetailsIntent_extraRestrictionProvided() {
+        EnforcedAdmin enforcedAdmin = new EnforcedAdmin();
+        enforcedAdmin.enforcedRestriction = "Dummy";
+        RestrictedLockUtils.sendShowAdminSupportDetailsIntent(mContext, enforcedAdmin);
+
+        ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+        verify(mContext).startActivityAsUser(intentCaptor.capture(), any());
+        assertThat(intentCaptor.getValue().getExtra(EXTRA_RESTRICTION)).isEqualTo("Dummy");
+    }
+
+    @Test
+    public void sendShowAdminSupportDetailsIntent_noExtraRestriction() {
+        RestrictedLockUtils.sendShowAdminSupportDetailsIntent(mContext, null);
+
+        ArgumentCaptor<Intent> intentCaptor = ArgumentCaptor.forClass(Intent.class);
+        verify(mContext).startActivityAsUser(intentCaptor.capture(), any());
+        assertThat(intentCaptor.getValue().getExtra(EXTRA_RESTRICTION)).isNull();
+    }
+
     private UserInfo setUpUser(int userId, ComponentName[] admins) {
         UserInfo userInfo = new UserInfo(userId, "primary", 0);
         when(mUserManager.getUserInfo(userId)).thenReturn(userInfo);
diff --git a/packages/SystemUI/res-keyguard/drawable-xxxhdpi/stretch_thumbnail.png b/packages/SystemUI/res-keyguard/drawable-xxxhdpi/analog_thumbnail.png
similarity index 100%
rename from packages/SystemUI/res-keyguard/drawable-xxxhdpi/stretch_thumbnail.png
rename to packages/SystemUI/res-keyguard/drawable-xxxhdpi/analog_thumbnail.png
Binary files differ
diff --git a/packages/SystemUI/res-keyguard/drawable-xxxhdpi/type_thumbnail.png b/packages/SystemUI/res-keyguard/drawable-xxxhdpi/type_thumbnail.png
deleted file mode 100644
index 2bfd655..0000000
--- a/packages/SystemUI/res-keyguard/drawable-xxxhdpi/type_thumbnail.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res-keyguard/drawable/analog_frame.xml b/packages/SystemUI/res-keyguard/drawable/analog_frame.xml
new file mode 100644
index 0000000..a663ac8
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable/analog_frame.xml
@@ -0,0 +1,7 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="250dp"
+    android:width="250dp"
+    android:viewportHeight="380"
+    android:viewportWidth="380">
+    <path android:fillColor="#000000" android:pathData="M190,190m0,2a2,2 0,1 1,0 -4a2,2 0,1 1,0 4"/>
+</vector>
diff --git a/packages/SystemUI/res-keyguard/drawable/analog_hour_hand.xml b/packages/SystemUI/res-keyguard/drawable/analog_hour_hand.xml
new file mode 100644
index 0000000..c7b6d60
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable/analog_hour_hand.xml
@@ -0,0 +1,7 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="250dp"
+    android:width="250dp"
+    android:viewportHeight="380"
+    android:viewportWidth="380">
+    <path android:fillColor="#777777" android:fillType="evenOdd" android:pathData="M203,190C203,185.398 200.608,181.354 197,179.044L197,58C197,54.134 193.866,51 190,51C186.134,51 183,54.134 183,58L183,179.043C179.392,181.354 177,185.397 177,190C177,197.18 182.82,203 190,203C197.18,203 203,197.18 203,190Z"/>
+</vector>
diff --git a/packages/SystemUI/res-keyguard/drawable/analog_minute_hand.xml b/packages/SystemUI/res-keyguard/drawable/analog_minute_hand.xml
new file mode 100644
index 0000000..458275b
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/drawable/analog_minute_hand.xml
@@ -0,0 +1,7 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="250dp"
+    android:width="250dp"
+    android:viewportHeight="380"
+    android:viewportWidth="380">
+    <path android:fillColor="#FFFFFF" android:pathData="M192,182.252C195.45,183.14 198,186.272 198,190C198,194.418 194.418,198 190,198C185.582,198 182,194.418 182,190C182,186.272 184.55,183.14 188,182.252L188,10C188,8.895 188.895,8 190,8C191.105,8 192,8.895 192,10L192,182.252Z"/>
+</vector>
diff --git a/packages/SystemUI/res-keyguard/layout/stretchanalog_clock.xml b/packages/SystemUI/res-keyguard/layout/analog_clock.xml
similarity index 67%
rename from packages/SystemUI/res-keyguard/layout/stretchanalog_clock.xml
rename to packages/SystemUI/res-keyguard/layout/analog_clock.xml
index dd25df8..cf6d35ee2 100644
--- a/packages/SystemUI/res-keyguard/layout/stretchanalog_clock.xml
+++ b/packages/SystemUI/res-keyguard/layout/analog_clock.xml
@@ -35,9 +35,27 @@
       android:format24Hour="@string/keyguard_widget_24_hours_format"
       android:elegantTextHeight="false"
   />
-  <com.android.keyguard.clock.StretchAnalogClock
+  <com.android.keyguard.clock.ImageClock
       android:id="@+id/analog_clock"
-      android:layout_width="match_parent"
-      android:layout_height="match_parent"
-  />
+      android:layout_width="wrap_content"
+      android:layout_height="wrap_content"
+  >
+    <ImageView
+        android:id="@+id/hour_hand"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:src="@drawable/analog_hour_hand"
+    />
+    <ImageView
+        android:id="@+id/minute_hand"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:src="@drawable/analog_minute_hand"
+    />
+    <ImageView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:src="@drawable/analog_frame"
+    />
+  </com.android.keyguard.clock.ImageClock>
 </com.android.keyguard.clock.ClockLayout>
diff --git a/packages/SystemUI/res-keyguard/values/strings.xml b/packages/SystemUI/res-keyguard/values/strings.xml
index 4738887..1e98189 100644
--- a/packages/SystemUI/res-keyguard/values/strings.xml
+++ b/packages/SystemUI/res-keyguard/values/strings.xml
@@ -413,9 +413,6 @@
     <string name="clock_title_bubble" translatable="false">Bubble</string>
     <!-- Title for Stretch clock face that will appear in the picker app next to a preview image of
          the clock face. [CHAR LIMIT=8] -->
-    <string name="clock_title_stretch" translatable="false">Stretch</string>
-    <!-- Title for Typographic clock face that will appear in the picker app next to a preview image of
-         the clock face. [CHAR LIMIT=8] -->
-    <string name="clock_title_type" translatable="false">Type</string>
+    <string name="clock_title_analog" translatable="false">Analog</string>
 
 </resources>
diff --git a/packages/SystemUI/res/layout/global_actions_grid_item.xml b/packages/SystemUI/res/layout/global_actions_grid_item.xml
index e92ec0f..3cefce0 100644
--- a/packages/SystemUI/res/layout/global_actions_grid_item.xml
+++ b/packages/SystemUI/res/layout/global_actions_grid_item.xml
@@ -20,44 +20,50 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="@dimen/global_actions_grid_item_width"
     android:layout_height="@dimen/global_actions_grid_item_height"
-    android:gravity="top|center_horizontal"
-    android:orientation="vertical"
+    android:gravity="center"
     android:layout_marginTop="@dimen/global_actions_grid_item_vertical_margin"
     android:layout_marginBottom="@dimen/global_actions_grid_item_vertical_margin"
     android:layout_marginLeft="@dimen/global_actions_grid_item_side_margin"
     android:layout_marginRight="@dimen/global_actions_grid_item_side_margin"
 >
-    <ImageView
-        android:id="@*android:id/icon"
-        android:layout_width="@dimen/global_actions_grid_item_icon_width"
-        android:layout_height="@dimen/global_actions_grid_item_icon_height"
-        android:layout_marginTop="@dimen/global_actions_grid_item_icon_top_margin"
-        android:layout_marginBottom="@dimen/global_actions_grid_item_icon_bottom_margin"
-        android:layout_marginLeft="@dimen/global_actions_grid_item_icon_side_margin"
-        android:layout_marginRight="@dimen/global_actions_grid_item_icon_side_margin"
-        android:scaleType="centerInside"
-        android:alpha="?android:attr/primaryContentAlpha"
-    />
+    <LinearLayout
+        android:layout_width="@dimen/global_actions_grid_item_width"
+        android:layout_height="@dimen/global_actions_grid_item_height"
+        android:gravity="top|center_horizontal"
+        android:orientation="vertical"
+    >
+        <ImageView
+            android:id="@*android:id/icon"
+            android:layout_width="@dimen/global_actions_grid_item_icon_width"
+            android:layout_height="@dimen/global_actions_grid_item_icon_height"
+            android:layout_marginTop="@dimen/global_actions_grid_item_icon_top_margin"
+            android:layout_marginBottom="@dimen/global_actions_grid_item_icon_bottom_margin"
+            android:layout_marginLeft="@dimen/global_actions_grid_item_icon_side_margin"
+            android:layout_marginRight="@dimen/global_actions_grid_item_icon_side_margin"
+            android:scaleType="centerInside"
+            android:alpha="?android:attr/primaryContentAlpha"
+        />
 
-    <TextView
-        android:id="@*android:id/message"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:ellipsize="marquee"
-        android:marqueeRepeatLimit="marquee_forever"
-        android:singleLine="true"
-        android:gravity="center"
-        android:textSize="12dp"
-        android:textAppearance="?android:attr/textAppearanceSmall"
-    />
+        <TextView
+            android:id="@*android:id/message"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:ellipsize="marquee"
+            android:marqueeRepeatLimit="marquee_forever"
+            android:singleLine="true"
+            android:gravity="center"
+            android:textSize="12dp"
+            android:textAppearance="?android:attr/textAppearanceSmall"
+        />
 
-    <TextView
-        android:visibility="gone"
-        android:id="@*android:id/status"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:gravity="center"
-        android:textColor="?android:attr/textColorTertiary"
-        android:textAppearance="?android:attr/textAppearanceSmall"
-    />
+        <TextView
+            android:visibility="gone"
+            android:id="@*android:id/status"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="center"
+            android:textColor="?android:attr/textColorTertiary"
+            android:textAppearance="?android:attr/textAppearanceSmall"
+        />
+    </LinearLayout>
 </LinearLayout>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 444cabfc..f121c8e 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1331,6 +1331,14 @@
     <!-- Content description for accessibility: Clear the odi caption tool tip. [CHAR LIMIT=NONE] -->
     <string name="accessibility_volume_close_odi_captions_tip">Close captions tip</string>
 
+    <!-- Content description for accessibility: Captions button. [CHAR LIMIT=NONE] -->
+    <string name="volume_odi_captions_content_description">Captions overlay</string>
+
+    <!-- Content description for accessibility: Hint if click will enable. [CHAR LIMIT=NONE] -->
+    <string name="volume_odi_captions_hint_enable">enable</string>
+    <!-- Content description for accessibility: Hint if click will disable. [CHAR LIMIT=NONE] -->
+    <string name="volume_odi_captions_hint_disable">disable</string>
+
     <!-- content description for audio output chooser [CHAR LIMIT=NONE]-->
     <string name="accessibility_output_chooser">Switch output device</string>
 
diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
index 64517ba..eca3926 100644
--- a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
+++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
@@ -16,14 +16,22 @@
 
 package com.android.keyguard;
 
+import static android.telephony.PhoneStateListener.LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE;
+import static android.telephony.PhoneStateListener.LISTEN_NONE;
+
+import static com.android.internal.telephony.PhoneConstants.MAX_PHONE_COUNT_DUAL_SIM;
+
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.net.ConnectivityManager;
 import android.net.wifi.WifiManager;
 import android.os.Handler;
+import android.telephony.CarrierConfigManager;
+import android.telephony.PhoneStateListener;
 import android.telephony.ServiceState;
 import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.Log;
@@ -36,6 +44,7 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
 
@@ -113,6 +122,17 @@
         }
     };
 
+    private int mActiveMobileDataSubscription = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+    private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
+        @Override
+        public void onActiveDataSubscriptionIdChanged(int subId) {
+            mActiveMobileDataSubscription = subId;
+            if (mKeyguardUpdateMonitor != null) {
+                updateCarrierText();
+            }
+        }
+    };
+
     /**
      * The status of this lock screen. Primarily used for widgets on LockScreen.
      */
@@ -200,6 +220,8 @@
      * @param callback Callback to provide text updates
      */
     public void setListening(CarrierTextCallback callback) {
+        TelephonyManager telephonyManager = ((TelephonyManager) mContext
+                .getSystemService(Context.TELEPHONY_SERVICE));
         if (callback != null) {
             mCarrierTextCallback = callback;
             if (ConnectivityManager.from(mContext).isNetworkSupported(
@@ -207,6 +229,8 @@
                 mKeyguardUpdateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
                 mKeyguardUpdateMonitor.registerCallback(mCallback);
                 mWakefulnessLifecycle.addObserver(mWakefulnessObserver);
+                telephonyManager.listen(mPhoneStateListener,
+                        LISTEN_ACTIVE_DATA_SUBSCRIPTION_ID_CHANGE);
             } else {
                 // Don't listen and clear out the text when the device isn't a phone.
                 mKeyguardUpdateMonitor = null;
@@ -218,6 +242,35 @@
                 mKeyguardUpdateMonitor.removeCallback(mCallback);
                 mWakefulnessLifecycle.removeObserver(mWakefulnessObserver);
             }
+            telephonyManager.listen(mPhoneStateListener, LISTEN_NONE);
+        }
+    }
+
+    /**
+     * STOPSHIP(b/130246708) remove when no longer needed for testing purpose.
+     * @param subscriptions
+     */
+    private void filterMobileSubscriptionInSameGroup(List<SubscriptionInfo> subscriptions) {
+        if (subscriptions.size() == MAX_PHONE_COUNT_DUAL_SIM) {
+            SubscriptionInfo info1 = subscriptions.get(0);
+            SubscriptionInfo info2 = subscriptions.get(1);
+            if (info1.getGroupUuid() != null && info1.getGroupUuid().equals(info2.getGroupUuid())) {
+                // If both subscriptions are primary, show both.
+                if (!info1.isOpportunistic() && !info2.isOpportunistic()) return;
+
+                // If carrier required, always show signal bar of primary subscription.
+                // Otherwise, show whichever subscription is currently active for Internet.
+                boolean alwaysShowPrimary = CarrierConfigManager.getDefaultConfig()
+                        .getBoolean(CarrierConfigManager
+                        .KEY_ALWAYS_SHOW_PRIMARY_SIGNAL_BAR_IN_OPPORTUNISTIC_NETWORK_BOOLEAN);
+                if (alwaysShowPrimary) {
+                    subscriptions.remove(info1.isOpportunistic() ? info1 : info2);
+                } else {
+                    subscriptions.remove(info1.getSubscriptionId() == mActiveMobileDataSubscription
+                            ? info2 : info1);
+                }
+
+            }
         }
     }
 
@@ -226,7 +279,17 @@
         boolean anySimReadyAndInService = false;
         CharSequence displayText = null;
 
-        List<SubscriptionInfo> subs = mKeyguardUpdateMonitor.getSubscriptionInfo(false);
+        // STOPSHIP(b/130246708) revert to mKeyguardUpdateMonitor.getSubscriptionInfo(false).
+        SubscriptionManager subscriptionManager = ((SubscriptionManager) mContext.getSystemService(
+                Context.TELEPHONY_SUBSCRIPTION_SERVICE));
+        List<SubscriptionInfo> subs = subscriptionManager.getActiveSubscriptionInfoList(false);
+
+        if (subs == null) {
+            subs = new ArrayList<>();
+        } else {
+            filterMobileSubscriptionInSameGroup(subs);
+        }
+
         final int numSubs = subs.size();
         final int[] subsIds = new int[numSubs];
         // This array will contain in position i, the index of subscription in slot ID i.
@@ -311,20 +374,23 @@
 
         displayText = updateCarrierTextWithSimIoError(displayText, carrierNames, subOrderBySlot,
                 allSimsMissing);
+        boolean airplaneMode = false;
         // APM (airplane mode) != no carrier state. There are carrier services
         // (e.g. WFC = Wi-Fi calling) which may operate in APM.
         if (!anySimReadyAndInService && WirelessUtils.isAirplaneModeOn(mContext)) {
             displayText = getAirplaneModeMessage();
+            airplaneMode = true;
         }
 
-        if (TextUtils.isEmpty(displayText)) {
+        if (TextUtils.isEmpty(displayText) && !airplaneMode) {
             displayText = TextUtils.join(mSeparator, carrierNames);
         }
         final CarrierTextCallbackInfo info = new CarrierTextCallbackInfo(
                 displayText,
                 carrierNames,
                 !allSimsMissing,
-                subsIds);
+                subsIds,
+                airplaneMode);
         postToCallback(info);
     }
 
@@ -525,14 +591,22 @@
         public final CharSequence[] listOfCarriers;
         public final boolean anySimReady;
         public final int[] subscriptionIds;
+        public boolean airplaneMode;
 
         @VisibleForTesting
         public CarrierTextCallbackInfo(CharSequence carrierText, CharSequence[] listOfCarriers,
                 boolean anySimReady, int[] subscriptionIds) {
+            this(carrierText, listOfCarriers, anySimReady, subscriptionIds, false);
+        }
+
+        @VisibleForTesting
+        public CarrierTextCallbackInfo(CharSequence carrierText, CharSequence[] listOfCarriers,
+                boolean anySimReady, int[] subscriptionIds, boolean airplaneMode) {
             this.carrierText = carrierText;
             this.listOfCarriers = listOfCarriers;
             this.anySimReady = anySimReady;
             this.subscriptionIds = subscriptionIds;
+            this.airplaneMode = airplaneMode;
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClockController.java b/packages/SystemUI/src/com/android/keyguard/clock/AnalogClockController.java
similarity index 90%
rename from packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClockController.java
rename to packages/SystemUI/src/com/android/keyguard/clock/AnalogClockController.java
index 81b6a60..1652121 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClockController.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/AnalogClockController.java
@@ -35,7 +35,7 @@
 /**
  * Controller for Stretch clock that can appear on lock screen and AOD.
  */
-public class StretchAnalogClockController implements ClockPlugin {
+public class AnalogClockController implements ClockPlugin {
 
     /**
      * Resources used to get title and thumbnail.
@@ -60,9 +60,9 @@
     /**
      * Custom clock shown on AOD screen and behind stack scroller on lock.
      */
-    private View mBigClockView;
+    private ClockLayout mBigClockView;
     private TextClock mDigitalClock;
-    private StretchAnalogClock mAnalogClock;
+    private ImageClock mAnalogClock;
 
     /**
      * Small clock shown on lock screen above stack scroller.
@@ -82,7 +82,7 @@
      * @param inflater Inflater used to inflate custom clock views.
      * @param colorExtractor Extracts accent color from wallpaper.
      */
-    public StretchAnalogClockController(Resources res, LayoutInflater inflater,
+    public AnalogClockController(Resources res, LayoutInflater inflater,
             SysuiColorExtractor colorExtractor) {
         mResources = res;
         mLayoutInflater = inflater;
@@ -90,7 +90,7 @@
     }
 
     private void createViews() {
-        mBigClockView = mLayoutInflater.inflate(R.layout.stretchanalog_clock, null);
+        mBigClockView = (ClockLayout) mLayoutInflater.inflate(R.layout.analog_clock, null);
         mAnalogClock = mBigClockView.findViewById(R.id.analog_clock);
         mDigitalClock = mBigClockView.findViewById(R.id.digital_clock);
 
@@ -114,17 +114,17 @@
 
     @Override
     public String getName() {
-        return "stretch";
+        return "analog";
     }
 
     @Override
     public String getTitle() {
-        return mResources.getString(R.string.clock_title_stretch);
+        return mResources.getString(R.string.clock_title_analog);
     }
 
     @Override
     public Bitmap getThumbnail() {
-        return BitmapFactory.decodeResource(mResources, R.drawable.stretch_thumbnail);
+        return BitmapFactory.decodeResource(mResources, R.drawable.analog_thumbnail);
     }
 
     @Override
@@ -175,13 +175,14 @@
         }
         final int length = colorPalette.length;
         mDigitalClock.setTextColor(colorPalette[Math.max(0, length - 5)]);
-        mAnalogClock.setClockColor(colorPalette[Math.max(0, length - 5)],
+        mAnalogClock.setClockColors(colorPalette[Math.max(0, length - 5)],
                 colorPalette[Math.max(0, length - 2)]);
     }
 
     @Override
     public void onTimeTick() {
         mAnalogClock.onTimeChanged();
+        mBigClockView.onTimeChanged();
         mDigitalClock.refresh();
         mLockClock.refresh();
     }
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java b/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java
index d30f45f..6069a5e 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java
@@ -60,7 +60,7 @@
     /**
      * Custom clock shown on AOD screen and behind stack scroller on lock.
      */
-    private View mView;
+    private ClockLayout mView;
     private TextClock mDigitalClock;
     private ImageClock mAnalogClock;
 
@@ -90,7 +90,7 @@
     }
 
     private void createViews() {
-        mView = mLayoutInflater.inflate(R.layout.bubble_clock, null);
+        mView = (ClockLayout) mLayoutInflater.inflate(R.layout.bubble_clock, null);
         mDigitalClock = (TextClock) mView.findViewById(R.id.digital_clock);
         mAnalogClock = (ImageClock) mView.findViewById(R.id.analog_clock);
 
@@ -186,6 +186,7 @@
     @Override
     public void onTimeTick() {
         mAnalogClock.onTimeChanged();
+        mView.onTimeChanged();
         mDigitalClock.refresh();
         mLockClock.refresh();
     }
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java
index 7ffee5d..55088a8 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/ClockLayout.java
@@ -32,6 +32,7 @@
  */
 public class ClockLayout extends FrameLayout {
 
+    private static final int ANALOG_CLOCK_SHIFT_FACTOR = 3;
     /**
      * Clock face views.
      */
@@ -73,7 +74,14 @@
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
+        positionChildren();
+    }
 
+    void onTimeChanged() {
+        positionChildren();
+    }
+
+    private void positionChildren() {
         final float offsetX = getBurnInOffset(mBurnInPreventionOffsetX * 2, true)
                 - mBurnInPreventionOffsetX;
         final float offsetY = getBurnInOffset(mBurnInPreventionOffsetY * 2, false)
@@ -89,9 +97,9 @@
         // Put the analog clock in the middle of the screen.
         if (mAnalogClock != null) {
             mAnalogClock.setX(Math.max(0f, 0.5f * (getWidth() - mAnalogClock.getWidth()))
-                    + offsetX);
+                    + ANALOG_CLOCK_SHIFT_FACTOR * offsetX);
             mAnalogClock.setY(Math.max(0f, 0.5f * (getHeight() - mAnalogClock.getHeight()))
-                    + offsetY);
+                    + ANALOG_CLOCK_SHIFT_FACTOR * offsetY);
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
index e373ca1..06488b8 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
@@ -142,8 +142,7 @@
 
         addBuiltinClock(() -> new DefaultClockController(res, layoutInflater, colorExtractor));
         addBuiltinClock(() -> new BubbleClockController(res, layoutInflater, colorExtractor));
-        addBuiltinClock(() -> new StretchAnalogClockController(res, layoutInflater,
-                colorExtractor));
+        addBuiltinClock(() -> new AnalogClockController(res, layoutInflater, colorExtractor));
 
         // Store the size of the display for generation of clock preview.
         DisplayMetrics dm = res.getDisplayMetrics();
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClock.java b/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClock.java
deleted file mode 100644
index 8cdd632..0000000
--- a/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClock.java
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * 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.keyguard.clock;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.util.AttributeSet;
-import android.view.View;
-
-import java.util.Calendar;
-import java.util.TimeZone;
-
-/**
- * Analog clock where the minute hand extends off of the screen.
- */
-public class StretchAnalogClock extends View {
-
-    private static final int DEFAULT_COLOR = Color.parseColor("#F5C983");
-    private static final float HOUR_STROKE_WIDTH = 60f;
-    private static final float MINUTE_STROKE_WIDTH = 20f;
-    private static final float CENTER_GAP_AND_CIRCLE_RADIUS = 80f;
-
-    private final Paint mHourPaint = new Paint();
-    private final Paint mMinutePaint = new Paint();
-    private Calendar mTime = Calendar.getInstance(TimeZone.getDefault());
-    private TimeZone mTimeZone;
-
-    public StretchAnalogClock(Context context) {
-        this(context, null);
-    }
-
-    public StretchAnalogClock(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public StretchAnalogClock(Context context, AttributeSet attrs, int defStyleAttr) {
-        this(context, attrs, defStyleAttr, 0);
-    }
-
-    public StretchAnalogClock(Context context, AttributeSet attrs, int defStyleAttr,
-            int defStyleRes) {
-        super(context, attrs, defStyleAttr, defStyleRes);
-        init();
-    }
-
-    /**
-     * Call when the time changes to update the clock hands.
-     */
-    public void onTimeChanged() {
-        mTime.setTimeInMillis(System.currentTimeMillis());
-        invalidate();
-    }
-
-    /**
-     * Call when the time zone has changed to update clock hands.
-     *
-     * @param timeZone The updated time zone that will be used.
-     */
-    public void onTimeZoneChanged(TimeZone timeZone) {
-        mTime.setTimeZone(timeZone);
-    }
-
-    /**
-     * Set the colors to use on the clock face.
-     * @param dark Darker color obtained from color palette.
-     * @param light Lighter color obtained from color palette.
-     */
-    public void setClockColor(int dark, int light) {
-        mHourPaint.setColor(dark);
-        invalidate();
-    }
-
-    private void init() {
-        mHourPaint.setColor(DEFAULT_COLOR);
-        mHourPaint.setStrokeWidth(HOUR_STROKE_WIDTH);
-        mHourPaint.setAntiAlias(true);
-        mHourPaint.setStrokeCap(Paint.Cap.ROUND);
-
-        mMinutePaint.setColor(Color.WHITE);
-        mMinutePaint.setStrokeWidth(MINUTE_STROKE_WIDTH);
-        mMinutePaint.setAntiAlias(true);
-        mMinutePaint.setStrokeCap(Paint.Cap.ROUND);
-    }
-
-    @Override
-    protected void onDraw(Canvas canvas) {
-        final float centerX = getWidth() / 2f;
-        final float centerY = getHeight() / 2f;
-
-        final float minutesRotation = mTime.get(Calendar.MINUTE) * 6f;
-        final float hoursRotation = mTime.get(Calendar.HOUR) * 30
-                + mTime.get(Calendar.MINUTE) * 0.5f;
-
-        // Compute length of clock hands. Hour hand is 60% the length from center to edge
-        // and minute hand is twice the length to make sure it extends past screen edge.
-        double sMinuteHandLengthFactor = Math.sin(2d * Math.PI * minutesRotation / 360d);
-        float sMinuteHandLength = (float) (2d * (centerY + (centerX - centerY)
-                * sMinuteHandLengthFactor * sMinuteHandLengthFactor));
-        double sHourHandLengthFactor = Math.sin(2d * Math.PI * hoursRotation / 360d);
-        float sHourHandLength = (float) (0.6d * (centerY + (centerX - centerY)
-                * sHourHandLengthFactor * sHourHandLengthFactor));
-
-        canvas.save();
-
-        canvas.rotate(minutesRotation, centerX, centerY);
-        canvas.drawLine(
-                centerX,
-                centerY + CENTER_GAP_AND_CIRCLE_RADIUS,
-                centerX,
-                centerY - sMinuteHandLength,
-                mMinutePaint);
-
-        canvas.rotate(hoursRotation - minutesRotation, centerX, centerY);
-        canvas.drawLine(
-                centerX,
-                centerY + CENTER_GAP_AND_CIRCLE_RADIUS,
-                centerX,
-                centerY - sHourHandLength,
-                mHourPaint);
-
-        canvas.restore();
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        mTime.setTimeZone(mTimeZone != null ? mTimeZone : TimeZone.getDefault());
-        onTimeChanged();
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
index 665df77..0332477 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java
@@ -16,47 +16,65 @@
 package com.android.systemui.bubbles;
 
 
+import android.os.UserHandle;
 import android.view.LayoutInflater;
 
 import com.android.systemui.R;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 
+import java.util.Objects;
+
 /**
  * Encapsulates the data and UI elements of a bubble.
  */
 class Bubble {
 
+    private static final boolean DEBUG = false;
+    private static final String TAG = "Bubble";
+
     private final String mKey;
+    private final String mGroupId;
     private final BubbleExpandedView.OnBubbleBlockedListener mListener;
 
     private boolean mInflated;
-
-    public BubbleView iconView;
-    public BubbleExpandedView expandedView;
     public NotificationEntry entry;
+    BubbleView iconView;
+    BubbleExpandedView expandedView;
+
+    private static String groupId(NotificationEntry entry) {
+        UserHandle user = entry.notification.getUser();
+        return user.getIdentifier() + '|' + entry.notification.getPackageName();
+    }
 
     Bubble(NotificationEntry e, BubbleExpandedView.OnBubbleBlockedListener listener) {
         entry = e;
         mKey = e.key;
+        mGroupId = groupId(e);
         mListener = listener;
     }
 
-    /** @deprecated use the other constructor to defer View creation. */
-    @Deprecated
-    Bubble(NotificationEntry e, LayoutInflater inflater, BubbleStackView stackView,
-            BubbleExpandedView.OnBubbleBlockedListener listener) {
-        this(e, listener);
-        inflate(inflater, stackView);
-    }
-
     public String getKey() {
         return mKey;
     }
 
+    public String getGroupId() {
+        return mGroupId;
+    }
+
+    public String getPackageName() {
+        return entry.notification.getPackageName();
+    }
+
     boolean isInflated() {
         return mInflated;
     }
 
+    public void updateDotVisibility() {
+        if (iconView != null) {
+            iconView.updateDotVisibility();
+        }
+    }
+
     void inflate(LayoutInflater inflater, BubbleStackView stackView) {
         if (mInflated) {
             return;
@@ -73,10 +91,32 @@
         mInflated = true;
     }
 
+    void setDismissed() {
+        entry.setBubbleDismissed(true);
+        // TODO: move this somewhere where it can be guaranteed not to run until safe from flicker
+        if (expandedView != null) {
+            expandedView.cleanUpExpandedState();
+        }
+    }
+
     void setEntry(NotificationEntry entry) {
+        this.entry = entry;
         if (mInflated) {
             iconView.update(entry);
             expandedView.update(entry);
         }
     }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (!(o instanceof Bubble)) return false;
+        Bubble bubble = (Bubble) o;
+        return Objects.equals(mKey, bubble.mKey);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(mKey);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index af9fd1d..6d0141b 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -78,8 +78,7 @@
  * The controller manages addition, removal, and visible state of bubbles on screen.
  */
 @Singleton
-public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListener,
-        ConfigurationController.ConfigurationListener {
+public class BubbleController implements ConfigurationController.ConfigurationListener {
 
     private static final String TAG = "BubbleController";
 
@@ -178,6 +177,10 @@
         @Override
         public void onStateChanged(int newState) {
             mState = newState;
+            boolean shouldCollapse = (mState != SHADE);
+            if (shouldCollapse) {
+                collapseStack();
+            }
             updateVisibility();
         }
     }
@@ -240,7 +243,6 @@
             if (mExpandListener != null) {
                 mStackView.setExpandListener(mExpandListener);
             }
-            mStackView.setOnBlockedListener(this);
         }
     }
 
@@ -296,28 +298,38 @@
         if (mStackView == null) {
             return false;
         }
-        for (Bubble bubble : mBubbleData.getBubbles()) {
-            if (!bubble.entry.isBubbleDismissed()) {
-                return true;
-            }
-        }
-        return false;
+        return mBubbleData.hasBubbles();
     }
 
     /**
      * Whether the stack of bubbles is expanded or not.
      */
     public boolean isStackExpanded() {
-        return mStackView != null && mStackView.isExpanded();
+        return mBubbleData.isExpanded();
+    }
+
+    /**
+     * Tell the stack of bubbles to expand.
+     */
+    public void expandStack() {
+        mBubbleData.setExpanded(true);
     }
 
     /**
      * Tell the stack of bubbles to collapse.
      */
     public void collapseStack() {
-        if (mStackView != null) {
-            mStackView.collapseStack();
-        }
+        mBubbleData.setExpanded(false /* expanded */);
+    }
+
+    void selectBubble(Bubble bubble) {
+        mBubbleData.setSelectedBubble(bubble);
+    }
+
+    @VisibleForTesting
+    void selectBubble(String key) {
+        Bubble bubble = mBubbleData.getBubbleWithKey(key);
+        selectBubble(bubble);
     }
 
     /**
@@ -326,8 +338,10 @@
      * @param notificationKey the notification key for the bubble to be selected
      */
     public void expandStackAndSelectBubble(String notificationKey) {
-        if (mStackView != null && mBubbleData.getBubble(notificationKey) != null) {
-            mStackView.setExpandedBubble(notificationKey);
+        Bubble bubble = mBubbleData.getBubbleWithKey(notificationKey);
+        if (bubble != null) {
+            mBubbleData.setSelectedBubble(bubble);
+            mBubbleData.setExpanded(true);
         }
     }
 
@@ -335,13 +349,7 @@
      * Tell the stack of bubbles to be dismissed, this will remove all of the bubbles in the stack.
      */
     void dismissStack(@DismissReason int reason) {
-        if (mStackView == null) {
-            return;
-        }
-        mStackView.stackDismissed(reason);
-
-        updateVisibility();
-        mNotificationEntryManager.updateNotifications();
+        mBubbleData.dismissAll(reason);
     }
 
     /**
@@ -360,20 +368,7 @@
      * @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 {
-            // It's new
-            ensureStackViewCreated();
-            mStackView.addBubble(notif);
-        }
-        Bubble bubble = mBubbleData.getBubble(notif.key);
-        if (shouldAutoExpand(notif)) {
-            mStackView.setSelectedBubble(bubble);
-            mStackView.setExpanded(true);
-        }
-        updateVisibility();
+        mBubbleData.notificationEntryUpdated(notif);
     }
 
     /**
@@ -383,23 +378,10 @@
      */
     @MainThread
     void removeBubble(String key, int reason) {
-        if (mStackView != null) {
-            mStackView.removeBubble(key, reason);
-        }
-        mNotificationEntryManager.updateNotifications();
-        updateVisibility();
-    }
-
-    @Override
-    public void onBubbleBlocked(NotificationEntry entry) {
-        Object[] bubbles = mBubbleData.getBubbles().toArray();
-        for (int i = 0; i < bubbles.length; i++) {
-            NotificationEntry e = ((Bubble) bubbles[i]).entry;
-            boolean samePackage = entry.notification.getPackageName().equals(
-                    e.notification.getPackageName());
-            if (samePackage) {
-                removeBubble(entry.key, DISMISS_BLOCKED);
-            }
+        // TEMP: refactor to change this to pass entry
+        Bubble bubble = mBubbleData.getBubbleWithKey(key);
+        if (bubble != null) {
+            mBubbleData.notificationEntryRemoved(bubble.entry, reason);
         }
     }
 
@@ -436,7 +418,6 @@
                 updateShowInShadeForSuppressNotification(entry);
                 entry.setBubbleDismissed(false); // updates come back as bubbles even if dismissed
                 updateBubble(entry);
-                mStackView.updateDotVisibility(entry.key);
             }
         }
 
@@ -458,44 +439,57 @@
         }
     };
 
+    @SuppressWarnings("FieldCanBeLocal")
     private final BubbleData.Listener mBubbleDataListener = new BubbleData.Listener() {
+
         @Override
         public void onBubbleAdded(Bubble bubble) {
-
+            ensureStackViewCreated();
+            mStackView.addBubble(bubble);
         }
 
         @Override
         public void onBubbleRemoved(Bubble bubble, int reason) {
-
+            if (mStackView != null) {
+                mStackView.removeBubble(bubble);
+            }
         }
 
         public void onBubbleUpdated(Bubble bubble) {
-
+            if (mStackView != null) {
+                mStackView.updateBubble(bubble);
+            }
         }
 
         @Override
         public void onOrderChanged(List<Bubble> bubbles) {
-
         }
 
         @Override
         public void onSelectionChanged(Bubble selectedBubble) {
-
+            if (mStackView != null) {
+                mStackView.setSelectedBubble(selectedBubble);
+            }
         }
 
         @Override
         public void onExpandedChanged(boolean expanded) {
-
+            if (mStackView != null) {
+                mStackView.setExpanded(expanded);
+            }
         }
 
         @Override
         public void showFlyoutText(Bubble bubble, String text) {
-
+            if (mStackView != null) {
+                mStackView.animateInFlyoutForBubble(bubble);
+            }
         }
 
         @Override
         public void apply() {
-
+            mNotificationEntryManager.updateNotifications();
+            updateVisibility();
         }
     };
 
@@ -526,7 +520,6 @@
             mStackView.setVisibility(hasBubbles() ? VISIBLE : INVISIBLE);
         } else if (mStackView != null) {
             mStackView.setVisibility(INVISIBLE);
-            collapseStack();
         }
         updateBubblesShowing();
     }
@@ -633,14 +626,14 @@
         @Override
         public void onTaskMovedToFront(RunningTaskInfo taskInfo) {
             if (mStackView != null && taskInfo.displayId == Display.DEFAULT_DISPLAY) {
-                mStackView.collapseStack();
+                mBubbleData.setExpanded(false);
             }
         }
 
         @Override
         public void onActivityLaunchOnSecondaryDisplayRerouted() {
             if (mStackView != null) {
-                mStackView.collapseStack();
+                mBubbleData.setExpanded(false);
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
index fe3f9d1..259665d 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java
@@ -15,14 +15,24 @@
  */
 package com.android.systemui.bubbles;
 
-import androidx.annotation.Nullable;
+import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE;
+
+import android.app.ActivityManager;
+import android.app.Notification;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.bubbles.BubbleController.DismissReason;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 
+import java.util.ArrayList;
 import java.util.Collection;
-import java.util.HashMap;
+import java.util.Collections;
+import java.util.Iterator;
 import java.util.List;
+import java.util.Objects;
 
 import javax.inject.Inject;
 import javax.inject.Singleton;
@@ -33,6 +43,8 @@
 @Singleton
 public class BubbleData {
 
+    private static final String TAG = "BubbleData";
+
     /**
      * This interface reports changes to the state and appearance of bubbles which should be applied
      * as necessary to the UI.
@@ -53,7 +65,7 @@
          * A Bubble has been removed. A call to {@link #onOrderChanged(List)} will
          * follow.
          */
-        void onBubbleRemoved(Bubble bubble, @BubbleController.DismissReason int reason);
+        void onBubbleRemoved(Bubble bubble, @DismissReason int reason);
 
         /**
          * An existing bubble has been updated.
@@ -86,46 +98,253 @@
         void apply();
     }
 
-    private HashMap<String, Bubble> mBubbles = new HashMap<>();
+    private final Context mContext;
+    private final List<Bubble> mBubbles = new ArrayList<>();
+    private Bubble mSelectedBubble;
+    private boolean mExpanded;
     private Listener mListener;
 
     @VisibleForTesting
     @Inject
-    public BubbleData() {}
-
-    /**
-     * The set of bubbles.
-     */
-    public Collection<Bubble> getBubbles() {
-        return mBubbles.values();
+    public BubbleData(Context context) {
+        mContext = context;
     }
 
-    @Nullable
-    public Bubble getBubble(String key) {
-        return mBubbles.get(key);
+    public boolean hasBubbles() {
+        return !mBubbles.isEmpty();
     }
 
-    public void addBubble(Bubble b) {
-        mBubbles.put(b.getKey(), b);
+    public boolean isExpanded() {
+        return mExpanded;
     }
 
-    @Nullable
-    public Bubble removeBubble(String key) {
-        return mBubbles.remove(key);
+    public boolean hasBubbleWithKey(String key) {
+        return getBubbleWithKey(key) != null;
     }
 
-    public void updateBubble(String key, NotificationEntry newEntry) {
-        Bubble oldBubble = mBubbles.get(key);
-        if (oldBubble != null) {
-            oldBubble.setEntry(newEntry);
+    public void setExpanded(boolean expanded) {
+        if (setExpandedInternal(expanded)) {
+            mListener.apply();
         }
     }
 
-    public void clear() {
-        mBubbles.clear();
+    public void setSelectedBubble(Bubble bubble) {
+        if (setSelectedBubbleInternal(bubble)) {
+            mListener.apply();
+        }
+    }
+
+    public void notificationEntryUpdated(NotificationEntry entry) {
+        Bubble bubble = getBubbleWithKey(entry.key);
+        if (bubble == null) {
+            // Create a new bubble
+            bubble = new Bubble(entry, this::onBubbleBlocked);
+            mBubbles.add(0, bubble); // TODO: reorder/group
+            mListener.onBubbleAdded(bubble);
+        } else {
+            // Updates an existing bubble
+            bubble.setEntry(entry);
+            mListener.onBubbleUpdated(bubble);
+        }
+        if (shouldAutoExpand(entry)) {
+            setSelectedBubbleInternal(bubble);
+            if (!mExpanded) {
+                setExpandedInternal(true);
+            }
+        } else if (mSelectedBubble == null) {
+            setSelectedBubbleInternal(bubble);
+        }
+        // TODO: reorder/group
+        mListener.apply();
+    }
+
+    public void notificationEntryRemoved(NotificationEntry entry, @DismissReason int reason) {
+        int indexToRemove = indexForKey(entry.key);
+        if (indexToRemove >= 0) {
+            Bubble removed = mBubbles.remove(indexToRemove);
+            removed.setDismissed();
+            mListener.onBubbleRemoved(removed, reason);
+            maybeSendDeleteIntent(reason, removed.entry);
+
+            if (mBubbles.isEmpty()) {
+                setExpandedInternal(false);
+                setSelectedBubbleInternal(null);
+            } else if (removed == mSelectedBubble) {
+                int newIndex = Math.min(indexToRemove, mBubbles.size() - 1);
+                Bubble newSelected = mBubbles.get(newIndex);
+                setSelectedBubbleInternal(newSelected);
+            }
+            // TODO: reorder/group
+            mListener.apply();
+        }
+    }
+
+    public void dismissAll(@DismissReason int reason) {
+        boolean changed = setExpandedInternal(false);
+        while (!mBubbles.isEmpty()) {
+            Bubble bubble = mBubbles.remove(0);
+            bubble.setDismissed();
+            maybeSendDeleteIntent(reason, bubble.entry);
+            mListener.onBubbleRemoved(bubble, reason);
+            changed = true;
+        }
+        if (setSelectedBubbleInternal(null)) {
+            changed = true;
+        }
+        if (changed) {
+            // TODO: reorder/group
+            mListener.apply();
+        }
+    }
+
+    /**
+     * Requests a change to the selected bubble. Calls {@link Listener#onSelectionChanged} if
+     * the value changes.
+     *
+     * @param bubble the new selected bubble
+     * @return true if the state changed as a result
+     */
+    private boolean setSelectedBubbleInternal(Bubble bubble) {
+        if (Objects.equals(bubble, mSelectedBubble)) {
+            return false;
+        }
+        if (bubble != null && !mBubbles.contains(bubble)) {
+            Log.e(TAG, "Cannot select bubble which doesn't exist!"
+                    + " (" + bubble + ") bubbles=" + mBubbles);
+            return false;
+        }
+        if (mExpanded) {
+            // TODO: bubble.markAsActive() ?
+            bubble.entry.setShowInShadeWhenBubble(false);
+        }
+        mSelectedBubble = bubble;
+        mListener.onSelectionChanged(mSelectedBubble);
+        return true;
+    }
+
+
+    /**
+     * Requests a change to the expanded state. Calls {@link Listener#onExpandedChanged} if
+     * the value changes.
+     *
+     * @param shouldExpand the new requested state
+     * @return true if the state changed as a result
+     */
+    private boolean setExpandedInternal(boolean shouldExpand) {
+        if (mExpanded == shouldExpand) {
+            return false;
+        }
+        if (shouldExpand) {
+            if (mBubbles.isEmpty()) {
+                Log.e(TAG, "Attempt to expand stack when empty!");
+                return false;
+            }
+            if (mSelectedBubble == null) {
+                Log.e(TAG, "Attempt to expand stack without selected bubble!");
+                return false;
+            }
+            // TODO: bubble.markAsActive() ?
+            mSelectedBubble.entry.setShowInShadeWhenBubble(false);
+        }
+        // TODO: reorder/regroup
+        mExpanded = shouldExpand;
+        mListener.onExpandedChanged(mExpanded);
+        return true;
+    }
+
+    private void maybeSendDeleteIntent(@DismissReason int reason, NotificationEntry entry) {
+        if (reason == BubbleController.DISMISS_USER_GESTURE) {
+            Notification.BubbleMetadata bubbleMetadata = entry.getBubbleMetadata();
+            PendingIntent deleteIntent = bubbleMetadata != null
+                    ? bubbleMetadata.getDeleteIntent()
+                    : null;
+            if (deleteIntent != null) {
+                try {
+                    deleteIntent.send();
+                } catch (PendingIntent.CanceledException e) {
+                    Log.w(TAG, "Failed to send delete intent for bubble with key: " + entry.key);
+                }
+            }
+        }
+    }
+
+    private void onBubbleBlocked(NotificationEntry entry) {
+        boolean changed = false;
+        final String blockedPackage = entry.notification.getPackageName();
+        for (Iterator<Bubble> i = mBubbles.iterator(); i.hasNext(); ) {
+            Bubble bubble = i.next();
+            if (bubble.getPackageName().equals(blockedPackage)) {
+                i.remove();
+                mListener.onBubbleRemoved(bubble, BubbleController.DISMISS_BLOCKED);
+                changed = true;
+            }
+        }
+        if (changed) {
+            // TODO: reorder/group
+            mListener.apply();
+        }
+    }
+
+    private int indexForKey(String key) {
+        for (int i = 0; i < mBubbles.size(); i++) {
+            Bubble bubble = mBubbles.get(i);
+            if (bubble.getKey().equals(key)) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    private Bubble removeBubbleWithKey(String key) {
+        for (int i = 0; i < mBubbles.size(); i++) {
+            Bubble bubble = mBubbles.get(i);
+            if (bubble.getKey().equals(key)) {
+                mBubbles.remove(i);
+                return bubble;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * The set of bubbles.
+     *
+     * @deprecated
+     */
+    @Deprecated
+    public Collection<Bubble> getBubbles() {
+        return Collections.unmodifiableList(mBubbles);
+    }
+
+    @VisibleForTesting(visibility = PRIVATE)
+    Bubble getBubbleWithKey(String key) {
+        for (int i = 0; i < mBubbles.size(); i++) {
+            Bubble bubble = mBubbles.get(i);
+            if (bubble.getKey().equals(key)) {
+                return bubble;
+            }
+        }
+        return null;
     }
 
     public void setListener(Listener listener) {
         mListener = listener;
     }
-}
+
+    boolean shouldAutoExpand(NotificationEntry entry) {
+        Notification.BubbleMetadata metadata = entry.getBubbleMetadata();
+        return metadata != null && metadata.getAutoExpandBubble()
+                && isForegroundApp(entry.notification.getPackageName());
+    }
+
+    /**
+     * Return true if the applications with the package name is running in foreground.
+     *
+     * @param pkgName application package name.
+     */
+    boolean isForegroundApp(String pkgName) {
+        ActivityManager am = mContext.getSystemService(ActivityManager.class);
+        List<ActivityManager.RunningTaskInfo> tasks = am.getRunningTasks(1 /* maxNum */);
+        return !tasks.isEmpty() && pkgName.equals(tasks.get(0).topActivity.getPackageName());
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index 024e564..a4a0fe1 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -20,8 +20,6 @@
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
 
 import android.annotation.NonNull;
-import android.app.Notification;
-import android.app.PendingIntent;
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Outline;
@@ -54,9 +52,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.widget.ViewClippingUtil;
-import com.android.systemui.Dependency;
 import com.android.systemui.R;
-import com.android.systemui.bubbles.BubbleController.DismissReason;
 import com.android.systemui.bubbles.animation.ExpandedAnimationController;
 import com.android.systemui.bubbles.animation.PhysicsAnimationLayout;
 import com.android.systemui.bubbles.animation.StackAnimationController;
@@ -390,14 +386,13 @@
         }
         switch (action) {
             case AccessibilityNodeInfo.ACTION_DISMISS:
-                Dependency.get(BubbleController.class).dismissStack(
-                        BubbleController.DISMISS_ACCESSIBILITY_ACTION);
+                mBubbleData.dismissAll(BubbleController.DISMISS_ACCESSIBILITY_ACTION);
                 return true;
             case AccessibilityNodeInfo.ACTION_COLLAPSE:
-                collapseStack();
+                mBubbleData.setExpanded(false);
                 return true;
             case AccessibilityNodeInfo.ACTION_EXPAND:
-                expandStack();
+                mBubbleData.setExpanded(true);
                 return true;
         }
         return false;
@@ -424,9 +419,9 @@
      * @param key the {@link NotificationEntry#key} associated with the bubble.
      */
     public void updateDotVisibility(String key) {
-        Bubble b = mBubbleData.getBubble(key);
+        Bubble b = mBubbleData.getBubbleWithKey(key);
         if (b != null) {
-            b.iconView.updateDotVisibility();
+            b.updateDotVisibility();
         }
     }
 
@@ -438,16 +433,6 @@
     }
 
     /**
-     * Sets the listener to notify when a bubble is blocked.
-     */
-    public void setOnBlockedListener(BubbleExpandedView.OnBubbleBlockedListener listener) {
-        mBlockedListener = listener;
-        for (Bubble b : mBubbleData.getBubbles()) {
-            b.expandedView.setOnBlockedListener(mBlockedListener);
-        }
-    }
-
-    /**
      * Whether the stack of bubbles is expanded or not.
      */
     public boolean isExpanded() {
@@ -476,7 +461,7 @@
      */
     @Deprecated
     void setExpandedBubble(String key) {
-        Bubble bubbleToExpand = mBubbleData.getBubble(key);
+        Bubble bubbleToExpand = mBubbleData.getBubbleWithKey(key);
         if (bubbleToExpand != null) {
             setSelectedBubble(bubbleToExpand);
             bubbleToExpand.entry.setShowInShadeWhenBubble(false);
@@ -497,11 +482,36 @@
         }
     }
 
+    // via BubbleData.Listener
+    void addBubble(Bubble bubble) {
+        bubble.inflate(mInflater, this);
+        mBubbleContainer.addView(bubble.iconView, 0,
+                new FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
+        ViewClippingUtil.setClippingDeactivated(bubble.iconView, true, mClippingParameters);
+        requestUpdate();
+        logBubbleEvent(bubble, StatsLog.BUBBLE_UICHANGED__ACTION__POSTED);
+    }
+
+    // via BubbleData.Listener
+    void removeBubble(Bubble bubble) {
+        // Remove it from the views
+        int removedIndex = mBubbleContainer.indexOfChild(bubble.iconView);
+        mBubbleContainer.removeViewAt(removedIndex);
+        logBubbleEvent(bubble, StatsLog.BUBBLE_UICHANGED__ACTION__DISMISSED);
+    }
+
+    // via BubbleData.Listener
+    void updateBubble(Bubble bubble) {
+        requestUpdate();
+        logBubbleEvent(bubble, StatsLog.BUBBLE_UICHANGED__ACTION__UPDATED);
+    }
+
     /**
      * Changes the currently selected bubble. If the stack is already expanded, the newly selected
      * bubble will be shown immediately. This does not change the expanded state or change the
      * position of any bubble.
      */
+    // via BubbleData.Listener
     public void setSelectedBubble(Bubble bubbleToSelect) {
         if (mExpandedBubble != null && mExpandedBubble.equals(bubbleToSelect)) {
             return;
@@ -520,7 +530,8 @@
                 logBubbleEvent(previouslySelected, StatsLog.BUBBLE_UICHANGED__ACTION__COLLAPSED);
                 logBubbleEvent(bubbleToSelect, StatsLog.BUBBLE_UICHANGED__ACTION__EXPANDED);
                 notifyExpansionChanged(previouslySelected.entry, false /* expanded */);
-                notifyExpansionChanged(bubbleToSelect.entry, true /* expanded */);
+                notifyExpansionChanged(bubbleToSelect == null ? null : bubbleToSelect.entry,
+                        true /* expanded */);
             });
         }
     }
@@ -528,13 +539,15 @@
     /**
      * Changes the expanded state of the stack.
      *
-     * @param expanded whether the bubble stack should appear expanded
+     * @param shouldExpand whether the bubble stack should appear expanded
      */
-    public void setExpanded(boolean expanded) {
-        if (expanded == mIsExpanded) {
+    // via BubbleData.Listener
+    public void setExpanded(boolean shouldExpand) {
+        boolean wasExpanded = mIsExpanded;
+        if (shouldExpand == wasExpanded) {
             return;
         }
-        if (mIsExpanded) {
+        if (wasExpanded) {
             // Collapse the stack
             animateExpansion(false /* expand */);
             logBubbleEvent(mExpandedBubble, StatsLog.BUBBLE_UICHANGED__ACTION__COLLAPSED);
@@ -549,131 +562,17 @@
     }
 
     /**
-     * Adds a bubble to the top of the stack.
-     *
-     * @param entry the notification to add to the stack of bubbles.
-     */
-    void addBubble(NotificationEntry entry) {
-        Bubble b = new Bubble(entry, mInflater, this /* stackView */, mBlockedListener);
-        mBubbleData.addBubble(b);
-
-        mBubbleContainer.addView(b.iconView, 0,
-                new FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
-        ViewClippingUtil.setClippingDeactivated(b.iconView, true, mClippingParameters);
-
-        requestUpdate();
-        logBubbleEvent(b, StatsLog.BUBBLE_UICHANGED__ACTION__POSTED);
-
-        animateInFlyoutForBubble(b);
-    }
-
-    /**
-     * Remove a bubble from the stack.
-     */
-    void removeBubble(String key, int reason) {
-        Bubble b = mBubbleData.removeBubble(key);
-        if (b == null) {
-            return;
-        }
-        setBubbleDismissed(b, reason);
-
-        // Remove it from the views
-        int removedIndex = mBubbleContainer.indexOfChild(b.iconView);
-        mBubbleContainer.removeViewAt(removedIndex);
-
-        int bubbleCount = mBubbleContainer.getChildCount();
-        if (bubbleCount == 0) {
-            // If no bubbles remain, collapse the entire stack.
-            collapseStack();
-            return;
-        } else if (b.equals(mExpandedBubble)) {
-            // Was the current bubble just removed?
-            // If we have other bubbles and are expanded go to the next one or previous
-            // if the bubble removed was last
-            int nextIndex = bubbleCount > removedIndex ? removedIndex : bubbleCount - 1;
-            BubbleView expandedBubble = (BubbleView) mBubbleContainer.getChildAt(nextIndex);
-            if (mIsExpanded) {
-                setExpandedBubble(expandedBubble.getKey());
-            } else {
-                mExpandedBubble = null;
-            }
-        }
-        // TODO: consider logging reason code
-        logBubbleEvent(b, StatsLog.BUBBLE_UICHANGED__ACTION__DISMISSED);
-    }
-
-    /**
      * Dismiss the stack of bubbles.
+     * @deprecated
      */
+    @Deprecated
     void stackDismissed(int reason) {
-        for (Bubble bubble : mBubbleData.getBubbles()) {
-            setBubbleDismissed(bubble, reason);
-        }
-        mBubbleData.clear();
-        collapseStack();
-        mBubbleContainer.removeAllViews();
-        mExpandedViewContainer.removeAllViews();
-        // TODO: consider logging reason code
+        mBubbleData.dismissAll(reason);
         logBubbleEvent(null /* no bubble associated with bubble stack dismiss */,
                 StatsLog.BUBBLE_UICHANGED__ACTION__STACK_DISMISSED);
     }
 
     /**
-     * Marks the notification entry as dismissed & calls any delete intents for the bubble.
-     *
-     * <p>Note: This does not remove the Bubble from BubbleData.
-     *
-     * @param bubble the Bubble being dismissed
-     * @param reason code for the reason the dismiss was triggered
-     * @see BubbleController.DismissReason
-     */
-    private void setBubbleDismissed(Bubble bubble, @DismissReason int reason) {
-        if (DEBUG) {
-            Log.d(TAG, "dismissBubble: " + bubble + " reason=" + reason);
-        }
-        bubble.entry.setBubbleDismissed(true);
-        bubble.expandedView.cleanUpExpandedState();
-
-        if (reason == BubbleController.DISMISS_USER_GESTURE) {
-            Notification.BubbleMetadata bubbleMetadata = bubble.entry.getBubbleMetadata();
-            PendingIntent deleteIntent = bubbleMetadata != null
-                    ? bubbleMetadata.getDeleteIntent()
-                    : null;
-            if (deleteIntent != null) {
-                try {
-                    deleteIntent.send();
-                } catch (PendingIntent.CanceledException e) {
-                    Log.w(TAG, "Failed to send delete intent for bubble with key: "
-                            + (bubble.entry != null ? bubble.entry.key : " null entry"));
-                }
-            }
-        }
-    }
-
-    /**
-     * Updates a bubble in the stack.
-     *  @param entry the entry to update in the stack.
-     */
-    public void updateBubble(NotificationEntry entry) {
-        Bubble b = mBubbleData.getBubble(entry.key);
-        mBubbleData.updateBubble(entry.key, entry);
-
-        if (!mIsExpanded) {
-            // If alerting it gets promoted to top of the stack.
-            if (mBubbleContainer.indexOfChild(b.iconView) != 0) {
-                mBubbleContainer.moveViewTo(b.iconView, 0);
-            }
-            requestUpdate();
-            animateInFlyoutForBubble(b /* bubble */);
-        }
-        if (mIsExpanded && entry.equals(mExpandedBubble.entry)) {
-            entry.setShowInShadeWhenBubble(false);
-            requestUpdate();
-        }
-        logBubbleEvent(b, StatsLog.BUBBLE_UICHANGED__ACTION__UPDATED);
-    }
-
-    /**
      * @return the view the touch event is on
      */
     @Nullable
@@ -701,7 +600,7 @@
         return this;
     }
 
-    public View getFlyoutView() {
+    View getFlyoutView() {
         return mFlyout;
     }
 
@@ -714,13 +613,8 @@
      */
     @Deprecated
     @MainThread
-    public void collapseStack() {
-        if (mIsExpanded) {
-            // TODO: Save opened bubble & move it to top of stack
-            animateExpansion(false /* shouldExpand */);
-            notifyExpansionChanged(mExpandedBubble.entry, mIsExpanded);
-            logBubbleEvent(mExpandedBubble, StatsLog.BUBBLE_UICHANGED__ACTION__COLLAPSED);
-        }
+    void collapseStack() {
+        mBubbleData.setExpanded(false);
     }
 
     /**
@@ -743,12 +637,8 @@
      */
     @Deprecated
     @MainThread
-    public void expandStack() {
-        if (!mIsExpanded) {
-            String expandedBubbleKey = getBubbleAt(0).getKey();
-            setExpandedBubble(expandedBubbleKey);
-            logBubbleEvent(mExpandedBubble, StatsLog.BUBBLE_UICHANGED__ACTION__STACK_EXPANDED);
-        }
+    void expandStack() {
+        mBubbleData.setExpanded(true);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsGridLayout.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsGridLayout.java
index f882569..e7878c6 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsGridLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsGridLayout.java
@@ -119,6 +119,17 @@
             }
         }
         updateSnapPosition();
+        updateSeparatedButtonSize();
+    }
+
+    private void updateSeparatedButtonSize() {
+        ViewGroup separated = getSeparatedView();
+        if (separated.getChildCount() == 1) {
+            View onlyChild = separated.getChildAt(0);
+            ViewGroup.LayoutParams childParams = onlyChild.getLayoutParams();
+            childParams.width = ViewGroup.LayoutParams.MATCH_PARENT;
+            childParams.height = ViewGroup.LayoutParams.MATCH_PARENT;
+        }
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
index 6f50baa..4590470 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
@@ -25,9 +25,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.graphics.Rect;
 import android.graphics.Typeface;
-import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Icon;
 import android.icu.text.DateFormat;
 import android.icu.text.DisplayContext;
@@ -37,13 +35,8 @@
 import android.os.Trace;
 import android.provider.Settings;
 import android.service.notification.ZenModeConfig;
-import android.text.SpannableStringBuilder;
-import android.text.Spanned;
 import android.text.TextUtils;
-import android.text.style.DynamicDrawableSpan;
-import android.text.style.ImageSpan;
 import android.text.style.StyleSpan;
-import android.util.MathUtils;
 
 import androidx.core.graphics.drawable.IconCompat;
 import androidx.slice.Slice;
@@ -205,9 +198,9 @@
                 addMediaLocked(builder);
             } else {
                 builder.addRow(new RowBuilder(mDateUri).setTitle(mLastText));
-                addNextAlarmLocked(builder);
-                addZenModeLocked(builder);
             }
+            addNextAlarmLocked(builder);
+            addZenModeLocked(builder);
             addPrimaryActionLocked(builder);
             slice = builder.build();
         }
@@ -221,32 +214,25 @@
 
     protected void addMediaLocked(ListBuilder listBuilder) {
         if (mMediaMetaData != null) {
-            SpannableStringBuilder builder = new SpannableStringBuilder();
-
-            Icon notificationIcon = mMediaManager == null ? null : mMediaManager.getMediaIcon();
-            if (notificationIcon != null) {
-                Drawable drawable = notificationIcon.loadDrawable(getContext());
-                Rect mediaBounds = new Rect(0 /* left */, 0 /* top */,
-                        drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
-                int iconHeaderSize = getContext().getResources()
-                        .getDimensionPixelSize(R.dimen.header_icon_size);
-                MathUtils.fitRect(mediaBounds, iconHeaderSize);
-                drawable.setBounds(mediaBounds);
-                builder.append("# ");
-                builder.setSpan(new ImageSpan(drawable, DynamicDrawableSpan.ALIGN_CENTER),
-                        0 /* start */, 1 /* end */, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);
-            }
-
             CharSequence title = mMediaMetaData.getText(MediaMetadata.METADATA_KEY_TITLE);
             if (TextUtils.isEmpty(title)) {
                 title = getContext().getResources().getString(R.string.music_controls_no_title);
             }
-            builder.append(title);
-            listBuilder.setHeader(new ListBuilder.HeaderBuilder(mHeaderUri).setTitle(builder));
+            listBuilder.setHeader(new ListBuilder.HeaderBuilder(mHeaderUri).setTitle(title));
 
             CharSequence album = mMediaMetaData.getText(MediaMetadata.METADATA_KEY_ARTIST);
             if (!TextUtils.isEmpty(album)) {
-                listBuilder.addRow(new RowBuilder(mMediaUri).setTitle(album));
+                RowBuilder albumBuilder = new RowBuilder(mMediaUri);
+                albumBuilder.setTitle(album);
+
+                Icon mediaIcon = mMediaManager == null ? null : mMediaManager.getMediaIcon();
+                IconCompat mediaIconCompat = mediaIcon == null ? null
+                        : IconCompat.createFromIcon(getContext(), mediaIcon);
+                if (mediaIconCompat != null) {
+                    albumBuilder.addEndItem(mediaIconCompat, ListBuilder.ICON_IMAGE);
+                }
+
+                listBuilder.addRow(albumBuilder);
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSCarrierGroup.java b/packages/SystemUI/src/com/android/systemui/qs/QSCarrierGroup.java
index 0eeaa9b..7de8b74 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSCarrierGroup.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSCarrierGroup.java
@@ -139,43 +139,49 @@
 
     @Override
     public void updateCarrierInfo(CarrierTextController.CarrierTextCallbackInfo info) {
-        if (info.anySimReady) {
-            boolean[] slotSeen = new boolean[SIM_SLOTS];
-            if (info.listOfCarriers.length == info.subscriptionIds.length) {
-                for (int i = 0; i < SIM_SLOTS && i < info.listOfCarriers.length; i++) {
-                    int slot = getSlotIndex(info.subscriptionIds[i]);
-                    if (slot >= SIM_SLOTS) {
-                        Log.w(TAG, "updateInfoCarrier - slot: " + slot);
-                        continue;
+        if (info.airplaneMode) {
+            setVisibility(View.GONE);
+        } else {
+            setVisibility(View.VISIBLE);
+            if (info.anySimReady) {
+                boolean[] slotSeen = new boolean[SIM_SLOTS];
+                if (info.listOfCarriers.length == info.subscriptionIds.length) {
+                    for (int i = 0; i < SIM_SLOTS && i < info.listOfCarriers.length; i++) {
+                        int slot = getSlotIndex(info.subscriptionIds[i]);
+                        if (slot >= SIM_SLOTS) {
+                            Log.w(TAG, "updateInfoCarrier - slot: " + slot);
+                            continue;
+                        }
+                        if (slot == SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
+                            Log.e(TAG,
+                                    "Invalid SIM slot index for subscription: "
+                                            + info.subscriptionIds[i]);
+                            continue;
+                        }
+                        mInfos[slot].visible = true;
+                        slotSeen[slot] = true;
+                        mCarrierGroups[slot].setCarrierText(
+                                info.listOfCarriers[i].toString().trim());
+                        mCarrierGroups[slot].setVisibility(View.VISIBLE);
                     }
-                    if (slot == SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
-                        Log.e(TAG,
-                                "Invalid SIM slot index for subscription: "
-                                        + info.subscriptionIds[i]);
-                        continue;
+                    for (int i = 0; i < SIM_SLOTS; i++) {
+                        if (!slotSeen[i]) {
+                            mInfos[i].visible = false;
+                            mCarrierGroups[i].setVisibility(View.GONE);
+                        }
                     }
-                    mInfos[slot].visible = true;
-                    slotSeen[slot] = true;
-                    mCarrierGroups[slot].setCarrierText(info.listOfCarriers[i].toString().trim());
-                    mCarrierGroups[slot].setVisibility(View.VISIBLE);
-                }
-                for (int i = 0; i < SIM_SLOTS; i++) {
-                    if (!slotSeen[i]) {
-                        mInfos[i].visible = false;
-                        mCarrierGroups[i].setVisibility(View.GONE);
-                    }
+                } else {
+                    Log.e(TAG, "Carrier information arrays not of same length");
                 }
             } else {
-                Log.e(TAG, "Carrier information arrays not of same length");
-            }
-        } else {
-            mInfos[0].visible = false;
-            mCarrierGroups[0].setCarrierText(info.carrierText);
-            mCarrierGroups[0].setVisibility(View.VISIBLE);
-            for (int i = 1; i < SIM_SLOTS; i++) {
-                mInfos[i].visible = false;
-                mCarrierGroups[i].setCarrierText("");
-                mCarrierGroups[i].setVisibility(View.GONE);
+                mInfos[0].visible = false;
+                mCarrierGroups[0].setCarrierText(info.carrierText);
+                mCarrierGroups[0].setVisibility(View.VISIBLE);
+                for (int i = 1; i < SIM_SLOTS; i++) {
+                    mInfos[i].visible = false;
+                    mCarrierGroups[i].setCarrierText("");
+                    mCarrierGroups[i].setVisibility(View.GONE);
+                }
             }
         }
         handleUpdateState();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
index 2e35f06..97f2dd0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
@@ -22,7 +22,6 @@
 import android.util.Log;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.ViewParent;
 
 import com.android.systemui.R;
 import com.android.systemui.bubbles.BubbleData;
@@ -120,7 +119,7 @@
         for (int i = 0; i < N; i++) {
             NotificationEntry ent = activeNotifications.get(i);
             if (ent.isRowDismissed() || ent.isRowRemoved()
-                    || (mBubbleData.getBubble(ent.key) != null && !ent.showInShadeWhenBubble())) {
+                    || (mBubbleData.hasBubbleWithKey(ent.key) && !ent.showInShadeWhenBubble())) {
                 // we don't want to update removed notifications because they could
                 // temporarily become children if they were isolated before.
                 continue;
diff --git a/packages/SystemUI/src/com/android/systemui/volume/CaptionsToggleImageButton.java b/packages/SystemUI/src/com/android/systemui/volume/CaptionsToggleImageButton.java
index 45fc756..1862ed3 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/CaptionsToggleImageButton.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/CaptionsToggleImageButton.java
@@ -22,6 +22,9 @@
 import android.view.GestureDetector;
 import android.view.MotionEvent;
 
+import androidx.core.view.ViewCompat;
+import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat;
+
 import com.android.keyguard.AlphaOptimizedImageButton;
 import com.android.systemui.R;
 
@@ -31,7 +34,7 @@
     private static final int[] OPTED_OUT_STATE = new int[] { R.attr.optedOut };
 
     private ConfirmedTapListener mConfirmedTapListener;
-    private boolean mComponentEnabled = false;
+    private boolean mCaptionsEnabled = false;
     private boolean mOptedOut = false;
 
     private GestureDetector mGestureDetector;
@@ -39,16 +42,14 @@
             new GestureDetector.SimpleOnGestureListener() {
         @Override
         public boolean onSingleTapConfirmed(MotionEvent e) {
-            if (mConfirmedTapListener != null) {
-                mConfirmedTapListener.onConfirmedTap();
-                return true;
-            }
-            return false;
+            return tryToSendTapConfirmedEvent();
         }
     };
 
     public CaptionsToggleImageButton(Context context, AttributeSet attrs) {
         super(context, attrs);
+        this.setContentDescription(
+                getContext().getString(R.string.volume_odi_captions_content_description));
     }
 
     @Override
@@ -66,16 +67,32 @@
         return state;
     }
 
-    Runnable setComponentEnabled(boolean isComponentEnabled) {
-        this.mComponentEnabled = isComponentEnabled;
+    Runnable setCaptionsEnabled(boolean areCaptionsEnabled) {
+        this.mCaptionsEnabled = areCaptionsEnabled;
 
-        return this.setImageResourceAsync(this.mComponentEnabled
+        ViewCompat.replaceAccessibilityAction(
+                this,
+                AccessibilityActionCompat.ACTION_CLICK,
+                mCaptionsEnabled
+                        ? getContext().getString(R.string.volume_odi_captions_hint_disable)
+                        : getContext().getString(R.string.volume_odi_captions_hint_enable),
+                (view, commandArguments) -> tryToSendTapConfirmedEvent());
+
+        return this.setImageResourceAsync(mCaptionsEnabled
                 ? R.drawable.ic_volume_odi_captions
                 : R.drawable.ic_volume_odi_captions_disabled);
     }
 
-    boolean getComponentEnabled() {
-        return this.mComponentEnabled;
+    private boolean tryToSendTapConfirmedEvent() {
+        if (mConfirmedTapListener != null) {
+            mConfirmedTapListener.onConfirmedTap();
+            return true;
+        }
+        return false;
+    }
+
+    boolean getCaptionsEnabled() {
+        return this.mCaptionsEnabled;
     }
 
     /** Sets whether or not the current stream has opted out of captions */
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 5095370..8d9c5a3 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -596,9 +596,9 @@
     }
 
     private void updateCaptionsIcon() {
-        boolean componentEnabled = mController.areCaptionsEnabled();
-        if (mODICaptionsIcon.getComponentEnabled() != componentEnabled) {
-            mHandler.post(mODICaptionsIcon.setComponentEnabled(componentEnabled));
+        boolean captionsEnabled = mController.areCaptionsEnabled();
+        if (mODICaptionsIcon.getCaptionsEnabled() != captionsEnabled) {
+            mHandler.post(mODICaptionsIcon.setCaptionsEnabled(captionsEnabled));
         }
 
         boolean isOptedOut = mController.isCaptionStreamOptedOut();
@@ -878,7 +878,6 @@
         }
 
         view.setContentDescription(mContext.getString(currStateResId));
-
         view.setAccessibilityDelegate(new AccessibilityDelegate() {
             public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
                 super.onInitializeAccessibilityNodeInfo(host, info);
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
index 8e061cc..df534d7 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/CarrierTextControllerTest.java
@@ -37,6 +37,7 @@
 import android.net.wifi.WifiManager;
 import android.os.Handler;
 import android.telephony.SubscriptionInfo;
+import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
@@ -81,6 +82,8 @@
     private ConnectivityManager mConnectivityManager;
     @Mock
     private TelephonyManager mTelephonyManager;
+    @Mock
+    private SubscriptionManager mSubscriptionManager;
     private CarrierTextController.CarrierTextCallbackInfo mCarrierTextCallbackInfo;
 
     private CarrierTextController mCarrierTextController;
@@ -94,6 +97,7 @@
         mContext.addMockSystemService(WifiManager.class, mWifiManager);
         mContext.addMockSystemService(ConnectivityManager.class, mConnectivityManager);
         mContext.addMockSystemService(TelephonyManager.class, mTelephonyManager);
+        mContext.addMockSystemService(SubscriptionManager.class, mSubscriptionManager);
         mDependency.injectMockDependency(WakefulnessLifecycle.class);
         mDependency.injectTestDependency(Dependency.MAIN_HANDLER,
                 new Handler(mTestableLooper.getLooper()));
@@ -169,6 +173,7 @@
         list.add(TEST_SUBSCRIPTION);
         when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(IccCardConstants.State.READY);
         when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list);
+        when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(list);
         mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
 
         ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor =
@@ -192,6 +197,7 @@
         list.add(TEST_SUBSCRIPTION_ROAMING);
         when(mKeyguardUpdateMonitor.getSimState(anyInt())).thenReturn(IccCardConstants.State.READY);
         when(mKeyguardUpdateMonitor.getSubscriptionInfo(anyBoolean())).thenReturn(list);
+        when(mSubscriptionManager.getActiveSubscriptionInfoList(anyBoolean())).thenReturn(list);
         mKeyguardUpdateMonitor.mServiceStates = new HashMap<>();
 
         ArgumentCaptor<CarrierTextController.CarrierTextCallbackInfo> captor =
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/clock/StretchAnalogClockControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/clock/AnalogClockControllerTest.java
similarity index 91%
rename from packages/SystemUI/tests/src/com/android/keyguard/clock/StretchAnalogClockControllerTest.java
rename to packages/SystemUI/tests/src/com/android/keyguard/clock/AnalogClockControllerTest.java
index 26fa62b..4bb2395 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/clock/StretchAnalogClockControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/clock/AnalogClockControllerTest.java
@@ -38,9 +38,9 @@
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @RunWithLooper
-public final class StretchAnalogClockControllerTest extends SysuiTestCase {
+public final class AnalogClockControllerTest extends SysuiTestCase {
 
-    private StretchAnalogClockController mClockController;
+    private AnalogClockController mClockController;
     @Mock SysuiColorExtractor mMockColorExtractor;
 
     @Before
@@ -49,7 +49,7 @@
 
         Resources res = getContext().getResources();
         LayoutInflater layoutInflater = LayoutInflater.from(getContext());
-        mClockController = new StretchAnalogClockController(res, layoutInflater,
+        mClockController = new AnalogClockController(res, layoutInflater,
                 mMockColorExtractor);
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
index 20f539b..40a5357 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -146,7 +146,7 @@
         when(mNotificationEntryManager.getNotificationData()).thenReturn(mNotificationData);
         when(mNotificationData.getChannel(mRow.getEntry().key)).thenReturn(mRow.getEntry().channel);
 
-        mBubbleData = new BubbleData();
+        mBubbleData = new BubbleData(mContext);
         mBubbleController = new TestableBubbleController(mContext, mStatusBarWindowController,
                 mBubbleData, mConfigurationController);
         mBubbleController.setBubbleStateChangeListener(mBubbleStateChangeListener);
@@ -177,25 +177,27 @@
     public void testRemoveBubble() {
         mBubbleController.updateBubble(mRow.getEntry());
         assertTrue(mBubbleController.hasBubbles());
-
+        verify(mNotificationEntryManager).updateNotifications();
         verify(mBubbleStateChangeListener).onHasBubblesChanged(true);
 
         mBubbleController.removeBubble(mRow.getEntry().key, BubbleController.DISMISS_USER_GESTURE);
         assertFalse(mStatusBarWindowController.getBubblesShowing());
         assertTrue(mRow.getEntry().isBubbleDismissed());
-        verify(mNotificationEntryManager).updateNotifications();
+        verify(mNotificationEntryManager, times(2)).updateNotifications();
         verify(mBubbleStateChangeListener).onHasBubblesChanged(false);
     }
 
     @Test
     public void testDismissStack() {
         mBubbleController.updateBubble(mRow.getEntry());
+        verify(mNotificationEntryManager, times(1)).updateNotifications();
         mBubbleController.updateBubble(mRow2.getEntry());
+        verify(mNotificationEntryManager, times(2)).updateNotifications();
         assertTrue(mBubbleController.hasBubbles());
 
         mBubbleController.dismissStack(BubbleController.DISMISS_USER_GESTURE);
         assertFalse(mStatusBarWindowController.getBubblesShowing());
-        verify(mNotificationEntryManager).updateNotifications();
+        verify(mNotificationEntryManager, times(3)).updateNotifications();
         assertTrue(mRow.getEntry().isBubbleDismissed());
         assertTrue(mRow2.getEntry().isBubbleDismissed());
     }
@@ -215,7 +217,7 @@
 
         // Expand the stack
         BubbleStackView stackView = mBubbleController.getStackView();
-        stackView.expandStack();
+        mBubbleController.expandStack();
         assertTrue(mBubbleController.isStackExpanded());
         verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().key);
         assertTrue(mStatusBarWindowController.getBubbleExpanded());
@@ -224,7 +226,7 @@
         assertFalse(mRow.getEntry().showInShadeWhenBubble());
 
         // Collapse
-        stackView.collapseStack();
+        mBubbleController.collapseStack();
         verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getEntry().key);
         assertFalse(mBubbleController.isStackExpanded());
         assertFalse(mStatusBarWindowController.getBubbleExpanded());
@@ -245,23 +247,24 @@
 
         // Expand
         BubbleStackView stackView = mBubbleController.getStackView();
-        stackView.expandStack();
+        mBubbleController.expandStack();
         assertTrue(mBubbleController.isStackExpanded());
-        verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getEntry().key);
+        verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().key);
 
-        // Last added is the one that is expanded
-        assertEquals(mRow2.getEntry(), stackView.getExpandedBubbleView().getEntry());
-        assertFalse(mRow2.getEntry().showInShadeWhenBubble());
-
-        // Switch which bubble is expanded
-        stackView.setExpandedBubble(mRow.getEntry());
+        // First added is the one that is expanded
         assertEquals(mRow.getEntry(), stackView.getExpandedBubbleView().getEntry());
         assertFalse(mRow.getEntry().showInShadeWhenBubble());
 
+        // Switch which bubble is expanded
+        mBubbleController.selectBubble(mRow2.getEntry().key);
+        stackView.setExpandedBubble(mRow2.getEntry());
+        assertEquals(mRow2.getEntry(), stackView.getExpandedBubbleView().getEntry());
+        assertFalse(mRow2.getEntry().showInShadeWhenBubble());
+
         // collapse for previous bubble
-        verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow2.getEntry().key);
+        verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getEntry().key);
         // expand for selected bubble
-        verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().key);
+        verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getEntry().key);
 
         // Collapse
         mBubbleController.collapseStack();
@@ -280,7 +283,7 @@
 
         // Expand
         BubbleStackView stackView = mBubbleController.getStackView();
-        stackView.expandStack();
+        mBubbleController.expandStack();
         assertTrue(mBubbleController.isStackExpanded());
         verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().key);
 
@@ -299,30 +302,30 @@
 
         // Expand
         BubbleStackView stackView = mBubbleController.getStackView();
-        stackView.expandStack();
+        mBubbleController.expandStack();
 
         assertTrue(mBubbleController.isStackExpanded());
-        verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getEntry().key);
+        verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().key);
 
-        // Last added is the one that is expanded
-        assertEquals(mRow2.getEntry(), stackView.getExpandedBubbleView().getEntry());
-        assertFalse(mRow2.getEntry().showInShadeWhenBubble());
+        // First added is the one that is expanded
+        assertEquals(mRow.getEntry(), stackView.getExpandedBubbleView().getEntry());
+        assertFalse(mRow.getEntry().showInShadeWhenBubble());
 
         // Dismiss currently expanded
         mBubbleController.removeBubble(stackView.getExpandedBubbleView().getKey(),
                 BubbleController.DISMISS_USER_GESTURE);
-        verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow2.getEntry().key);
+        verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getEntry().key);
 
         // Make sure next bubble is selected
-        assertEquals(mRow.getEntry(), stackView.getExpandedBubbleView().getEntry());
-        verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getEntry().key);
+        assertEquals(mRow2.getEntry(), stackView.getExpandedBubbleView().getEntry());
+        verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getEntry().key);
 
         // Dismiss that one
         mBubbleController.removeBubble(stackView.getExpandedBubbleView().getKey(),
                 BubbleController.DISMISS_USER_GESTURE);
 
         // Make sure state changes and collapse happens
-        verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getEntry().key);
+        verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow2.getEntry().key);
         verify(mBubbleStateChangeListener).onHasBubblesChanged(false);
         assertFalse(mBubbleController.hasBubbles());
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleStackViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleStackViewTest.java
index 801308f..da31134 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleStackViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleStackViewTest.java
@@ -48,7 +48,7 @@
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
-        mStackView = new BubbleStackView(mContext, new BubbleData(), null);
+        mStackView = new BubbleStackView(mContext, new BubbleData(getContext()), null);
         mBubble.entry = mNotifEntry;
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
index 63d42a7..c534de7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
@@ -24,6 +24,7 @@
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
 
 import android.app.AlarmManager;
 import android.content.ContentResolver;
@@ -102,6 +103,7 @@
     @Test
     public void onBindSlice_readsMedia() {
         MediaMetadata metadata = mock(MediaMetadata.class);
+        when(metadata.getText(any())).thenReturn("metadata");
         mProvider.onDozingChanged(true);
         mProvider.onMetadataChanged(metadata);
         mProvider.onBindSlice(mProvider.getUri());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
index 2172a12..3662c38 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
@@ -98,7 +98,7 @@
         mViewHierarchyManager = new NotificationViewHierarchyManager(mContext,
                 mLockscreenUserManager, mGroupManager, mVisualStabilityManager,
                 mock(StatusBarStateControllerImpl.class), mEntryManager,
-                () -> mShadeController, new BubbleData());
+                () -> mShadeController, new BubbleData(mContext));
         Dependency.get(InitController.class).executePostInitTasks();
         mViewHierarchyManager.setUpWithPresenter(mPresenter, mListContainer);
     }
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index fdc3567..a94d1dc 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -806,6 +806,17 @@
             mAugmentedAutofillState.injectAugmentedAutofillInfo(options, userId, packageName);
             return options;
         }
+
+        @Override
+        public boolean isAugmentedAutofillServiceForUser(int callingUid, int userId) {
+            synchronized (mLock) {
+                final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
+                if (service != null) {
+                    return service.isAugmentedAutofillServiceForUserLocked(callingUid);
+                }
+            }
+            return false;
+        }
     }
 
     /**
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 4bd6fbd..f1963b3 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -1165,6 +1165,11 @@
         return true;
     }
 
+    boolean isAugmentedAutofillServiceForUserLocked(int callingUid) {
+        return mRemoteAugmentedAutofillServiceInfo != null
+                && mRemoteAugmentedAutofillServiceInfo.applicationInfo.uid == callingUid;
+    }
+
     /**
      * Sets which packages and activities can trigger augmented autofill.
      *
diff --git a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
index adf5829..609904b 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
@@ -17,6 +17,7 @@
 package com.android.server.autofill;
 
 import static com.android.server.autofill.Helper.sDebug;
+import static com.android.server.autofill.Helper.sVerbose;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -99,7 +100,7 @@
         }
         try {
             if (state) {
-                mService.onConnected();
+                mService.onConnected(sDebug, sVerbose);
             } else {
                 mService.onDisconnected();
             }
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index fdc01e0..9e73684d 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -265,7 +265,7 @@
     // main reason being the cases where user tap HOME.
     // Right now it's completely destroying the UI, but we need to decide whether / how to
     // properly recover it later (for example, if the user switches back to the activity,
-    // should it be restored? Right not it kind of is, because Autofill's Session trigger a
+    // should it be restored? Right now it kind of is, because Autofill's Session trigger a
     // new FillRequest, which in turn triggers the Augmented Autofill request again)
     @GuardedBy("mLock")
     @Nullable
@@ -2755,9 +2755,6 @@
         viewState.setState(ViewState.STATE_TRIGGERED_AUGMENTED_AUTOFILL);
         final AutofillValue currentValue = viewState.getCurrentValue();
 
-        // TODO(b/111330312): we might need to add a new state in the AutofillManager to optimize
-        // further AFM -> AFMS calls.
-
         if (mAugmentedRequestsLogs == null) {
             mAugmentedRequestsLogs = new ArrayList<>();
         }
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index 447bd8c..03f2149 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -566,10 +566,6 @@
         // require frequent starting and stopping.
         mConstants.start();
 
-        // Set up the various sorts of package tracking we do
-        mFullBackupScheduleFile = new File(mBaseStateDir, "fb-schedule");
-        initPackageTracking();
-
         // Build our mapping of uid to backup client services.  This implicitly
         // schedules a backup pass on the Package Manager metadata the first
         // time anything needs to be backed up.
@@ -589,6 +585,10 @@
 
         // Power management
         mWakelock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "*backup*-" + userId);
+
+        // Set up the various sorts of package tracking we do
+        mFullBackupScheduleFile = new File(mBaseStateDir, "fb-schedule");
+        initPackageTracking();
     }
 
     void initializeBackupEnableState() {
@@ -744,6 +744,11 @@
         return mDataDir;
     }
 
+    @VisibleForTesting
+    BroadcastReceiver getPackageTrackingReceiver() {
+        return mBroadcastReceiver;
+    }
+
     @Nullable
     public DataChangedJournal getJournal() {
         return mJournal;
diff --git a/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java b/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java
index 593bb2c..35dfccf 100644
--- a/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java
+++ b/services/backup/java/com/android/server/backup/utils/AppBackupUtils.java
@@ -23,22 +23,20 @@
 import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
 
 import android.annotation.Nullable;
-import android.app.AppGlobals;
 import android.app.backup.BackupTransport;
 import android.content.pm.ApplicationInfo;
-import android.content.pm.IPackageManager;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.Signature;
 import android.content.pm.SigningInfo;
-import android.os.RemoteException;
 import android.os.UserHandle;
 import android.util.Slog;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.backup.IBackupTransport;
 import com.android.internal.util.ArrayUtils;
+import com.android.server.LocalServices;
 import com.android.server.backup.transport.TransportClient;
 
 import com.google.android.collect.Sets;
@@ -67,12 +65,13 @@
      * </ol>
      */
     public static boolean appIsEligibleForBackup(ApplicationInfo app, int userId) {
-        return appIsEligibleForBackup(app, AppGlobals.getPackageManager(), userId);
+        return appIsEligibleForBackup(
+                app, LocalServices.getService(PackageManagerInternal.class), userId);
     }
 
     @VisibleForTesting
-    static boolean appIsEligibleForBackup(ApplicationInfo app,
-        IPackageManager packageManager, int userId) {
+    static boolean appIsEligibleForBackup(
+            ApplicationInfo app, PackageManagerInternal packageManager, int userId) {
         // 1. their manifest states android:allowBackup="false"
         if ((app.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) == 0) {
             return false;
@@ -108,9 +107,9 @@
     /**
      * Returns whether an app is eligible for backup at runtime. That is, the app has to:
      * <ol>
-     *     <li>Return true for {@link #appIsEligibleForBackup(ApplicationInfo, PackageManager)}
+     *     <li>Return true for {@link #appIsEligibleForBackup(ApplicationInfo, int)}
      *     <li>Return false for {@link #appIsStopped(ApplicationInfo)}
-     *     <li>Return false for {@link #appIsDisabled(ApplicationInfo, PackageManager)}
+     *     <li>Return false for {@link #appIsDisabled(ApplicationInfo, int)}
      *     <li>Be eligible for the transport via
      *         {@link BackupTransport#isAppEligibleForBackup(PackageInfo, boolean)}
      * </ol>
@@ -149,19 +148,13 @@
 
     /** Avoid backups of 'disabled' apps. */
     static boolean appIsDisabled(ApplicationInfo app, int userId) {
-        return appIsDisabled(app, AppGlobals.getPackageManager(), userId);
+        return appIsDisabled(app, LocalServices.getService(PackageManagerInternal.class), userId);
     }
 
     @VisibleForTesting
-    static boolean appIsDisabled(ApplicationInfo app,
-        IPackageManager packageManager, int userId) {
-        int enabledSetting;
-        try {
-            enabledSetting = packageManager.getApplicationEnabledSetting(app.packageName, userId);
-        } catch (RemoteException e) {
-            Slog.e(TAG, "Failed to get application enabled setting: " + e);
-            return false;
-        }
+    static boolean appIsDisabled(
+            ApplicationInfo app, PackageManagerInternal packageManager, int userId) {
+        int enabledSetting = packageManager.getApplicationEnabledState(app.packageName, userId);
 
         switch (enabledSetting) {
             case PackageManager.COMPONENT_ENABLED_STATE_DISABLED:
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 382fdec..053e686 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -293,7 +293,6 @@
     private static final String TAG_VOLUMES = "volumes";
     private static final String ATTR_VERSION = "version";
     private static final String ATTR_PRIMARY_STORAGE_UUID = "primaryStorageUuid";
-    private static final String ATTR_ISOLATED_STORAGE = "isolatedStorage";
     private static final String TAG_VOLUME = "volume";
     private static final String ATTR_TYPE = "type";
     private static final String ATTR_FS_UUID = "fsUuid";
@@ -349,10 +348,6 @@
     @GuardedBy("mLock")
     private String mPrimaryStorageUuid;
 
-    /** Flag indicating isolated storage state of last boot */
-    @GuardedBy("mLock")
-    private boolean mLastIsolatedStorage = false;
-
     /** Map from disk ID to latches */
     @GuardedBy("mLock")
     private ArrayMap<String, CountDownLatch> mDiskScanLatches = new ArrayMap<>();
@@ -1074,6 +1069,15 @@
         mVold.onUserStarted(userId, packages, appIds, sandboxIds);
     }
 
+     private boolean supportsBlockCheckpoint() throws RemoteException {
+        // Only the system process is permitted to start checkpoints
+        if (Binder.getCallingUid() != android.os.Process.SYSTEM_UID) {
+            throw new SecurityException("no permission to check block based checkpoint support");
+        }
+
+        return mVold.supportsBlockCheckpoint();
+    }
+
     @Override
     public void onAwakeStateChanged(boolean isAwake) {
         // Ignored
@@ -1681,63 +1685,6 @@
             mIAppOpsService.startWatchingMode(OP_REQUEST_INSTALL_PACKAGES, null, mAppOpsCallback);
         } catch (RemoteException e) {
         }
-
-        synchronized (mLock) {
-            final boolean thisIsolatedStorage = StorageManager.hasIsolatedStorage();
-            if (mLastIsolatedStorage != thisIsolatedStorage) {
-                if (thisIsolatedStorage) {
-                    // This boot enables isolated storage; apply legacy behavior
-                    applyLegacyStorage();
-                }
-
-                // Always remember the new state we just booted with
-                writeSettingsLocked();
-            }
-        }
-    }
-
-    /**
-     * If we're enabling isolated storage, we need to remember which existing
-     * apps have already been using shared storage, and grant them legacy access
-     * to keep them running smoothly.
-     *
-     * @see com.android.server.pm.permission.PermissionManagerService
-     *      #applyLegacyStoragePermissionModel
-     */
-    private void applyLegacyStorage() {
-        final AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class);
-        final UserManagerInternal um = LocalServices.getService(UserManagerInternal.class);
-        for (int userId : um.getUserIds()) {
-            final UserHandle user = UserHandle.of(userId);
-            final PackageManager pm;
-            try {
-                pm = mContext.createPackageContextAsUser(mContext.getPackageName(), 0,
-                        user).getPackageManager();
-            } catch (PackageManager.NameNotFoundException e) {
-                throw new RuntimeException(e);
-            }
-
-            final List<PackageInfo> pkgs = pm.getPackagesHoldingPermissions(
-                    ALL_STORAGE_PERMISSIONS,
-                    MATCH_UNINSTALLED_PACKAGES | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE
-                            | GET_PERMISSIONS);
-            for (PackageInfo pkg : pkgs) {
-                final int uid = pkg.applicationInfo.uid;
-                final String packageName = pkg.applicationInfo.packageName;
-
-                final long lastAccess = getLastAccessTime(appOps, uid, packageName, new int[] {
-                        AppOpsManager.OP_READ_EXTERNAL_STORAGE,
-                        AppOpsManager.OP_WRITE_EXTERNAL_STORAGE,
-                });
-
-                Log.d(TAG, "Found " + uid + " " + packageName
-                        + " with granted storage access, last accessed " + lastAccess);
-                if (lastAccess > 0) {
-                    appOps.setUidMode(AppOpsManager.OP_LEGACY_STORAGE, uid,
-                            AppOpsManager.MODE_ALLOWED);
-                }
-            }
-        }
     }
 
     private static long getLastAccessTime(AppOpsManager manager,
@@ -1783,7 +1730,6 @@
     private void readSettingsLocked() {
         mRecords.clear();
         mPrimaryStorageUuid = getDefaultPrimaryStorageUuid();
-        mLastIsolatedStorage = false;
 
         FileInputStream fis = null;
         try {
@@ -1805,9 +1751,6 @@
                             mPrimaryStorageUuid = readStringAttribute(in,
                                     ATTR_PRIMARY_STORAGE_UUID);
                         }
-                        mLastIsolatedStorage = readBooleanAttribute(in,
-                                ATTR_ISOLATED_STORAGE, false);
-
                     } else if (TAG_VOLUME.equals(tag)) {
                         final VolumeRecord rec = readVolumeRecord(in);
                         mRecords.put(rec.fsUuid, rec);
@@ -1837,7 +1780,6 @@
             out.startTag(null, TAG_VOLUMES);
             writeIntAttribute(out, ATTR_VERSION, VERSION_FIX_PRIMARY);
             writeStringAttribute(out, ATTR_PRIMARY_STORAGE_UUID, mPrimaryStorageUuid);
-            writeBooleanAttribute(out, ATTR_ISOLATED_STORAGE, StorageManager.hasIsolatedStorage());
             final int size = mRecords.size();
             for (int i = 0; i < size; i++) {
                 final VolumeRecord rec = mRecords.valueAt(i);
@@ -2116,37 +2058,45 @@
         enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
 
         try {
-            mVold.fstrim(flags, new IVoldTaskListener.Stub() {
-                @Override
-                public void onStatus(int status, PersistableBundle extras) {
-                    dispatchOnStatus(listener, status, extras);
+            // Block based checkpoint process runs fstrim. So, if checkpoint is in progress
+            // (first boot after OTA), We skip idle maintenance and make sure the last
+            // fstrim time is still updated. If file based checkpoints are used, we run
+            // idle maintenance (GC + fstrim) regardless of checkpoint status.
+            if (!needsCheckpoint() || !supportsBlockCheckpoint()) {
+                mVold.fstrim(flags, new IVoldTaskListener.Stub() {
+                    @Override
+                    public void onStatus(int status, PersistableBundle extras) {
+                        dispatchOnStatus(listener, status, extras);
 
-                    // Ignore trim failures
-                    if (status != 0) return;
+                        // Ignore trim failures
+                        if (status != 0) return;
 
-                    final String path = extras.getString("path");
-                    final long bytes = extras.getLong("bytes");
-                    final long time = extras.getLong("time");
+                        final String path = extras.getString("path");
+                        final long bytes = extras.getLong("bytes");
+                        final long time = extras.getLong("time");
 
-                    final DropBoxManager dropBox = mContext.getSystemService(DropBoxManager.class);
-                    dropBox.addText(TAG_STORAGE_TRIM, scrubPath(path) + " " + bytes + " " + time);
+                        final DropBoxManager dropBox = mContext.getSystemService(DropBoxManager.class);
+                        dropBox.addText(TAG_STORAGE_TRIM, scrubPath(path) + " " + bytes + " " + time);
 
-                    synchronized (mLock) {
-                        final VolumeRecord rec = findRecordForPath(path);
-                        if (rec != null) {
-                            rec.lastTrimMillis = System.currentTimeMillis();
-                            writeSettingsLocked();
+                        synchronized (mLock) {
+                            final VolumeRecord rec = findRecordForPath(path);
+                            if (rec != null) {
+                                rec.lastTrimMillis = System.currentTimeMillis();
+                                writeSettingsLocked();
+                            }
                         }
                     }
-                }
 
-                @Override
-                public void onFinished(int status, PersistableBundle extras) {
-                    dispatchOnFinished(listener, status, extras);
+                    @Override
+                    public void onFinished(int status, PersistableBundle extras) {
+                        dispatchOnFinished(listener, status, extras);
 
-                    // TODO: benchmark when desired
-                }
-            });
+                        // TODO: benchmark when desired
+                    }
+                });
+            } else {
+                Slog.i(TAG, "Skipping fstrim - block based checkpoint in progress");
+            }
         } catch (RemoteException e) {
             throw e.rethrowAsRuntimeException();
         }
@@ -2156,18 +2106,26 @@
         enforcePermission(android.Manifest.permission.MOUNT_FORMAT_FILESYSTEMS);
 
         try {
-            mVold.runIdleMaint(new IVoldTaskListener.Stub() {
-                @Override
-                public void onStatus(int status, PersistableBundle extras) {
-                    // Not currently used
-                }
-                @Override
-                public void onFinished(int status, PersistableBundle extras) {
-                    if (callback != null) {
-                        BackgroundThread.getHandler().post(callback);
+            // Block based checkpoint process runs fstrim. So, if checkpoint is in progress
+            // (first boot after OTA), We skip idle maintenance and make sure the last
+            // fstrim time is still updated. If file based checkpoints are used, we run
+            // idle maintenance (GC + fstrim) regardless of checkpoint status.
+            if (!needsCheckpoint() || !supportsBlockCheckpoint()) {
+                mVold.runIdleMaint(new IVoldTaskListener.Stub() {
+                    @Override
+                    public void onStatus(int status, PersistableBundle extras) {
+                        // Not currently used
                     }
-                }
-            });
+                    @Override
+                    public void onFinished(int status, PersistableBundle extras) {
+                        if (callback != null) {
+                            BackgroundThread.getHandler().post(callback);
+                        }
+                    }
+                });
+            } else {
+                Slog.i(TAG, "Skipping idle maintenance - block based checkpoint in progress");
+            }
         } catch (Exception e) {
             Slog.wtf(TAG, e);
         }
@@ -3766,7 +3724,7 @@
                 return Zygote.MOUNT_EXTERNAL_NONE;
             }
             if (mPmInternal.isInstantApp(packageName, UserHandle.getUserId(uid))) {
-                return Zygote.MOUNT_EXTERNAL_NONE;
+                return Zygote.MOUNT_EXTERNAL_DEFAULT;
             }
 
             // Determine if caller is holding runtime permission
@@ -3800,11 +3758,7 @@
             // they hold the runtime permission
             final boolean hasLegacy = mIAppOpsService.checkOperation(OP_LEGACY_STORAGE,
                     uid, packageName) == MODE_ALLOWED;
-            // STOPSHIP: only use app-op once permission model has fully landed
-            final boolean requestedLegacy = !mIPackageManager
-                    .getApplicationInfo(packageName, 0, UserHandle.getUserId(uid))
-                    .isExternalStorageSandboxAllowed();
-            if ((hasLegacy || requestedLegacy) && hasStorage) {
+            if (hasLegacy && hasStorage) {
                 return Zygote.MOUNT_EXTERNAL_LEGACY;
             } else {
                 return Zygote.MOUNT_EXTERNAL_WRITE;
diff --git a/services/core/java/com/android/server/SystemServerInitThreadPool.java b/services/core/java/com/android/server/SystemServerInitThreadPool.java
index 6bb3200..1ce65561 100644
--- a/services/core/java/com/android/server/SystemServerInitThreadPool.java
+++ b/services/core/java/com/android/server/SystemServerInitThreadPool.java
@@ -120,7 +120,7 @@
     private static void dumpStackTraces() {
         final ArrayList<Integer> pids = new ArrayList<>();
         pids.add(Process.myPid());
-        ActivityManagerService.dumpStackTraces(
-                pids, null, null, null);
+        ActivityManagerService.dumpStackTraces(pids, null, null,
+                Watchdog.getInterestingNativePids());
     }
 }
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index afcf954..cc3b43a 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -101,17 +101,18 @@
     };
 
     public static final List<String> HAL_INTERFACES_OF_INTEREST = Arrays.asList(
-        "android.hardware.audio@2.0::IDevicesFactory",
-        "android.hardware.audio@4.0::IDevicesFactory",
-        "android.hardware.bluetooth@1.0::IBluetoothHci",
-        "android.hardware.camera.provider@2.4::ICameraProvider",
-        "android.hardware.graphics.allocator@2.0::IAllocator",
-        "android.hardware.graphics.composer@2.1::IComposer",
-        "android.hardware.health@2.0::IHealth",
-        "android.hardware.media.omx@1.0::IOmx",
-        "android.hardware.media.omx@1.0::IOmxStore",
-        "android.hardware.sensors@1.0::ISensors",
-        "android.hardware.vr@1.0::IVr"
+            "android.hardware.audio@2.0::IDevicesFactory",
+            "android.hardware.audio@4.0::IDevicesFactory",
+            "android.hardware.bluetooth@1.0::IBluetoothHci",
+            "android.hardware.camera.provider@2.4::ICameraProvider",
+            "android.hardware.graphics.allocator@2.0::IAllocator",
+            "android.hardware.graphics.composer@2.1::IComposer",
+            "android.hardware.health@2.0::IHealth",
+            "android.hardware.media.omx@1.0::IOmx",
+            "android.hardware.media.omx@1.0::IOmxStore",
+            "android.hardware.sensors@1.0::ISensors",
+            "android.hardware.vr@1.0::IVr",
+            "android.hardware.biometrics.face@1.0::IBiometricsFace"
     );
 
     static Watchdog sWatchdog;
@@ -396,7 +397,7 @@
         return builder.toString();
     }
 
-    private ArrayList<Integer> getInterestingHalPids() {
+    private static ArrayList<Integer> getInterestingHalPids() {
         try {
             IServiceManager serviceManager = IServiceManager.getService();
             ArrayList<IServiceManager.InstanceDebugInfo> dump =
@@ -419,7 +420,7 @@
         }
     }
 
-    private ArrayList<Integer> getInterestingNativePids() {
+    static ArrayList<Integer> getInterestingNativePids() {
         ArrayList<Integer> pids = getInterestingHalPids();
 
         int[] nativePids = Process.getPidsForCommands(NATIVE_STACKS_OF_INTEREST);
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 4ec90ba..0271354 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -1806,7 +1806,7 @@
                                 || (callerApp.getCurProcState() <= ActivityManager.PROCESS_STATE_TOP
                                         && (flags & Context.BIND_TREAT_LIKE_ACTIVITY) != 0),
                         b.client);
-                mAm.updateOomAdjLocked();
+                mAm.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_BIND_SERVICE);
             }
 
             if (DEBUG_SERVICE) Slog.v(TAG_SERVICE, "Bind " + s + " with " + b
@@ -1957,11 +1957,12 @@
                                 r.binding.service.app.hasClientActivities()
                                 || r.binding.service.app.treatLikeActivity, null);
                     }
-                    mAm.updateOomAdjLocked(r.binding.service.app, false);
+                    mAm.updateOomAdjLocked(r.binding.service.app, false,
+                            OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE);
                 }
             }
 
-            mAm.updateOomAdjLocked();
+            mAm.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE);
 
         } finally {
             Binder.restoreCallingIdentity(origId);
@@ -2676,7 +2677,7 @@
         bumpServiceExecutingLocked(r, execInFg, "create");
         mAm.updateLruProcessLocked(app, false, null);
         updateServiceForegroundLocked(r.app, /* oomAdj= */ false);
-        mAm.updateOomAdjLocked();
+        mAm.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_START_SERVICE);
 
         boolean created = false;
         try {
@@ -2797,7 +2798,7 @@
             bumpServiceExecutingLocked(r, execInFg, "start");
             if (!oomAdjusted) {
                 oomAdjusted = true;
-                mAm.updateOomAdjLocked(r.app, true);
+                mAm.updateOomAdjLocked(r.app, true, OomAdjuster.OOM_ADJ_REASON_START_SERVICE);
             }
             if (r.fgRequired && !r.fgWaiting) {
                 if (!r.isForeground) {
@@ -2923,7 +2924,8 @@
                 if (ibr.hasBound) {
                     try {
                         bumpServiceExecutingLocked(r, false, "bring down unbind");
-                        mAm.updateOomAdjLocked(r.app, true);
+                        mAm.updateOomAdjLocked(r.app, true,
+                                OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE);
                         ibr.hasBound = false;
                         ibr.requested = false;
                         r.app.thread.scheduleUnbindService(r,
@@ -3038,7 +3040,8 @@
                     bumpServiceExecutingLocked(r, false, "destroy");
                     mDestroyingServices.add(r);
                     r.destroying = true;
-                    mAm.updateOomAdjLocked(r.app, true);
+                    mAm.updateOomAdjLocked(r.app, true,
+                            OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE);
                     r.app.thread.scheduleStopService(r);
                 } catch (Exception e) {
                     Slog.w(TAG, "Exception when destroying service "
@@ -3143,7 +3146,8 @@
                         // it to go down there and we want it to start out near the top.
                         mAm.updateLruProcessLocked(s.app, false, null);
                     }
-                    mAm.updateOomAdjLocked(s.app, true);
+                    mAm.updateOomAdjLocked(s.app, true,
+                            OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE);
                     b.intent.hasBound = false;
                     // Assume the client doesn't want to know about a rebind;
                     // we will deal with that later if it asks for one.
@@ -3296,7 +3300,7 @@
                     mDestroyingServices.remove(r);
                     r.bindings.clear();
                 }
-                mAm.updateOomAdjLocked(r.app, true);
+                mAm.updateOomAdjLocked(r.app, true, OomAdjuster.OOM_ADJ_REASON_UNBIND_SERVICE);
             }
             r.executeFg = false;
             if (r.tracker != null) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 3b6b404..cdcd9e1 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -1972,7 +1972,7 @@
                 app.makeActive(mSystemThread.getApplicationThread(), mProcessStats);
                 mPidsSelfLocked.put(app.pid, app);
                 mProcessList.updateLruProcessLocked(app, false, null);
-                updateOomAdjLocked();
+                updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE);
             }
         } catch (PackageManager.NameNotFoundException e) {
             throw new RuntimeException(
@@ -2456,7 +2456,7 @@
         // bind background threads to little cores
         // this is expected to fail inside of framework tests because apps can't touch cpusets directly
         // make sure we've already adjusted system_server's internal view of itself first
-        updateOomAdjLocked();
+        updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE);
         try {
             Process.setThreadGroupAndCpuset(BackgroundThread.get().getThreadId(),
                     Process.THREAD_GROUP_SYSTEM);
@@ -3634,7 +3634,7 @@
             handleAppDiedLocked(app, false, true);
 
             if (doOomAdj) {
-                updateOomAdjLocked();
+                updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_PROCESS_END);
             }
             if (doLowMem) {
                 doLowMemReportIfNeededLocked(app);
@@ -5002,7 +5002,7 @@
         }
 
         if (!didSomething) {
-            updateOomAdjLocked();
+            updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_PROCESS_BEGIN);
             checkTime(startTime, "attachApplicationLocked: after updateOomAdjLocked");
         }
 
@@ -5485,7 +5485,7 @@
         synchronized (this) {
             mConstants.setOverrideMaxCachedProcesses(max);
         }
-        trimApplications();
+        trimApplications(OomAdjuster.OOM_ADJ_REASON_PROCESS_END);
     }
 
     @Override
@@ -5511,7 +5511,7 @@
                 pr.forcingToImportant = null;
                 updateProcessForegroundLocked(pr, false, 0, false);
             }
-            updateOomAdjLocked();
+            updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_UI_VISIBILITY);
         }
     }
 
@@ -5557,7 +5557,7 @@
             }
 
             if (changed) {
-                updateOomAdjLocked();
+                updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_UI_VISIBILITY);
             }
         }
     }
@@ -6714,7 +6714,8 @@
 
                 checkTime(startTime, "getContentProviderImpl: before updateOomAdj");
                 final int verifiedAdj = cpr.proc.verifiedAdj;
-                boolean success = updateOomAdjLocked(cpr.proc, true);
+                boolean success = updateOomAdjLocked(cpr.proc, true,
+                        OomAdjuster.OOM_ADJ_REASON_GET_PROVIDER);
                 // XXX things have changed so updateOomAdjLocked doesn't actually tell us
                 // if the process has been successfully adjusted.  So to reduce races with
                 // it, we will check whether the process still exists.  Note that this doesn't
@@ -7147,7 +7148,7 @@
                     throw new NullPointerException("connection is null");
                 }
                 if (decProviderCountLocked(conn, null, null, stable)) {
-                    updateOomAdjLocked();
+                    updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_REMOVE_PROVIDER);
                 }
             }
         } finally {
@@ -7188,7 +7189,7 @@
             ContentProviderRecord localCpr = mProviderMap.getProviderByClass(comp, userId);
             if (localCpr.hasExternalProcessHandles()) {
                 if (localCpr.removeExternalProcessHandleLocked(token)) {
-                    updateOomAdjLocked();
+                    updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_REMOVE_PROVIDER);
                 } else {
                     Slog.e(TAG, "Attmpt to remove content provider " + localCpr
                             + " with no external reference for token: "
@@ -7255,7 +7256,7 @@
                         dst.setProcess(r);
                         dst.notifyAll();
                     }
-                    updateOomAdjLocked(r, true);
+                    updateOomAdjLocked(r, true, OomAdjuster.OOM_ADJ_REASON_GET_PROVIDER);
                     maybeUpdateProviderUsageStatsLocked(r, src.info.packageName,
                             src.info.authority);
                 }
@@ -7645,7 +7646,7 @@
                     new HostingRecord("added application",
                             customProcess != null ? customProcess : info.processName));
             mProcessList.updateLruProcessLocked(app, false, null);
-            updateOomAdjLocked();
+            updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_PROCESS_BEGIN);
         }
 
         // This package really, really can not be stopped.
@@ -7740,7 +7741,7 @@
                 mActivityTaskManager.onScreenAwakeChanged(isAwake);
                 mOomAdjProfiler.onWakefulnessChanged(wakefulness);
             }
-            updateOomAdjLocked();
+            updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_UI_VISIBILITY);
         }
     }
 
@@ -8320,7 +8321,7 @@
                     }
                 }
                 if (changed) {
-                    updateOomAdjLocked(pr, true);
+                    updateOomAdjLocked(pr, true, OomAdjuster.OOM_ADJ_REASON_UI_VISIBILITY);
                 }
             }
         } finally {
@@ -8350,7 +8351,7 @@
                 Slog.i(TAG, "Setting runningRemoteAnimation=" + pr.runningRemoteAnimation
                         + " for pid=" + pid);
             }
-            updateOomAdjLocked(pr, true);
+            updateOomAdjLocked(pr, true, OomAdjuster.OOM_ADJ_REASON_UI_VISIBILITY);
         }
     }
 
@@ -13984,7 +13985,7 @@
             mBackupTargets.put(targetUserId, r);
 
             // Try not to kill the process during backup
-            updateOomAdjLocked(proc, true);
+            updateOomAdjLocked(proc, true, OomAdjuster.OOM_ADJ_REASON_NONE);
 
             // If the process is already attached, schedule the creation of the backup agent now.
             // If it is not yet live, this will be done when it attaches to the framework.
@@ -14099,7 +14100,7 @@
 
                 // Not backing this app up any more; reset its OOM adjustment
                 final ProcessRecord proc = backupTarget.app;
-                updateOomAdjLocked(proc, true);
+                updateOomAdjLocked(proc, true, OomAdjuster.OOM_ADJ_REASON_NONE);
                 proc.inFullBackup = false;
 
                 oldBackupUid = backupTarget != null ? backupTarget.appInfo.uid : -1;
@@ -14388,7 +14389,7 @@
             // If we actually concluded any broadcasts, we might now be able
             // to trim the recipients' apps from our working set
             if (doTrim) {
-                trimApplications();
+                trimApplications(OomAdjuster.OOM_ADJ_REASON_FINISH_RECEIVER);
                 return;
             }
 
@@ -15463,7 +15464,7 @@
                     r.queue.processNextBroadcastLocked(/*fromMsg=*/ false, /*skipOomAdj=*/ true);
                 }
                 // updateOomAdjLocked() will be done here
-                trimApplicationsLocked();
+                trimApplicationsLocked(OomAdjuster.OOM_ADJ_REASON_FINISH_RECEIVER);
             }
 
         } finally {
@@ -16448,7 +16449,7 @@
             item.foregroundServiceTypes = fgServiceTypes;
 
             if (oomAdj) {
-                updateOomAdjLocked();
+                updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_UI_VISIBILITY);
             }
         }
     }
@@ -16496,11 +16497,13 @@
      * @param app The process to update
      * @param oomAdjAll If it's ok to call updateOomAdjLocked() for all running apps
      *                  if necessary, or skip.
+     * @param oomAdjReason
      * @return whether updateOomAdjLocked(app) was successful.
      */
     @GuardedBy("this")
-    final boolean updateOomAdjLocked(ProcessRecord app, boolean oomAdjAll) {
-        return mOomAdjuster.updateOomAdjLocked(app, oomAdjAll);
+    final boolean updateOomAdjLocked(ProcessRecord app, boolean oomAdjAll,
+            String oomAdjReason) {
+        return mOomAdjuster.updateOomAdjLocked(app, oomAdjAll, oomAdjReason);
     }
 
     static final class ProcStatsRunnable implements Runnable {
@@ -16693,8 +16696,8 @@
     }
 
     @GuardedBy("this")
-    final void updateOomAdjLocked() {
-        mOomAdjuster.updateOomAdjLocked();
+    final void updateOomAdjLocked(String oomAdjReason) {
+        mOomAdjuster.updateOomAdjLocked(oomAdjReason);
     }
 
     @Override
@@ -16979,14 +16982,14 @@
         mOomAdjuster.setUidTempWhitelistStateLocked(uid, onWhitelist);
     }
 
-    final void trimApplications() {
+    final void trimApplications(String oomAdjReason) {
         synchronized (this) {
-            trimApplicationsLocked();
+            trimApplicationsLocked(oomAdjReason);
         }
     }
 
     @GuardedBy("this")
-    final void trimApplicationsLocked() {
+    final void trimApplicationsLocked(String oomAdjReason) {
         // First remove any unused application processes whose package
         // has been removed.
         for (int i = mProcessList.mRemovedProcesses.size() - 1; i >= 0; i--) {
@@ -17018,7 +17021,7 @@
 
         // Now update the oom adj for all processes. Don't skip this, since other callers
         // might be depending on it.
-        updateOomAdjLocked();
+        updateOomAdjLocked(oomAdjReason);
     }
 
     /** This method sends the specified signal to each of the persistent apps */
@@ -17627,7 +17630,7 @@
                 }
                 pr.setHasOverlayUi(hasOverlayUi);
                 //Slog.i(TAG, "Setting hasOverlayUi=" + pr.hasOverlayUi + " for pid=" + pid);
-                updateOomAdjLocked(pr, true);
+                updateOomAdjLocked(pr, true, OomAdjuster.OOM_ADJ_REASON_UI_VISIBILITY);
             }
         }
 
@@ -17784,7 +17787,7 @@
 
         @Override
         public void trimApplications() {
-            ActivityManagerService.this.trimApplications();
+            ActivityManagerService.this.trimApplications(OomAdjuster.OOM_ADJ_REASON_ACTIVITY);
         }
 
         public void killProcessesForRemovedTask(ArrayList<Object> procsToKill) {
@@ -17836,7 +17839,7 @@
         @Override
         public void updateOomAdj() {
             synchronized (ActivityManagerService.this) {
-                ActivityManagerService.this.updateOomAdjLocked();
+                ActivityManagerService.this.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE);
             }
         }
 
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 3c57c3b..ee9b561 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -309,7 +309,7 @@
         app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_RECEIVER);
         mService.mProcessList.updateLruProcessLocked(app, false, null);
         if (!skipOomAdj) {
-            mService.updateOomAdjLocked();
+            mService.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_NONE);
         }
 
         // Tell the application to launch this receiver.
@@ -791,7 +791,8 @@
                 // are already core system stuff so don't matter for this.
                 r.curApp = filter.receiverList.app;
                 filter.receiverList.app.curReceivers.add(r);
-                mService.updateOomAdjLocked(r.curApp, true);
+                mService.updateOomAdjLocked(r.curApp, true,
+                        OomAdjuster.OOM_ADJ_REASON_START_RECEIVER);
             }
         }
         try {
@@ -1028,7 +1029,7 @@
                     // If we had finished the last ordered broadcast, then
                     // make sure all processes have correct oom and sched
                     // adjustments.
-                    mService.updateOomAdjLocked();
+                    mService.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_START_RECEIVER);
                 }
 
                 // when we have no more ordered broadcast on this queue, stop logging
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 44d435f..8ae7c7d 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -90,6 +90,21 @@
 public final class OomAdjuster {
     private static final String TAG = "OomAdjuster";
 
+    static final String OOM_ADJ_REASON_METHOD = "updateOomAdj";
+    static final String OOM_ADJ_REASON_NONE = OOM_ADJ_REASON_METHOD + "_meh";
+    static final String OOM_ADJ_REASON_ACTIVITY = OOM_ADJ_REASON_METHOD + "_activityChange";
+    static final String OOM_ADJ_REASON_FINISH_RECEIVER = OOM_ADJ_REASON_METHOD + "_finishReceiver";
+    static final String OOM_ADJ_REASON_START_RECEIVER = OOM_ADJ_REASON_METHOD + "_startReceiver";
+    static final String OOM_ADJ_REASON_BIND_SERVICE = OOM_ADJ_REASON_METHOD + "_bindService";
+    static final String OOM_ADJ_REASON_UNBIND_SERVICE = OOM_ADJ_REASON_METHOD + "_unbindService";
+    static final String OOM_ADJ_REASON_START_SERVICE = OOM_ADJ_REASON_METHOD + "_startService";
+    static final String OOM_ADJ_REASON_GET_PROVIDER = OOM_ADJ_REASON_METHOD + "_getProvider";
+    static final String OOM_ADJ_REASON_REMOVE_PROVIDER = OOM_ADJ_REASON_METHOD + "_removeProvider";
+    static final String OOM_ADJ_REASON_UI_VISIBILITY = OOM_ADJ_REASON_METHOD + "_uiVisibility";
+    static final String OOM_ADJ_REASON_WHITELIST = OOM_ADJ_REASON_METHOD + "_whitelistChange";
+    static final String OOM_ADJ_REASON_PROCESS_BEGIN = OOM_ADJ_REASON_METHOD + "_processBegin";
+    static final String OOM_ADJ_REASON_PROCESS_END = OOM_ADJ_REASON_METHOD + "_processEnd";
+
     /**
      * For some direct access we need to power manager.
      */
@@ -156,10 +171,12 @@
      * @param app The process to update
      * @param oomAdjAll If it's ok to call updateOomAdjLocked() for all running apps
      *                  if necessary, or skip.
+     * @param oomAdjReason
      * @return whether updateOomAdjLocked(app) was successful.
      */
     @GuardedBy("mService")
-    final boolean updateOomAdjLocked(ProcessRecord app, boolean oomAdjAll) {
+    boolean updateOomAdjLocked(ProcessRecord app, boolean oomAdjAll,
+            String oomAdjReason) {
         final ProcessRecord TOP_APP = mService.getTopAppLocked();
         final boolean wasCached = app.cached;
 
@@ -177,7 +194,7 @@
                 && (wasCached != app.cached || app.getCurRawAdj() == ProcessList.UNKNOWN_ADJ)) {
             // Changed to/from cached state, so apps after it in the LRU
             // list may also be changed.
-            updateOomAdjLocked();
+            updateOomAdjLocked(oomAdjReason);
         }
         return success;
     }
@@ -195,8 +212,8 @@
     }
 
     @GuardedBy("mService")
-    final void updateOomAdjLocked() {
-        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "updateOomAdj");
+    void updateOomAdjLocked(String oomAdjReason) {
+        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, oomAdjReason);
         mService.mOomAdjProfiler.oomAdjStarted();
         final ProcessRecord TOP_APP = mService.getTopAppLocked();
         final long now = SystemClock.uptimeMillis();
@@ -2009,7 +2026,7 @@
             }
         }
         if (changed) {
-            updateOomAdjLocked();
+            updateOomAdjLocked(OOM_ADJ_REASON_WHITELIST);
         }
     }
 
@@ -2019,7 +2036,7 @@
         final UidRecord uidRec = mActiveUids.get(uid);
         if (uidRec != null && uidRec.curWhitelist != onWhitelist) {
             uidRec.curWhitelist = onWhitelist;
-            updateOomAdjLocked();
+            updateOomAdjLocked(OOM_ADJ_REASON_WHITELIST);
         }
     }
 
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index a08c829..588e05d 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -29,6 +29,7 @@
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.IBinder;
+import android.os.Process;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.TransactionTooLargeException;
@@ -380,8 +381,9 @@
                 userId = controller.mUserController.getCurrentOrTargetUserId();
             }
             // temporarily allow receivers and services to open activities from background if the
-            // PendingIntent.send() caller was foreground at the time of sendInner() call
-            final boolean allowTrampoline = uid != callingUid
+            // PendingIntent.send() caller was foreground at the time of sendInner() call, unless
+            // caller is SYSTEM_UID
+            final boolean allowTrampoline = uid != callingUid && callingUid != Process.SYSTEM_UID
                     && controller.mAtmInternal.isUidForeground(callingUid);
 
             // note: we on purpose don't pass in the information about the PendingIntent's creator,
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 0a926f9..316368a 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -2227,9 +2227,10 @@
         for (AppZygote appZygote : zygotesToKill) {
             killAppZygoteIfNeededLocked(appZygote);
         }
-        mService.updateOomAdjLocked();
+        mService.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_PROCESS_END);
         return N > 0;
     }
+
     @GuardedBy("mService")
     boolean removeProcessLocked(ProcessRecord app,
             boolean callerWillRestart, boolean allowRestart, String reason) {
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 933f41c..49930c1 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -1301,7 +1301,7 @@
             }
             mService.mProcessList.updateLruProcessLocked(this, activityChange, null /* client */);
             if (updateOomAdj) {
-                mService.updateOomAdjLocked();
+                mService.updateOomAdjLocked(OomAdjuster.OOM_ADJ_REASON_ACTIVITY);
             }
         }
     }
diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java
index 873cadb..cd8167a 100644
--- a/services/core/java/com/android/server/appop/AppOpsService.java
+++ b/services/core/java/com/android/server/appop/AppOpsService.java
@@ -3097,6 +3097,7 @@
         int nonpackageUid;
         final static Binder sBinder = new Binder();
         IBinder mToken;
+        boolean targetsUid;
 
         Shell(IAppOpsService iface, AppOpsService internal) {
             mInterface = iface;
@@ -3190,6 +3191,8 @@
             for (String argument; (argument = getNextArg()) != null;) {
                 if ("--user".equals(argument)) {
                     userId = UserHandle.parseUserArg(getNextArgRequired());
+                } else if ("--uid".equals(argument)) {
+                    targetsUid = true;
                 } else {
                     if (packageName == null) {
                         packageName = argument;
@@ -3288,7 +3291,7 @@
         pw.println("    Starts a given operation for a particular application.");
         pw.println("  stop [--user <USER_ID>] <PACKAGE | UID> <OP> ");
         pw.println("    Stops a given operation for a particular application.");
-        pw.println("  set [--user <USER_ID>] <PACKAGE | UID> <OP> <MODE>");
+        pw.println("  set [--user <USER_ID>] <--uid PACKAGE | PACKAGE | UID> <OP> <MODE>");
         pw.println("    Set the mode for a particular application and operation.");
         pw.println("  get [--user <USER_ID>] <PACKAGE | UID> [<OP>]");
         pw.println("    Return the mode for a particular application and optional operation.");
@@ -3306,6 +3309,7 @@
         pw.println("    <MODE>    one of allow, ignore, deny, or default");
         pw.println("    <USER_ID> the user id under which the package is installed. If --user is not");
         pw.println("              specified, the current user is assumed.");
+        pw.println("    --uid PACKAGE refer to the UID of the package");
     }
 
     static int onShellCommand(Shell shell, String cmd) {
@@ -3332,9 +3336,17 @@
                         return -1;
                     }
 
-                    if (shell.packageName != null) {
+                    if (!shell.targetsUid && shell.packageName != null) {
                         shell.mInterface.setMode(shell.op, shell.packageUid, shell.packageName,
                                 mode);
+                    } else if (shell.targetsUid && shell.packageName != null) {
+                        try {
+                            final int uid = shell.mInternal.mContext.getPackageManager()
+                                    .getPackageUid(shell.packageName, shell.userId);
+                            shell.mInterface.setUidMode(shell.op, uid, mode);
+                        } catch (PackageManager.NameNotFoundException e) {
+                            return -1;
+                        }
                     } else {
                         shell.mInterface.setUidMode(shell.op, shell.nonpackageUid, mode);
                     }
diff --git a/services/core/java/com/android/server/attention/AttentionManagerService.java b/services/core/java/com/android/server/attention/AttentionManagerService.java
index 411dd79..d7d4851 100644
--- a/services/core/java/com/android/server/attention/AttentionManagerService.java
+++ b/services/core/java/com/android/server/attention/AttentionManagerService.java
@@ -58,6 +58,7 @@
 
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.Preconditions;
@@ -100,16 +101,25 @@
     private final Object mLock;
     @GuardedBy("mLock")
     private final SparseArray<UserState> mUserStates = new SparseArray<>();
-    private final AttentionHandler mAttentionHandler;
+    private AttentionHandler mAttentionHandler;
 
-    private ComponentName mComponentName;
+    @VisibleForTesting
+    ComponentName mComponentName;
 
     public AttentionManagerService(Context context) {
+        this(context, (PowerManager) context.getSystemService(Context.POWER_SERVICE),
+                new Object(), null);
+        mAttentionHandler = new AttentionHandler();
+    }
+
+    @VisibleForTesting
+    AttentionManagerService(Context context, PowerManager powerManager, Object lock,
+            AttentionHandler handler) {
         super(context);
         mContext = Preconditions.checkNotNull(context);
-        mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
-        mLock = new Object();
-        mAttentionHandler = new AttentionHandler();
+        mPowerManager = powerManager;
+        mLock = lock;
+        mAttentionHandler = handler;
     }
 
     @Override
@@ -147,7 +157,8 @@
         return isServiceEnabled() && isServiceAvailable();
     }
 
-    private boolean isServiceEnabled() {
+    @VisibleForTesting
+    protected boolean isServiceEnabled() {
         return DeviceConfig.getBoolean(NAMESPACE_ATTENTION_MANAGER_SERVICE, SERVICE_ENABLED,
                 DEFAULT_SERVICE_ENABLED);
     }
@@ -161,7 +172,8 @@
      *
      * @return {@code true} if the framework was able to dispatch the request
      */
-    private boolean checkAttention(long timeout, AttentionCallbackInternal callbackInternal) {
+    @VisibleForTesting
+    boolean checkAttention(long timeout, AttentionCallbackInternal callbackInternal) {
         Preconditions.checkNotNull(callbackInternal);
 
         if (!isAttentionServiceSupported()) {
@@ -257,24 +269,24 @@
     }
 
     /** Cancels the specified attention check. */
-    private void cancelAttentionCheck(AttentionCallbackInternal callbackInternal) {
+    @VisibleForTesting
+    void cancelAttentionCheck(AttentionCallbackInternal callbackInternal) {
         synchronized (mLock) {
             final UserState userState = peekCurrentUserStateLocked();
             if (userState == null) {
                 return;
             }
-
             if (!userState.mCurrentAttentionCheck.mCallbackInternal.equals(callbackInternal)) {
                 Slog.e(LOG_TAG, "Cannot cancel a non-current request");
                 return;
             }
-
             cancel(userState);
         }
     }
 
     @GuardedBy("mLock")
-    private void freeIfInactiveLocked() {
+    @VisibleForTesting
+    protected void freeIfInactiveLocked() {
         // If we are called here, it means someone used the API again - reset the timer then.
         mAttentionHandler.removeMessages(AttentionHandler.CHECK_CONNECTION_EXPIRATION);
 
@@ -291,7 +303,8 @@
 
 
     @GuardedBy("mLock")
-    private UserState getOrCreateCurrentUserStateLocked() {
+    @VisibleForTesting
+    protected UserState getOrCreateCurrentUserStateLocked() {
         return getOrCreateUserStateLocked(ActivityManager.getCurrentUser());
     }
 
@@ -307,7 +320,8 @@
 
     @GuardedBy("mLock")
     @Nullable
-    private UserState peekCurrentUserStateLocked() {
+    @VisibleForTesting
+    protected UserState peekCurrentUserStateLocked() {
         return peekUserStateLocked(ActivityManager.getCurrentUser());
     }
 
@@ -418,7 +432,8 @@
         }
     }
 
-    private static final class AttentionCheck {
+    @VisibleForTesting
+    static final class AttentionCheck {
         private final AttentionCallbackInternal mCallbackInternal;
         private final IAttentionCallback mIAttentionCallback;
         private boolean mIsDispatched;
@@ -435,7 +450,8 @@
         }
     }
 
-    private static final class UserState {
+    @VisibleForTesting
+    protected static class UserState {
         final ComponentName mComponentName;
         final AttentionServiceConnection mConnection = new AttentionServiceConnection();
 
@@ -453,7 +469,7 @@
         final Context mContext;
         final Object mLock;
 
-        private UserState(int userId, Context context, Object lock, ComponentName componentName) {
+        UserState(int userId, Context context, Object lock, ComponentName componentName) {
             mUserId = userId;
             mContext = Preconditions.checkNotNull(context);
             mLock = Preconditions.checkNotNull(lock);
@@ -509,7 +525,7 @@
             }
         }
 
-        private final class AttentionServiceConnection implements ServiceConnection {
+        private class AttentionServiceConnection implements ServiceConnection {
             @Override
             public void onServiceConnected(ComponentName name, IBinder service) {
                 init(IAttentionService.Stub.asInterface(service));
@@ -544,7 +560,8 @@
         }
     }
 
-    private class AttentionHandler extends Handler {
+    @VisibleForTesting
+    protected class AttentionHandler extends Handler {
         private static final int CHECK_CONNECTION_EXPIRATION = 1;
         private static final int ATTENTION_CHECK_TIMEOUT = 2;
 
@@ -576,7 +593,8 @@
         }
     }
 
-    private void cancel(UserState userState) {
+    @VisibleForTesting
+    void cancel(UserState userState) {
         if (userState == null || userState.mCurrentAttentionCheck == null) {
             return;
         }
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index 44c1715..c5733322 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -114,8 +114,10 @@
     // All post* methods are asynchronous
 
     /*package*/ void onSystemReady() {
-        synchronized (mDeviceStateLock) {
-            mBtHelper.onSystemReady();
+        synchronized (mSetModeLock) {
+            synchronized (mDeviceStateLock) {
+                mBtHelper.onSystemReady();
+            }
         }
     }
 
@@ -151,8 +153,10 @@
      * @param intent
      */
     /*package*/ void receiveBtEvent(@NonNull Intent intent) {
-        synchronized (mDeviceStateLock) {
-            mBtHelper.receiveBtEvent(intent);
+        synchronized (mSetModeLock) {
+            synchronized (mDeviceStateLock) {
+                mBtHelper.receiveBtEvent(intent);
+            }
         }
     }
 
@@ -350,13 +354,19 @@
         sendLMsgNoDelay(MSG_L_A2DP_DEVICE_CONFIG_CHANGE, SENDMSG_QUEUE, device);
     }
 
+    @GuardedBy("mSetModeLock")
     /*package*/ void startBluetoothScoForClient_Sync(IBinder cb, int scoAudioMode,
                 @NonNull String eventSource) {
-        mBtHelper.startBluetoothScoForClient(cb, scoAudioMode, eventSource);
+        synchronized (mDeviceStateLock) {
+            mBtHelper.startBluetoothScoForClient(cb, scoAudioMode, eventSource);
+        }
     }
 
+    @GuardedBy("mSetModeLock")
     /*package*/ void stopBluetoothScoForClient_Sync(IBinder cb, @NonNull String eventSource) {
-        mBtHelper.stopBluetoothScoForClient(cb, eventSource);
+        synchronized (mDeviceStateLock) {
+            mBtHelper.stopBluetoothScoForClient(cb, eventSource);
+        }
     }
 
     //---------------------------------------------------------------------
@@ -479,6 +489,10 @@
                 hearingAidProfile);
     }
 
+    /*package*/ void postScoClientDied(Object obj) {
+        sendLMsgNoDelay(MSG_L_SCOCLIENT_DIED, SENDMSG_QUEUE, obj);
+    }
+
     //---------------------------------------------------------------------
     // Method forwarding between the helper classes (BtHelper, AudioDeviceInventory)
     // only call from a "handle"* method or "on"* method
@@ -708,8 +722,10 @@
                     }
                     break;
                 case MSG_BT_HEADSET_CNCT_FAILED:
-                    synchronized (mDeviceStateLock) {
-                        mBtHelper.resetBluetoothSco();
+                    synchronized (mSetModeLock) {
+                        synchronized (mDeviceStateLock) {
+                            mBtHelper.resetBluetoothSco();
+                        }
                     }
                     break;
                 case MSG_IL_BTA2DP_DOCK_TIMEOUT:
@@ -742,8 +758,17 @@
                     }
                     break;
                 case MSG_I_DISCONNECT_BT_SCO:
-                    synchronized (mDeviceStateLock) {
-                        mBtHelper.disconnectBluetoothSco(msg.arg1);
+                    synchronized (mSetModeLock) {
+                        synchronized (mDeviceStateLock) {
+                            mBtHelper.disconnectBluetoothSco(msg.arg1);
+                        }
+                    }
+                    break;
+                case MSG_L_SCOCLIENT_DIED:
+                    synchronized (mSetModeLock) {
+                        synchronized (mDeviceStateLock) {
+                            mBtHelper.scoClientDied(msg.arg1);
+                        }
                     }
                     break;
                 case MSG_TOGGLE_HDMI:
@@ -774,8 +799,10 @@
                     }
                     break;
                 case MSG_DISCONNECT_BT_HEADSET:
-                    synchronized (mDeviceStateLock) {
-                        mBtHelper.disconnectHeadset();
+                    synchronized (mSetModeLock) {
+                        synchronized (mDeviceStateLock) {
+                            mBtHelper.disconnectHeadset();
+                        }
                     }
                     break;
                 case MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP:
@@ -794,8 +821,10 @@
                     }
                     break;
                 case MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEADSET:
-                    synchronized (mDeviceStateLock) {
-                        mBtHelper.onHeadsetProfileConnected((BluetoothHeadset) msg.obj);
+                    synchronized (mSetModeLock) {
+                        synchronized (mDeviceStateLock) {
+                            mBtHelper.onHeadsetProfileConnected((BluetoothHeadset) msg.obj);
+                        }
                     }
                     break;
                 case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT: {
@@ -892,6 +921,8 @@
     private static final int MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT = 28;
     // process external command to (dis)connect or change active A2DP device
     private static final int MSG_L_A2DP_ACTIVE_DEVICE_CHANGE_EXT = 29;
+    // a ScoClient died in BtHelper
+    private static final int MSG_L_SCOCLIENT_DIED = 30;
 
 
     private static boolean isMessageHandledUnderWakelock(int msgId) {
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index aee08bb..d30a9d2 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -3484,7 +3484,9 @@
                 !mSystemReady) {
             return;
         }
-        mDeviceBroker.startBluetoothScoForClient_Sync(cb, scoAudioMode, eventSource);
+        synchronized (mDeviceBroker.mSetModeLock) {
+            mDeviceBroker.startBluetoothScoForClient_Sync(cb, scoAudioMode, eventSource);
+        }
     }
 
     /** @see AudioManager#stopBluetoothSco() */
@@ -3496,7 +3498,9 @@
         final String eventSource =  new StringBuilder("stopBluetoothSco()")
                 .append(") from u/pid:").append(Binder.getCallingUid()).append("/")
                 .append(Binder.getCallingPid()).toString();
-        mDeviceBroker.stopBluetoothScoForClient_Sync(cb, eventSource);
+        synchronized (mDeviceBroker.mSetModeLock) {
+            mDeviceBroker.stopBluetoothScoForClient_Sync(cb, eventSource);
+        }
     }
 
 
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index 2d9156b..332ff36 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -36,6 +36,8 @@
 import android.provider.Settings;
 import android.util.Log;
 
+import com.android.internal.annotations.GuardedBy;
+
 import java.util.ArrayList;
 import java.util.List;
 import java.util.NoSuchElementException;
@@ -163,6 +165,8 @@
     //----------------------------------------------------------------------
     // Interface for AudioDeviceBroker
 
+    // @GuardedBy("AudioDeviceBroker.mSetModeLock")
+    @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
     /*package*/ synchronized void onSystemReady() {
         mScoConnectionState = android.media.AudioManager.SCO_AUDIO_STATE_ERROR;
         resetBluetoothSco();
@@ -231,6 +235,8 @@
         return mapBluetoothCodecToAudioFormat(btCodecConfig.getCodecType());
     }
 
+    // @GuardedBy("AudioDeviceBroker.mSetModeLock")
+    @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
     /*package*/ synchronized void receiveBtEvent(Intent intent) {
         final String action = intent.getAction();
         if (action.equals(BluetoothHeadset.ACTION_ACTIVE_DEVICE_CHANGED)) {
@@ -317,6 +323,8 @@
      *
      * @param exceptPid pid whose SCO connections through {@link AudioManager} should be kept
      */
+    // @GuardedBy("AudioDeviceBroker.mSetModeLock")
+    @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
     /*package*/ synchronized void disconnectBluetoothSco(int exceptPid) {
         checkScoAudioState();
         if (mScoAudioState == SCO_STATE_ACTIVE_EXTERNAL) {
@@ -325,6 +333,8 @@
         clearAllScoClients(exceptPid, true);
     }
 
+    // @GuardedBy("AudioDeviceBroker.mSetModeLock")
+    @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
     /*package*/ synchronized void startBluetoothScoForClient(IBinder cb, int scoAudioMode,
                 @NonNull String eventSource) {
         ScoClient client = getScoClient(cb, true);
@@ -344,6 +354,8 @@
         Binder.restoreCallingIdentity(ident);
     }
 
+    // @GuardedBy("AudioDeviceBroker.mSetModeLock")
+    @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
     /*package*/ synchronized void stopBluetoothScoForClient(IBinder cb,
             @NonNull String eventSource) {
         ScoClient client = getScoClient(cb, false);
@@ -401,6 +413,8 @@
         mDeviceBroker.postDisconnectHearingAid();
     }
 
+    // @GuardedBy("AudioDeviceBroker.mSetModeLock")
+    @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
     /*package*/ synchronized void resetBluetoothSco() {
         clearAllScoClients(0, false);
         mScoAudioState = SCO_STATE_INACTIVE;
@@ -409,6 +423,8 @@
         mDeviceBroker.setBluetoothScoOn(false, "resetBluetoothSco");
     }
 
+    // @GuardedBy("AudioDeviceBroker.mSetModeLock")
+    @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
     /*package*/ synchronized void disconnectHeadset() {
         setBtScoActiveDevice(null);
         mBluetoothHeadset = null;
@@ -454,6 +470,8 @@
                 /*eventSource*/ "mBluetoothProfileServiceListener");
     }
 
+    // @GuardedBy("AudioDeviceBroker.mSetModeLock")
+    @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
     /*package*/ synchronized void onHeadsetProfileConnected(BluetoothHeadset headset) {
         // Discard timeout message
         mDeviceBroker.handleCancelFailureToConnectToBtHeadsetService();
@@ -540,6 +558,9 @@
         return result;
     }
 
+    // @GuardedBy("AudioDeviceBroker.mSetModeLock")
+    //@GuardedBy("AudioDeviceBroker.mDeviceStateLock")
+    @GuardedBy("BtHelper.this")
     private void setBtScoActiveDevice(BluetoothDevice btDevice) {
         Log.i(TAG, "setBtScoActiveDevice: " + mBluetoothHeadsetDevice + " -> " + btDevice);
         final BluetoothDevice previousActiveDevice = mBluetoothHeadsetDevice;
@@ -621,6 +642,20 @@
             };
 
     //----------------------------------------------------------------------
+    // @GuardedBy("AudioDeviceBroker.mSetModeLock")
+    @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
+    /*package*/ synchronized void scoClientDied(Object obj) {
+        final ScoClient client = (ScoClient) obj;
+        Log.w(TAG, "SCO client died");
+        int index = mScoClients.indexOf(client);
+        if (index < 0) {
+            Log.w(TAG, "unregistered SCO client died");
+        } else {
+            client.clearCount(true);
+            mScoClients.remove(client);
+        }
+    }
+
     private class ScoClient implements IBinder.DeathRecipient {
         private IBinder mCb; // To be notified of client's death
         private int mCreatorPid;
@@ -634,21 +669,14 @@
 
         @Override
         public void binderDied() {
-            // this is the only place the implementation of ScoClient needs to be synchronized
-            // on the instance, as all other methods are directly or indirectly called from
-            // package-private methods, which are synchronized
-            synchronized (BtHelper.this) {
-                Log.w(TAG, "SCO client died");
-                int index = mScoClients.indexOf(this);
-                if (index < 0) {
-                    Log.w(TAG, "unregistered SCO client died");
-                } else {
-                    clearCount(true);
-                    mScoClients.remove(this);
-                }
-            }
+            // process this from DeviceBroker's message queue to take the right locks since
+            // this event can impact SCO mode and requires querying audio mode stack
+            mDeviceBroker.postScoClientDied(this);
         }
 
+        // @GuardedBy("AudioDeviceBroker.mSetModeLock")
+        // @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
+        @GuardedBy("BtHelper.this")
         void incCount(int scoAudioMode) {
             requestScoState(BluetoothHeadset.STATE_AUDIO_CONNECTED, scoAudioMode);
             if (mStartcount == 0) {
@@ -663,6 +691,9 @@
             mStartcount++;
         }
 
+        // @GuardedBy("AudioDeviceBroker.mSetModeLock")
+        // @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
+        @GuardedBy("BtHelper.this")
         void decCount() {
             if (mStartcount == 0) {
                 Log.w(TAG, "ScoClient.decCount() already 0");
@@ -679,6 +710,9 @@
             }
         }
 
+        // @GuardedBy("AudioDeviceBroker.mSetModeLock")
+        // @GuardedBy("AudioDeviceBroker.mDeviceStateLock")
+        @GuardedBy("BtHelper.this")
         void clearCount(boolean stopSco) {
             if (mStartcount != 0) {
                 try {
@@ -714,6 +748,9 @@
             return count;
         }
 
+        // @GuardedBy("AudioDeviceBroker.mSetModeLock")
+        //@GuardedBy("AudioDeviceBroker.mDeviceStateLock")
+        @GuardedBy("BtHelper.this")
         private void requestScoState(int state, int scoAudioMode) {
             checkScoAudioState();
             int clientCount = totalCount();
@@ -728,74 +765,71 @@
                 broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTING);
                 // Accept SCO audio activation only in NORMAL audio mode or if the mode is
                 // currently controlled by the same client process.
-                // TODO do not sync that way, see b/123769055
-                synchronized (mDeviceBroker.mSetModeLock) {
-                    int modeOwnerPid =  mDeviceBroker.getSetModeDeathHandlers().isEmpty()
-                            ? 0 : mDeviceBroker.getSetModeDeathHandlers().get(0).getPid();
-                    if (modeOwnerPid != 0 && (modeOwnerPid != mCreatorPid)) {
-                        Log.w(TAG, "requestScoState: audio mode is not NORMAL and modeOwnerPid "
-                                + modeOwnerPid + " != creatorPid " + mCreatorPid);
-                        broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
-                        return;
-                    }
-                    switch (mScoAudioState) {
-                        case SCO_STATE_INACTIVE:
-                            mScoAudioMode = scoAudioMode;
-                            if (scoAudioMode == SCO_MODE_UNDEFINED) {
-                                mScoAudioMode = SCO_MODE_VIRTUAL_CALL;
-                                if (mBluetoothHeadsetDevice != null) {
-                                    mScoAudioMode = Settings.Global.getInt(
-                                            mDeviceBroker.getContentResolver(),
-                                            "bluetooth_sco_channel_"
-                                                    + mBluetoothHeadsetDevice.getAddress(),
-                                            SCO_MODE_VIRTUAL_CALL);
-                                    if (mScoAudioMode > SCO_MODE_MAX || mScoAudioMode < 0) {
-                                        mScoAudioMode = SCO_MODE_VIRTUAL_CALL;
-                                    }
+                int modeOwnerPid =  mDeviceBroker.getSetModeDeathHandlers().isEmpty()
+                        ? 0 : mDeviceBroker.getSetModeDeathHandlers().get(0).getPid();
+                if (modeOwnerPid != 0 && (modeOwnerPid != mCreatorPid)) {
+                    Log.w(TAG, "requestScoState: audio mode is not NORMAL and modeOwnerPid "
+                            + modeOwnerPid + " != creatorPid " + mCreatorPid);
+                    broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
+                    return;
+                }
+                switch (mScoAudioState) {
+                    case SCO_STATE_INACTIVE:
+                        mScoAudioMode = scoAudioMode;
+                        if (scoAudioMode == SCO_MODE_UNDEFINED) {
+                            mScoAudioMode = SCO_MODE_VIRTUAL_CALL;
+                            if (mBluetoothHeadsetDevice != null) {
+                                mScoAudioMode = Settings.Global.getInt(
+                                        mDeviceBroker.getContentResolver(),
+                                        "bluetooth_sco_channel_"
+                                                + mBluetoothHeadsetDevice.getAddress(),
+                                        SCO_MODE_VIRTUAL_CALL);
+                                if (mScoAudioMode > SCO_MODE_MAX || mScoAudioMode < 0) {
+                                    mScoAudioMode = SCO_MODE_VIRTUAL_CALL;
                                 }
                             }
-                            if (mBluetoothHeadset == null) {
-                                if (getBluetoothHeadset()) {
-                                    mScoAudioState = SCO_STATE_ACTIVATE_REQ;
-                                } else {
-                                    Log.w(TAG, "requestScoState: getBluetoothHeadset failed during"
-                                            + " connection, mScoAudioMode=" + mScoAudioMode);
-                                    broadcastScoConnectionState(
-                                            AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
-                                }
-                                break;
-                            }
-                            if (mBluetoothHeadsetDevice == null) {
-                                Log.w(TAG, "requestScoState: no active device while connecting,"
-                                        + " mScoAudioMode=" + mScoAudioMode);
-                                broadcastScoConnectionState(
-                                        AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
-                                break;
-                            }
-                            if (connectBluetoothScoAudioHelper(mBluetoothHeadset,
-                                    mBluetoothHeadsetDevice, mScoAudioMode)) {
-                                mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
+                        }
+                        if (mBluetoothHeadset == null) {
+                            if (getBluetoothHeadset()) {
+                                mScoAudioState = SCO_STATE_ACTIVATE_REQ;
                             } else {
-                                Log.w(TAG, "requestScoState: connect to " + mBluetoothHeadsetDevice
-                                        + " failed, mScoAudioMode=" + mScoAudioMode);
+                                Log.w(TAG, "requestScoState: getBluetoothHeadset failed during"
+                                        + " connection, mScoAudioMode=" + mScoAudioMode);
                                 broadcastScoConnectionState(
                                         AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
                             }
                             break;
-                        case SCO_STATE_DEACTIVATING:
-                            mScoAudioState = SCO_STATE_ACTIVATE_REQ;
+                        }
+                        if (mBluetoothHeadsetDevice == null) {
+                            Log.w(TAG, "requestScoState: no active device while connecting,"
+                                    + " mScoAudioMode=" + mScoAudioMode);
+                            broadcastScoConnectionState(
+                                    AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
                             break;
-                        case SCO_STATE_DEACTIVATE_REQ:
+                        }
+                        if (connectBluetoothScoAudioHelper(mBluetoothHeadset,
+                                mBluetoothHeadsetDevice, mScoAudioMode)) {
                             mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
-                            broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED);
-                            break;
-                        default:
-                            Log.w(TAG, "requestScoState: failed to connect in state "
-                                    + mScoAudioState + ", scoAudioMode=" + scoAudioMode);
-                            broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
-                            break;
+                        } else {
+                            Log.w(TAG, "requestScoState: connect to " + mBluetoothHeadsetDevice
+                                    + " failed, mScoAudioMode=" + mScoAudioMode);
+                            broadcastScoConnectionState(
+                                    AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
+                        }
+                        break;
+                    case SCO_STATE_DEACTIVATING:
+                        mScoAudioState = SCO_STATE_ACTIVATE_REQ;
+                        break;
+                    case SCO_STATE_DEACTIVATE_REQ:
+                        mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
+                        broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_CONNECTED);
+                        break;
+                    default:
+                        Log.w(TAG, "requestScoState: failed to connect in state "
+                                + mScoAudioState + ", scoAudioMode=" + scoAudioMode);
+                        broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
+                        break;
 
-                    }
                 }
             } else if (state == BluetoothHeadset.STATE_AUDIO_DISCONNECTED) {
                 switch (mScoAudioState) {
@@ -906,6 +940,9 @@
         return null;
     }
 
+    // @GuardedBy("AudioDeviceBroker.mSetModeLock")
+    //@GuardedBy("AudioDeviceBroker.mDeviceStateLock")
+    @GuardedBy("BtHelper.this")
     private void clearAllScoClients(int exceptPid, boolean stopSco) {
         ScoClient savedClient = null;
         for (ScoClient cl : mScoClients) {
diff --git a/services/core/java/com/android/server/clipboard/ClipboardService.java b/services/core/java/com/android/server/clipboard/ClipboardService.java
index 258c325..d28482e 100644
--- a/services/core/java/com/android/server/clipboard/ClipboardService.java
+++ b/services/core/java/com/android/server/clipboard/ClipboardService.java
@@ -52,6 +52,7 @@
 import android.text.TextUtils;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.view.autofill.AutofillManagerInternal;
 
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
@@ -159,6 +160,7 @@
     private final PackageManager mPm;
     private final AppOpsManager mAppOps;
     private final ContentCaptureManagerInternal mContentCaptureInternal;
+    private final AutofillManagerInternal mAutofillInternal;
     private final IBinder mPermissionOwner;
     private HostClipboardMonitor mHostClipboardMonitor = null;
     private Thread mHostMonitorThread = null;
@@ -179,6 +181,7 @@
         mUm = (IUserManager) ServiceManager.getService(Context.USER_SERVICE);
         mAppOps = (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE);
         mContentCaptureInternal = LocalServices.getService(ContentCaptureManagerInternal.class);
+        mAutofillInternal = LocalServices.getService(AutofillManagerInternal.class);
         final IBinder permOwner = mUgmInternal.newUriPermissionOwner("clipboard");
         mPermissionOwner = permOwner;
         if (IS_EMULATOR) {
@@ -653,13 +656,18 @@
                 // Clipboard can only be read by applications with focus..
                 boolean allowed = mWm.isUidFocused(callingUid);
                 if (!allowed && mContentCaptureInternal != null) {
-                    // ...or the Intelligence Service
+                    // ...or the Content Capture Service
                     allowed = mContentCaptureInternal.isContentCaptureServiceForUser(callingUid,
                             userId);
                 }
+                if (!allowed && mAutofillInternal != null) {
+                    // ...or the Augmented Autofill Service
+                    allowed = mAutofillInternal.isAugmentedAutofillServiceForUser(callingUid,
+                            userId);
+                }
                 if (!allowed) {
                     Slog.e(TAG, "Denying clipboard access to " + callingPackage
-                            + ", application is not in focus neither is the IntelligeService for "
+                            + ", application is not in focus neither is a system service for "
                             + "user " + userId);
                 }
                 return allowed;
diff --git a/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java b/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
index 948c690..a1a8e35 100644
--- a/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
+++ b/services/core/java/com/android/server/connectivity/NetworkDiagnostics.java
@@ -33,6 +33,7 @@
 import android.util.Pair;
 
 import com.android.internal.util.IndentingPrintWriter;
+import com.android.internal.util.TrafficStatsConstants;
 
 import libcore.io.IoUtils;
 
@@ -381,7 +382,8 @@
         protected void setupSocket(
                 int sockType, int protocol, long writeTimeout, long readTimeout, int dstPort)
                 throws ErrnoException, IOException {
-            final int oldTag = TrafficStats.getAndSetThreadStatsTag(TrafficStats.TAG_SYSTEM_PROBE);
+            final int oldTag = TrafficStats.getAndSetThreadStatsTag(
+                    TrafficStatsConstants.TAG_SYSTEM_PROBE);
             try {
                 mFileDescriptor = Os.socket(mAddressFamily, sockType, protocol);
             } finally {
diff --git a/services/core/java/com/android/server/connectivity/PacManager.java b/services/core/java/com/android/server/connectivity/PacManager.java
index 1ac09ad..f6ce2dc 100644
--- a/services/core/java/com/android/server/connectivity/PacManager.java
+++ b/services/core/java/com/android/server/connectivity/PacManager.java
@@ -39,6 +39,7 @@
 import android.util.Log;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.TrafficStatsConstants;
 import com.android.net.IProxyCallback;
 import com.android.net.IProxyPortListener;
 import com.android.net.IProxyService;
@@ -111,7 +112,8 @@
             String file;
             final Uri pacUrl = mPacUrl;
             if (Uri.EMPTY.equals(pacUrl)) return;
-            final int oldTag = TrafficStats.getAndSetThreadStatsTag(TrafficStats.TAG_SYSTEM_PAC);
+            final int oldTag = TrafficStats.getAndSetThreadStatsTag(
+                    TrafficStatsConstants.TAG_SYSTEM_PAC);
             try {
                 file = get(pacUrl);
             } catch (IOException ioe) {
diff --git a/services/core/java/com/android/server/location/GpsXtraDownloader.java b/services/core/java/com/android/server/location/GpsXtraDownloader.java
index c012ee4..7dffcb4 100644
--- a/services/core/java/com/android/server/location/GpsXtraDownloader.java
+++ b/services/core/java/com/android/server/location/GpsXtraDownloader.java
@@ -20,6 +20,8 @@
 import android.text.TextUtils;
 import android.util.Log;
 
+import com.android.internal.util.TrafficStatsConstants;
+
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
@@ -92,7 +94,8 @@
 
         // load balance our requests among the available servers
         while (result == null) {
-            final int oldTag = TrafficStats.getAndSetThreadStatsTag(TrafficStats.TAG_SYSTEM_GPS);
+            final int oldTag = TrafficStats.getAndSetThreadStatsTag(
+                    TrafficStatsConstants.TAG_SYSTEM_GPS);
             try {
                 result = doDownload(mXtraServers[mNextServerIndex]);
             } finally {
diff --git a/services/core/java/com/android/server/media/MediaSessionServiceImpl.java b/services/core/java/com/android/server/media/MediaSessionServiceImpl.java
index a5f2217..fdb499b 100644
--- a/services/core/java/com/android/server/media/MediaSessionServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaSessionServiceImpl.java
@@ -140,6 +140,7 @@
     private AudioPlayerStateMonitor mAudioPlayerStateMonitor;
 
     // Used to notify System UI and Settings when remote volume was changed.
+    @GuardedBy("mLock")
     final RemoteCallbackList<IRemoteVolumeController> mRemoteVolumeControllers =
             new RemoteCallbackList<>();
 
@@ -287,17 +288,19 @@
         if (!session.isActive()) {
             return;
         }
-        int size = mRemoteVolumeControllers.beginBroadcast();
-        MediaSession.Token token = session.getSessionToken();
-        for (int i = size - 1; i >= 0; i--) {
-            try {
-                IRemoteVolumeController cb = mRemoteVolumeControllers.getBroadcastItem(i);
-                cb.remoteVolumeChanged(token, flags);
-            } catch (Exception e) {
-                Log.w(TAG, "Error sending volume change.", e);
+        synchronized (mLock) {
+            int size = mRemoteVolumeControllers.beginBroadcast();
+            MediaSession.Token token = session.getSessionToken();
+            for (int i = size - 1; i >= 0; i--) {
+                try {
+                    IRemoteVolumeController cb = mRemoteVolumeControllers.getBroadcastItem(i);
+                    cb.remoteVolumeChanged(token, flags);
+                } catch (Exception e) {
+                    Log.w(TAG, "Error sending volume change.", e);
+                }
             }
+            mRemoteVolumeControllers.finishBroadcast();
         }
-        mRemoteVolumeControllers.finishBroadcast();
     }
 
     @Override
@@ -647,19 +650,21 @@
             return;
         }
 
-        int size = mRemoteVolumeControllers.beginBroadcast();
-        MediaSessionRecord record = user.mPriorityStack.getDefaultRemoteSession(userId);
-        MediaSession.Token token = record == null ? null : record.getSessionToken();
+        synchronized (mLock) {
+            int size = mRemoteVolumeControllers.beginBroadcast();
+            MediaSessionRecord record = user.mPriorityStack.getDefaultRemoteSession(userId);
+            MediaSession.Token token = record == null ? null : record.getSessionToken();
 
-        for (int i = size - 1; i >= 0; i--) {
-            try {
-                IRemoteVolumeController cb = mRemoteVolumeControllers.getBroadcastItem(i);
-                cb.updateRemoteController(token);
-            } catch (Exception e) {
-                Log.w(TAG, "Error sending default remote volume.", e);
+            for (int i = size - 1; i >= 0; i--) {
+                try {
+                    IRemoteVolumeController cb = mRemoteVolumeControllers.getBroadcastItem(i);
+                    cb.updateRemoteController(token);
+                } catch (Exception e) {
+                    Log.w(TAG, "Error sending default remote volume.", e);
+                }
             }
+            mRemoteVolumeControllers.finishBroadcast();
         }
-        mRemoteVolumeControllers.finishBroadcast();
     }
 
     void pushSession2TokensChangedLocked(int userId) {
@@ -1676,11 +1681,13 @@
             final int pid = Binder.getCallingPid();
             final int uid = Binder.getCallingUid();
             final long token = Binder.clearCallingIdentity();
-            try {
-                enforceStatusBarServicePermission("listen for volume changes", pid, uid);
-                mRemoteVolumeControllers.register(rvc);
-            } finally {
-                Binder.restoreCallingIdentity(token);
+            synchronized (mLock) {
+                try {
+                    enforceStatusBarServicePermission("listen for volume changes", pid, uid);
+                    mRemoteVolumeControllers.register(rvc);
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
             }
         }
 
@@ -1689,11 +1696,13 @@
             final int pid = Binder.getCallingPid();
             final int uid = Binder.getCallingUid();
             final long token = Binder.clearCallingIdentity();
-            try {
-                enforceStatusBarServicePermission("listen for volume changes", pid, uid);
-                mRemoteVolumeControllers.unregister(rvc);
-            } finally {
-                Binder.restoreCallingIdentity(token);
+            synchronized (mLock) {
+                try {
+                    enforceStatusBarServicePermission("listen for volume changes", pid, uid);
+                    mRemoteVolumeControllers.unregister(rvc);
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+                }
             }
         }
 
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 7f1b25ca..042ac8c 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1689,6 +1689,9 @@
 
         mPreferencesHelper.lockChannelsForOEM(getContext().getResources().getStringArray(
                 com.android.internal.R.array.config_nonBlockableNotificationPackages));
+
+        mZenModeHelper.setPriorityOnlyDndExemptPackages(getContext().getResources().getStringArray(
+                com.android.internal.R.array.config_priorityOnlyDndExemptPackages));
     }
 
     @Override
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 7e74cc2..1f5b99c 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -80,6 +80,7 @@
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 import java.util.Objects;
 
@@ -96,7 +97,7 @@
     private final Context mContext;
     private final H mHandler;
     private final SettingsObserver mSettingsObserver;
-    @VisibleForTesting protected final AppOpsManager mAppOps;
+    private final AppOpsManager mAppOps;
     @VisibleForTesting protected final NotificationManager mNotificationManager;
     @VisibleForTesting protected ZenModeConfig mDefaultConfig;
     private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
@@ -123,11 +124,13 @@
 
     @VisibleForTesting protected boolean mIsBootComplete;
 
+    private String[] mPriorityOnlyDndExemptPackages;
+
     public ZenModeHelper(Context context, Looper looper, ConditionProviders conditionProviders) {
         mContext = context;
         mHandler = new H(looper);
         addCallback(mMetrics);
-        mAppOps = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
+        mAppOps = context.getSystemService(AppOpsManager.class);
         mNotificationManager =  context.getSystemService(NotificationManager.class);
 
         mDefaultConfig = readDefaultConfig(mContext.getResources());
@@ -214,6 +217,10 @@
         loadConfigForUser(user, "onUserUnlocked");
     }
 
+    void setPriorityOnlyDndExemptPackages(String[] packages) {
+        mPriorityOnlyDndExemptPackages = packages;
+    }
+
     private void loadConfigForUser(int user, String reason) {
         if (mUser == user || user < UserHandle.USER_SYSTEM) return;
         mUser = user;
@@ -994,53 +1001,47 @@
         for (int usage : AudioAttributes.SDK_USAGES) {
             final int suppressionBehavior = AudioAttributes.SUPPRESSIBLE_USAGES.get(usage);
             if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_NEVER) {
-                applyRestrictions(false /*mute*/, usage);
+                applyRestrictions(zenPriorityOnly, false /*mute*/, usage);
             } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_NOTIFICATION) {
-                applyRestrictions(muteNotifications || muteEverything, usage);
+                applyRestrictions(zenPriorityOnly, muteNotifications || muteEverything, usage);
             } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_CALL) {
-                applyRestrictions(muteCalls || muteEverything, usage);
+                applyRestrictions(zenPriorityOnly, muteCalls || muteEverything, usage);
             } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_ALARM) {
-                applyRestrictions(muteAlarms || muteEverything, usage);
+                applyRestrictions(zenPriorityOnly, muteAlarms || muteEverything, usage);
             } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_MEDIA) {
-                applyRestrictions(muteMedia || muteEverything, usage);
+                applyRestrictions(zenPriorityOnly, muteMedia || muteEverything, usage);
             } else if (suppressionBehavior == AudioAttributes.SUPPRESSIBLE_SYSTEM) {
                 if (usage == AudioAttributes.USAGE_ASSISTANCE_SONIFICATION) {
                     // normally DND will only restrict touch sounds, not haptic feedback/vibrations
-                    applyRestrictions(muteSystem || muteEverything, usage,
+                    applyRestrictions(zenPriorityOnly, muteSystem || muteEverything, usage,
                             AppOpsManager.OP_PLAY_AUDIO);
-                    applyRestrictions(false, usage, AppOpsManager.OP_VIBRATE);
+                    applyRestrictions(zenPriorityOnly, false, usage, AppOpsManager.OP_VIBRATE);
                 } else {
-                    applyRestrictions(muteSystem || muteEverything, usage);
+                    applyRestrictions(zenPriorityOnly, muteSystem || muteEverything, usage);
                 }
             } else {
-                applyRestrictions(muteEverything, usage);
+                applyRestrictions(zenPriorityOnly, muteEverything, usage);
             }
         }
     }
 
 
     @VisibleForTesting
-    protected void applyRestrictions(boolean mute, int usage, int code) {
-        final String[] exceptionPackages = null; // none (for now)
-
-        // Only do this if we are executing within the system process...  otherwise
-        // we are running as test code, so don't have access to the protected call.
-        if (Process.myUid() == Process.SYSTEM_UID) {
-            final long ident = Binder.clearCallingIdentity();
-            try {
-                mAppOps.setRestriction(code, usage,
-                        mute ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED,
-                        exceptionPackages);
-            } finally {
-                Binder.restoreCallingIdentity(ident);
-            }
+    protected void applyRestrictions(boolean zenPriorityOnly, boolean mute, int usage, int code) {
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            mAppOps.setRestriction(code, usage,
+                    mute ? AppOpsManager.MODE_IGNORED : AppOpsManager.MODE_ALLOWED,
+                    zenPriorityOnly ? mPriorityOnlyDndExemptPackages : null);
+        } finally {
+            Binder.restoreCallingIdentity(ident);
         }
     }
 
     @VisibleForTesting
-    protected void applyRestrictions(boolean mute, int usage) {
-        applyRestrictions(mute, usage, AppOpsManager.OP_VIBRATE);
-        applyRestrictions(mute, usage, AppOpsManager.OP_PLAY_AUDIO);
+    protected void applyRestrictions(boolean zenPriorityOnly, boolean mute, int usage) {
+        applyRestrictions(zenPriorityOnly, mute, usage, AppOpsManager.OP_VIBRATE);
+        applyRestrictions(zenPriorityOnly, mute, usage, AppOpsManager.OP_PLAY_AUDIO);
     }
 
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index c12ee03..c4d4106 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2801,6 +2801,11 @@
                         if (disabledPs.codePath == null || !disabledPs.codePath.exists()
                                 || disabledPs.pkg == null) {
                             possiblyDeletedUpdatedSystemApps.add(ps.name);
+                        } else {
+                            // We're expecting that the system app should remain disabled, but add
+                            // it to expecting better to recover in case the data version cannot
+                            // be scanned.
+                            mExpectingBetter.put(disabledPs.name, disabledPs.codePath);
                         }
                     }
                 }
@@ -5733,6 +5738,8 @@
                     "getWhitelistedRestrictedPermissions for user " + userId);
         }
 
+        final PackageParser.Package pkg;
+
         synchronized (mPackages) {
             final PackageSetting packageSetting = mSettings.mPackages.get(packageName);
             if (packageSetting == null) {
@@ -5740,6 +5747,8 @@
                 return null;
             }
 
+            pkg = packageSetting.pkg;
+
             final boolean isCallerPrivileged = mContext.checkCallingOrSelfPermission(
                     Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS)
                             == PackageManager.PERMISSION_GRANTED;
@@ -5767,14 +5776,14 @@
                     UserHandle.getCallingUserId())) {
                 return null;
             }
+        }
 
-            final long identity = Binder.clearCallingIdentity();
-            try {
-                return mPermissionManager.getWhitelistedRestrictedPermissions(
-                        packageSetting.pkg, whitelistFlags, userId);
-            } finally {
-                Binder.restoreCallingIdentity(identity);
-            }
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            return mPermissionManager.getWhitelistedRestrictedPermissions(
+                    pkg, whitelistFlags, userId);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
         }
     }
 
@@ -5785,6 +5794,10 @@
         // Other argument checks are done in get/setWhitelistedRestrictedPermissions
         Preconditions.checkNotNull(permission);
 
+        if (!checkExistsAndEnforceCannotModifyImmutablyRestrictedPermission(permission)) {
+            return false;
+        }
+
         List<String> permissions = getWhitelistedRestrictedPermissions(packageName,
                 whitelistFlags, userId);
         if (permissions == null) {
@@ -5792,13 +5805,31 @@
         }
         if (permissions.indexOf(permission) < 0) {
             permissions.add(permission);
-            setWhitelistedRestrictedPermissions(packageName, permissions,
+            return setWhitelistedRestrictedPermissions(packageName, permissions,
                     whitelistFlags, userId);
-            return true;
         }
         return false;
     }
 
+    private boolean checkExistsAndEnforceCannotModifyImmutablyRestrictedPermission(
+            @NonNull String permission) {
+        synchronized (mPackages) {
+            final BasePermission bp = mPermissionManager.getPermissionTEMP(permission);
+            if (bp == null) {
+                Slog.w(TAG, "No such permissions: " + permission);
+                return false;
+            }
+            if (bp.isHardOrSoftRestricted() && bp.isImmutablyRestricted()
+                    && mContext.checkCallingOrSelfPermission(
+                    Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS)
+                    != PackageManager.PERMISSION_GRANTED) {
+                throw new SecurityException("Cannot modify whitelisting of an immutably "
+                        + "restricted permission: " + permission);
+            }
+            return true;
+        }
+    }
+
     @Override
     public boolean removeWhitelistedRestrictedPermission(@NonNull String packageName,
             @NonNull String permission, @PermissionWhitelistFlags int whitelistFlags,
@@ -5806,17 +5837,20 @@
         // Other argument checks are done in get/setWhitelistedRestrictedPermissions
         Preconditions.checkNotNull(permission);
 
+        if (!checkExistsAndEnforceCannotModifyImmutablyRestrictedPermission(permission)) {
+            return false;
+        }
+
         final List<String> permissions = getWhitelistedRestrictedPermissions(packageName,
                 whitelistFlags, userId);
         if (permissions != null && permissions.remove(permission)) {
-            setWhitelistedRestrictedPermissions(packageName, permissions,
+            return setWhitelistedRestrictedPermissions(packageName, permissions,
                     whitelistFlags, userId);
-            return true;
         }
         return false;
     }
 
-    private void setWhitelistedRestrictedPermissions(@NonNull String packageName,
+    private boolean setWhitelistedRestrictedPermissions(@NonNull String packageName,
             @Nullable List<String> permissions, @PermissionWhitelistFlags int whitelistFlag,
             @UserIdInt int userId) {
         Preconditions.checkNotNull(packageName);
@@ -5833,13 +5867,17 @@
                     "setWhitelistedRestrictedPermissions for user " + userId);
         }
 
+        final PackageParser.Package pkg;
+
         synchronized (mPackages) {
             final PackageSetting packageSetting = mSettings.mPackages.get(packageName);
             if (packageSetting == null) {
                 Slog.w(TAG, "Unknown package: " + packageName);
-                return;
+                return false;
             }
 
+            pkg = packageSetting.pkg;
+
             final boolean isCallerPrivileged = mContext.checkCallingOrSelfPermission(
                     Manifest.permission.WHITELIST_RESTRICTED_PERMISSIONS)
                             == PackageManager.PERMISSION_GRANTED;
@@ -5864,7 +5902,7 @@
                         packageName, whitelistFlag, userId);
                 if (permissions == null || permissions.isEmpty()) {
                     if (whitelistedPermissions == null || whitelistedPermissions.isEmpty()) {
-                        return;
+                        return true;
                     }
                 } else {
                     // Only the system can add and remove while the installer can only remove.
@@ -5890,18 +5928,20 @@
 
             if (filterAppAccessLPr(packageSetting, Binder.getCallingUid(),
                     UserHandle.getCallingUserId())) {
-                return;
-            }
-
-            final long identity = Binder.clearCallingIdentity();
-            try {
-                mPermissionManager.setWhitelistedRestrictedPermissions(packageSetting.pkg,
-                        new int[]{userId}, permissions, Process.myUid(), whitelistFlag,
-                        mPermissionCallback);
-            } finally {
-                Binder.restoreCallingIdentity(identity);
+                return false;
             }
         }
+
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            mPermissionManager.setWhitelistedRestrictedPermissions(pkg,
+                    new int[]{userId}, permissions, Process.myUid(), whitelistFlag,
+                    mPermissionCallback);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+
+        return true;
     }
 
     @Override
@@ -9334,6 +9374,7 @@
                 | SCAN_UPDATE_SIGNATURE, currentTime, user);
         if (scanResult.success) {
             synchronized (mPackages) {
+                boolean appIdCreated = false;
                 try {
                     final String pkgName = scanResult.pkgSetting.name;
                     final Map<String, ReconciledPackage> reconcileResult = reconcilePackagesLocked(
@@ -9346,11 +9387,12 @@
                                     Collections.singletonMap(pkgName,
                                             getSharedLibLatestVersionSetting(scanResult))),
                             mSettings.mKeySetManagerService);
-                    prepareScanResultLocked(scanResult);
-                    commitReconciledScanResultLocked(
-                            reconcileResult.get(pkgName));
+                    appIdCreated = optimisticallyRegisterAppId(scanResult);
+                    commitReconciledScanResultLocked(reconcileResult.get(pkgName));
                 } catch (PackageManagerException e) {
-                    unprepareScanResultLocked(scanResult);
+                    if (appIdCreated) {
+                        cleanUpAppIdCreation(scanResult);
+                    }
                     throw e;
                 }
             }
@@ -10837,27 +10879,32 @@
     }
 
 
-    /** Prepares the system to commit a {@link ScanResult} in a way that will not fail. */
-    private void prepareScanResultLocked(@NonNull ScanResult result)
+    /**
+     * Prepares the system to commit a {@link ScanResult} in a way that will not fail by registering
+     * the app ID required for reconcile.
+     * @return {@code true} if a new app ID was registered and will need to be cleaned up on
+     *         failure.
+     */
+    private boolean optimisticallyRegisterAppId(@NonNull ScanResult result)
             throws PackageManagerException {
         if (!result.existingSettingCopied) {
             // THROWS: when we can't allocate a user id. add call to check if there's
             // enough space to ensure we won't throw; otherwise, don't modify state
-            mSettings.registerAppIdLPw(result.pkgSetting);
+            return mSettings.registerAppIdLPw(result.pkgSetting);
         }
+        return false;
     }
 
     /**
-     * Reverts any changes to the system that were made by
-     * {@link #prepareScanResultLocked(ScanResult)}
+     * Reverts any app ID creation that were made by
+     * {@link #optimisticallyRegisterAppId(ScanResult)}. Note: this is only necessary if the
+     * referenced method returned true.
      */
-    private void unprepareScanResultLocked(@NonNull ScanResult result) {
-        if (!result.existingSettingCopied) {
-            // iff we've acquired an app ID for a new package setting, remove it so that it can be
-            // acquired by another request.
-            if (result.pkgSetting.appId > 0) {
-                mSettings.removeAppIdLPw(result.pkgSetting.appId);
-            }
+    private void cleanUpAppIdCreation(@NonNull ScanResult result) {
+        // iff we've acquired an app ID for a new package setting, remove it so that it can be
+        // acquired by another request.
+        if (result.pkgSetting.appId > 0) {
+            mSettings.removeAppIdLPw(result.pkgSetting.appId);
         }
     }
 
@@ -14608,6 +14655,20 @@
             return mUser;
         }
 
+        /**
+         * Gets the user handle for the user that the rollback agent should
+         * use to look up information about this installation when enabling
+         * rollback.
+         */
+        UserHandle getRollbackUser() {
+            // The session for packages installed for "all" users is
+            // associated with the "system" user.
+            if (mUser == UserHandle.ALL) {
+                return UserHandle.SYSTEM;
+            }
+            return mUser;
+        }
+
         HandlerParams setTraceMethod(String traceMethod) {
             this.traceMethod = traceMethod;
             return this;
@@ -15226,7 +15287,7 @@
                             installedUsers);
                     enableRollbackIntent.putExtra(
                             PackageManagerInternal.EXTRA_ENABLE_ROLLBACK_USER,
-                            getUser().getIdentifier());
+                            getRollbackUser().getIdentifier());
                     enableRollbackIntent.setDataAndType(Uri.fromFile(new File(origin.resolvedPath)),
                             PACKAGE_MIME_TYPE);
                     enableRollbackIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
@@ -16701,6 +16762,7 @@
         final Map<String, VersionInfo> versionInfos = new ArrayMap<>(requests.size());
         final Map<String, PackageSetting> lastStaticSharedLibSettings =
                 new ArrayMap<>(requests.size());
+        final Map<String, Boolean> createdAppId = new ArrayMap<>(requests.size());
         boolean success = false;
         try {
             Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installPackagesLI");
@@ -16740,7 +16802,7 @@
                                             + " in multi-package install request.");
                             return;
                         }
-                        prepareScanResultLocked(result);
+                        createdAppId.put(packageName, optimisticallyRegisterAppId(result));
                         versionInfos.put(result.pkgSetting.pkg.packageName,
                                 getSettingsVersionForPackage(result.pkgSetting.pkg));
                         if (result.staticSharedLibraryInfo != null) {
@@ -16797,7 +16859,9 @@
         } finally {
             if (!success) {
                 for (ScanResult result : preparedScans.values()) {
-                    unprepareScanResultLocked(result);
+                    if (createdAppId.getOrDefault(result.request.pkg.packageName, false)) {
+                        cleanUpAppIdCreation(result);
+                    }
                 }
             }
             for (PrepareResult result : prepareResults.values()) {
@@ -19890,26 +19954,28 @@
         mPermissionManager.enforceCrossUserPermission(callingUid, userId,
                 true /* requireFullPermission */, false /* checkShell */,
                 "replace preferred activity");
-        synchronized (mPackages) {
-            if (mContext.checkCallingOrSelfPermission(
-                    android.Manifest.permission.SET_PREFERRED_APPLICATIONS)
-                    != PackageManager.PERMISSION_GRANTED) {
+        if (mContext.checkCallingOrSelfPermission(
+                android.Manifest.permission.SET_PREFERRED_APPLICATIONS)
+                != PackageManager.PERMISSION_GRANTED) {
+            synchronized (mPackages) {
                 if (getUidTargetSdkVersionLockedLPr(callingUid)
                         < Build.VERSION_CODES.FROYO) {
                     Slog.w(TAG, "Ignoring replacePreferredActivity() from uid "
                             + Binder.getCallingUid());
                     return;
                 }
-                mContext.enforceCallingOrSelfPermission(
-                        android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
             }
+            mContext.enforceCallingOrSelfPermission(
+                    android.Manifest.permission.SET_PREFERRED_APPLICATIONS, null);
+        }
 
-            PreferredIntentResolver pir = mSettings.mPreferredActivities.get(userId);
+        synchronized (mPackages) {
+            final PreferredIntentResolver pir = mSettings.mPreferredActivities.get(userId);
             if (pir != null) {
                 // Get all of the existing entries that exactly match this filter.
-                ArrayList<PreferredActivity> existing = pir.findFilters(filter);
+                final ArrayList<PreferredActivity> existing = pir.findFilters(filter);
                 if (existing != null && existing.size() == 1) {
-                    PreferredActivity cur = existing.get(0);
+                    final PreferredActivity cur = existing.get(0);
                     if (DEBUG_PREFERRED) {
                         Slog.i(TAG, "Checking replace of preferred:");
                         filter.dump(new LogPrinter(Log.INFO, TAG), "  ");
@@ -19939,14 +20005,13 @@
                         return;
                     }
                 }
-
                 if (existing != null) {
                     if (DEBUG_PREFERRED) {
                         Slog.i(TAG, existing.size() + " existing preferred matches for:");
                         filter.dump(new LogPrinter(Log.INFO, TAG), "  ");
                     }
-                    for (int i = 0; i < existing.size(); i++) {
-                        PreferredActivity pa = existing.get(i);
+                    for (int i = existing.size() - 1; i >= 0; --i) {
+                        final PreferredActivity pa = existing.get(i);
                         if (DEBUG_PREFERRED) {
                             Slog.i(TAG, "Removing existing preferred activity "
                                     + pa.mPref.mComponent + ":");
@@ -19956,9 +20021,9 @@
                     }
                 }
             }
-            addPreferredActivityInternal(filter, match, set, activity, true, userId,
-                    "Replacing preferred");
         }
+        addPreferredActivityInternal(filter, match, set, activity, true, userId,
+                "Replacing preferred");
     }
 
     @Override
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 4e4a0e4..6b804df 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -2423,6 +2423,16 @@
                     sessionParams.setStaged();
                     break;
                 case "--enable-rollback":
+                    if (params.installerPackageName == null) {
+                        // com.android.shell has the TEST_MANAGE_ROLLBACKS
+                        // permission needed to enable rollback for non-module
+                        // packages, which is likely what the user wants when
+                        // enabling rollback through the shell command. Set
+                        // the installer to com.android.shell if no installer
+                        // has been provided so that the user doesn't have to
+                        // remember to set it themselves.
+                        params.installerPackageName = "com.android.shell";
+                    }
                     sessionParams.installFlags |= PackageManager.INSTALL_ENABLE_ROLLBACK;
                     break;
                 default:
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 41a8a77..db2fba9 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -810,15 +810,20 @@
 
     /**
      * Registers a user ID with the system. Potentially allocates a new user ID.
+     * @return {@code true} if a new app ID was created in the process. {@code false} can be
+     *         returned in the case that a shared user ID already exists or the explicit app ID is
+     *         already registered.
      * @throws PackageManagerException If a user ID could not be allocated.
      */
-    void registerAppIdLPw(PackageSetting p) throws PackageManagerException {
+    boolean registerAppIdLPw(PackageSetting p) throws PackageManagerException {
+        final boolean createdNew;
         if (p.appId == 0) {
             // Assign new user ID
             p.appId = acquireAndRegisterNewAppIdLPw(p);
+            createdNew = true;
         } else {
             // Add new setting to list of user IDs
-            registerExistingAppIdLPw(p.appId, p, p.name);
+            createdNew = registerExistingAppIdLPw(p.appId, p, p.name);
         }
         if (p.appId < 0) {
             PackageManagerService.reportSettingsProblem(Log.WARN,
@@ -826,6 +831,7 @@
             throw new PackageManagerException(INSTALL_FAILED_INSUFFICIENT_STORAGE,
                     "Package " + p.name + " could not be assigned a valid UID");
         }
+        return createdNew;
     }
 
     /**
@@ -4413,7 +4419,7 @@
             ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION, "PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION",
             ApplicationInfo.PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE, "PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE",
             ApplicationInfo.PRIVATE_FLAG_ALLOW_AUDIO_PLAYBACK_CAPTURE, "ALLOW_AUDIO_PLAYBACK_CAPTURE",
-            ApplicationInfo.PRIVATE_FLAG_ALLOW_EXTERNAL_STORAGE_SANDBOX, "ALLOW_EXTERNAL_STORAGE_SANDBOX",
+            ApplicationInfo.PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE, "PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE",
             ApplicationInfo.PRIVATE_FLAG_BACKUP_IN_FOREGROUND, "BACKUP_IN_FOREGROUND",
             ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE, "CANT_SAVE_STATE",
             ApplicationInfo.PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE, "DEFAULT_TO_DEVICE_PROTECTED_STORAGE",
@@ -4737,7 +4743,7 @@
                 }
                 pw.print(prefix); pw.print("    "); pw.print(perm);
                 final BasePermission bp = mPermissions.getPermission(perm);
-                if (bp != null && bp.isRestricted()) {
+                if (bp != null && bp.isHardOrSoftRestricted()) {
                     pw.println(": restricted=true");
                 } else {
                     pw.println();
diff --git a/services/core/java/com/android/server/pm/permission/BasePermission.java b/services/core/java/com/android/server/pm/permission/BasePermission.java
index 490c647..6d22faa 100644
--- a/services/core/java/com/android/server/pm/permission/BasePermission.java
+++ b/services/core/java/com/android/server/pm/permission/BasePermission.java
@@ -203,12 +203,17 @@
                 && (perm.info.flags & PermissionInfo.FLAG_HARD_RESTRICTED) != 0;
     }
 
-    public boolean isRestricted() {
+    public boolean isHardOrSoftRestricted() {
         return perm != null && perm.info != null
                 && (perm.info.flags & (PermissionInfo.FLAG_HARD_RESTRICTED
                 | PermissionInfo.FLAG_SOFT_RESTRICTED)) != 0;
     }
 
+    public boolean isImmutablyRestricted() {
+        return perm != null && perm.info != null
+                && (perm.info.flags & PermissionInfo.FLAG_IMMUTABLY_RESTRICTED) != 0;
+    }
+
     public boolean isSignature() {
         return (protectionLevel & PermissionInfo.PROTECTION_MASK_BASE) ==
                 PermissionInfo.PROTECTION_SIGNATURE;
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index dd63e3c..9ede263 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -2059,7 +2059,7 @@
             return;
         }
 
-        if (RESTRICTED_PERMISSIONS_ENABLED && bp.isRestricted()
+        if (RESTRICTED_PERMISSIONS_ENABLED && bp.isHardOrSoftRestricted()
                 && (flags & PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT) == 0) {
             Log.e(TAG, "Cannot grant restricted non-exempt permission "
                     + permName + " for package " + packageName);
@@ -2241,7 +2241,7 @@
                 continue;
             }
 
-            if (!bp.isRestricted()) {
+            if (!bp.isHardOrSoftRestricted()) {
                 continue;
             }
 
@@ -2294,13 +2294,16 @@
 
             updatePermissions = true;
 
+            final boolean wasWhitelisted = (oldFlags
+                    & (PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT)) != 0;
+            final boolean isWhitelisted = (newFlags
+                    & (PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT)) != 0;
+
             // If the permission is policy fixed as granted but it is no longer
             // on any of the whitelists we need to clear the policy fixed flag
             // as whitelisting trumps policy i.e. policy cannot grant a non
             // grantable permission.
             if ((oldFlags & PackageManager.FLAG_PERMISSION_POLICY_FIXED) != 0) {
-                final boolean isWhitelisted = (newFlags
-                        & (PackageManager.FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT)) != 0;
                 final boolean isGranted = permissionsState.hasPermission(permissionName, userId);
                 if (!isWhitelisted && isGranted) {
                     mask |= PackageManager.FLAG_PERMISSION_POLICY_FIXED;
@@ -2308,6 +2311,14 @@
                 }
             }
 
+            // If we are whitelisting an app that does not support runtime permissions
+            // we need to make sure it goes through the permission review UI at launch.
+            if (pkg.applicationInfo.targetSdkVersion < Build.VERSION_CODES.M
+                    && !wasWhitelisted && isWhitelisted) {
+                mask |= PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
+                newFlags |= PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED;
+            }
+
             updatePermissionFlags(permissionName, pkg.packageName, mask, newFlags,
                     callingUid, userId, false, null /*callback*/);
         }
diff --git a/services/core/java/com/android/server/policy/PermissionPolicyService.java b/services/core/java/com/android/server/policy/PermissionPolicyService.java
index 1fd8b71..a280d83 100644
--- a/services/core/java/com/android/server/policy/PermissionPolicyService.java
+++ b/services/core/java/com/android/server/policy/PermissionPolicyService.java
@@ -19,6 +19,7 @@
 import static android.content.pm.PackageManager.FLAG_PERMISSION_APPLY_RESTRICTION;
 import static android.content.pm.PackageManager.GET_PERMISSIONS;
 
+import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
@@ -36,9 +37,7 @@
 import android.os.UserHandle;
 import android.permission.PermissionControllerManager;
 import android.permission.PermissionManagerInternal;
-import android.util.ArraySet;
 import android.util.Slog;
-import android.util.SparseArray;
 import android.util.SparseIntArray;
 
 import com.android.server.FgThread;
@@ -46,7 +45,6 @@
 import com.android.server.SystemService;
 
 import java.util.ArrayList;
-import java.util.List;
 import java.util.concurrent.CountDownLatch;
 
 /**
@@ -57,17 +55,10 @@
  * and app ops - and vise versa.
  */
 public final class PermissionPolicyService extends SystemService {
-    private static final String PLATFORM_PACKAGE = "android";
-
     private static final String LOG_TAG = PermissionPolicyService.class.getSimpleName();
 
-    // No need to lock as this is populated on boot when the OS is
-    // single threaded and is never mutated until a reboot.
-    private static final ArraySet<String> sAllRestrictedPermissions = new ArraySet<>();
-
     public PermissionPolicyService(@NonNull Context context) {
         super(context);
-        cacheAllRestrictedPermissions(context);
     }
 
     @Override
@@ -101,20 +92,6 @@
         startWatchingRuntimePermissionChanges(getContext(), userId);
     }
 
-    private static void cacheAllRestrictedPermissions(@NonNull Context context) {
-        try {
-            final PackageInfo packageInfo = context.getPackageManager()
-                    .getPackageInfo(PLATFORM_PACKAGE, PackageManager.GET_PERMISSIONS);
-            for (PermissionInfo permissionInfo : packageInfo.permissions) {
-                if (permissionInfo.isRestricted()) {
-                    sAllRestrictedPermissions.add(permissionInfo.name);
-                }
-            }
-        } catch (NameNotFoundException impossible) {
-            /* cannot happen */
-        }
-    }
-
     private static void grantOrUpgradeDefaultRuntimePermissionsInNeeded(@NonNull Context context,
             @UserIdInt int userId) {
         final PackageManagerInternal packageManagerInternal = LocalServices.getService(
@@ -162,7 +139,7 @@
     }
 
     private static @Nullable Context getUserContext(@NonNull Context context,
-            @NonNull UserHandle user) {
+            @Nullable UserHandle user) {
         if (context.getUser().equals(user)) {
             return context;
         } else {
@@ -230,18 +207,31 @@
         private final @NonNull SparseIntArray mAllUids = new SparseIntArray();
 
         /**
-         * All ops that need to be restricted
+         * All ops that need to be set to default
+         *
+         * Currently, only used by the restricted permissions logic.
          *
          * @see #syncRestrictedOps
          */
-        private final @NonNull ArrayList<OpToRestrict> mOpsToRestrict = new ArrayList<>();
+        private final @NonNull ArrayList<OpToRestrict> mOpsToDefault = new ArrayList<>();
 
         /**
-         * All ops that need to be unrestricted
+         * All ops that need to be flipped to allow if default.
+         *
+         * Currently, only used by the restricted permissions logic.
          *
          * @see #syncRestrictedOps
          */
-        private final @NonNull ArrayList<OpToUnrestrict> mOpsToUnrestrict = new ArrayList<>();
+        private final @NonNull ArrayList<OpToUnrestrict> mOpsToAllow = new ArrayList<>();
+
+        /**
+         * All ops that need to be flipped to ignore if default.
+         *
+         * Currently, only used by the restricted permissions logic.
+         *
+         * @see #syncRestrictedOps
+         */
+        private final @NonNull ArrayList<OpToUnrestrict> mOpsToIgnore = new ArrayList<>();
 
         /**
          * All foreground permissions
@@ -262,89 +252,20 @@
          * <p>This processes ops previously added by {@link #addOpIfRestricted}
          */
         private void syncRestrictedOps() {
-            final SparseIntArray unprocessedUids = mAllUids.clone();
-
-            // TRICKY: we set the app op for a restricted permission to allow if the app
-            // requesting the permission is whitelisted and to deny if the app requesting
-            // the permission is not whitelisted. However, there is another case where an
-            // app in a shared user can access a component in another app in the same shared
-            // user due to being in the same shared user and not by having the permission
-            // that guards the component form the rest of the world. We need to handle this.
-            // The way we do this is by setting app ops corresponding to non requested
-            // restricted permissions to allow as this would allow the shared uid access
-            // case and be okay for other apps as they would not have the permission and
-            // would fail on the permission checks before reaching the app op check.
-            final SparseArray<List<String>> unrequestedRestrictedPermissionsForUid =
-                    new SparseArray<>();
-
-            final int unrestrictCount = mOpsToUnrestrict.size();
-            for (int i = 0; i < unrestrictCount; i++) {
-                final OpToUnrestrict op = mOpsToUnrestrict.get(i);
-                setUidModeAllowed(op.code, op.uid, op.packageName);
-
-                // Keep track this permission was requested by the UID.
-                List<String> unrequestedRestrictedPermissions =
-                        unrequestedRestrictedPermissionsForUid.get(op.uid);
-                if (unrequestedRestrictedPermissions == null) {
-                    unrequestedRestrictedPermissions = new ArrayList<>(sAllRestrictedPermissions);
-                    unrequestedRestrictedPermissionsForUid.put(op.uid,
-                            unrequestedRestrictedPermissions);
-                }
-                unrequestedRestrictedPermissions.remove(AppOpsManager.opToPermission(op.code));
-
-                unprocessedUids.delete(op.uid);
+            final int allowCount = mOpsToAllow.size();
+            for (int i = 0; i < allowCount; i++) {
+                final OpToUnrestrict op = mOpsToAllow.get(i);
+                setUidModeAllowedIfDefault(op.code, op.uid, op.packageName);
             }
-            final int restrictCount = mOpsToRestrict.size();
-            for (int i = 0; i < restrictCount; i++) {
-                final OpToRestrict op = mOpsToRestrict.get(i);
+            final int ignoreCount = mOpsToIgnore.size();
+            for (int i = 0; i < ignoreCount; i++) {
+                final OpToUnrestrict op = mOpsToIgnore.get(i);
+                setUidModeIgnoredIfDefault(op.code, op.uid, op.packageName);
+            }
+            final int defaultCount = mOpsToDefault.size();
+            for (int i = 0; i < defaultCount; i++) {
+                final OpToRestrict op = mOpsToDefault.get(i);
                 setUidModeDefault(op.code, op.uid);
-
-                // Keep track this permission was requested by the UID.
-                List<String> unrequestedRestrictedPermissions =
-                        unrequestedRestrictedPermissionsForUid.get(op.uid);
-                if (unrequestedRestrictedPermissions == null) {
-                    unrequestedRestrictedPermissions = new ArrayList<>(sAllRestrictedPermissions);
-                    unrequestedRestrictedPermissionsForUid.put(op.uid,
-                            unrequestedRestrictedPermissions);
-                }
-                unrequestedRestrictedPermissions.remove(AppOpsManager.opToPermission(op.code));
-
-                unprocessedUids.delete(op.uid);
-            }
-
-            // Give root access
-            unprocessedUids.put(Process.ROOT_UID, Process.ROOT_UID);
-
-            // Add records for UIDs that don't use any restricted permissions.
-            final int uidCount = unprocessedUids.size();
-            for (int i = 0; i < uidCount; i++) {
-                final int uid = unprocessedUids.keyAt(i);
-                unrequestedRestrictedPermissionsForUid.put(uid,
-                        new ArrayList<>(sAllRestrictedPermissions));
-            }
-
-            // Flip ops for all unrequested restricted permission for the UIDs.
-            final int unrequestedUidCount = unrequestedRestrictedPermissionsForUid.size();
-            for (int i = 0; i < unrequestedUidCount; i++) {
-                final List<String> unrequestedRestrictedPermissions =
-                        unrequestedRestrictedPermissionsForUid.valueAt(i);
-                if (unrequestedRestrictedPermissions != null) {
-                    final int uid = unrequestedRestrictedPermissionsForUid.keyAt(i);
-                    final String[] packageNames = (uid != Process.ROOT_UID)
-                            ? mPackageManager.getPackagesForUid(uid)
-                            : new String[] {"root"};
-                    if (packageNames == null) {
-                        continue;
-                    }
-                    final int permissionCount = unrequestedRestrictedPermissions.size();
-                    for (int j = 0; j < permissionCount; j++) {
-                        final String permission = unrequestedRestrictedPermissions.get(j);
-                        for (String packageName : packageNames) {
-                            setUidModeAllowed(AppOpsManager.permissionToOpCode(permission), uid,
-                                    packageName);
-                        }
-                    }
-                }
             }
         }
 
@@ -411,12 +332,27 @@
 
             if (permissionInfo.isHardRestricted()) {
                 if (applyRestriction) {
-                    mOpsToRestrict.add(new OpToRestrict(uid, opCode));
+                    mOpsToDefault.add(new OpToRestrict(uid, opCode));
                 } else {
-                    mOpsToUnrestrict.add(new OpToUnrestrict(uid, pkg.packageName, opCode));
+                    mOpsToAllow.add(new OpToUnrestrict(uid, pkg.packageName, opCode));
                 }
             } else if (permissionInfo.isSoftRestricted()) {
-                //TODO: Implement soft restrictions like storage here.
+                // Storage uses a special app op to decide the mount state and
+                // supports soft restriction where the restricted state allows
+                // the permission but only for accessing the medial collections.
+                if (Manifest.permission.READ_EXTERNAL_STORAGE.equals(permission)
+                        || Manifest.permission.WRITE_EXTERNAL_STORAGE.equals(permission)) {
+                    if (applyRestriction) {
+                        mOpsToDefault.add(new OpToRestrict(uid,
+                                AppOpsManager.OP_LEGACY_STORAGE));
+                    } else if (pkg.applicationInfo.hasRequestedLegacyExternalStorage()) {
+                        mOpsToAllow.add(new OpToUnrestrict(uid, pkg.packageName,
+                                AppOpsManager.OP_LEGACY_STORAGE));
+                    } else {
+                        mOpsToIgnore.add(new OpToUnrestrict(uid, pkg.packageName,
+                                AppOpsManager.OP_LEGACY_STORAGE));
+                    }
+                }
             }
         }
 
@@ -474,11 +410,20 @@
             }
         }
 
-        private void setUidModeAllowed(int opCode, int uid, @NonNull String packageName) {
+        private void setUidModeAllowedIfDefault(int opCode, int uid, @NonNull String packageName) {
+            setUidModeIfDefault(opCode, uid, AppOpsManager.MODE_ALLOWED, packageName);
+        }
+
+        private void setUidModeIgnoredIfDefault(int opCode, int uid, @NonNull String packageName) {
+            setUidModeIfDefault(opCode, uid, AppOpsManager.MODE_IGNORED, packageName);
+        }
+
+        private void setUidModeIfDefault(int opCode, int uid, int mode,
+                @NonNull String packageName) {
             final int currentMode = mAppOpsManager.unsafeCheckOpRaw(AppOpsManager
                     .opToPublicName(opCode), uid, packageName);
             if (currentMode == AppOpsManager.MODE_DEFAULT) {
-                mAppOpsManager.setUidMode(opCode, uid, AppOpsManager.MODE_ALLOWED);
+                mAppOpsManager.setUidMode(opCode, uid, mode);
             }
         }
 
diff --git a/services/core/java/com/android/server/power/ThermalManagerService.java b/services/core/java/com/android/server/power/ThermalManagerService.java
index 0381445..1552fd5 100644
--- a/services/core/java/com/android/server/power/ThermalManagerService.java
+++ b/services/core/java/com/android/server/power/ThermalManagerService.java
@@ -312,10 +312,8 @@
                     if (!mThermalEventListeners.register(listener, null)) {
                         return false;
                     }
-                    if (mHalReady.get()) {
-                        // Notify its callback after new client registered.
-                        postEventListenerCurrentTemperatures(listener, null);
-                    }
+                    // Notify its callback after new client registered.
+                    postEventListenerCurrentTemperatures(listener, null);
                     return true;
                 } finally {
                     Binder.restoreCallingIdentity(token);
@@ -334,10 +332,8 @@
                     if (!mThermalEventListeners.register(listener, new Integer(type))) {
                         return false;
                     }
-                    if (mHalReady.get()) {
-                        // Notify its callback after new client registered.
-                        postEventListenerCurrentTemperatures(listener, new Integer(type));
-                    }
+                    // Notify its callback after new client registered.
+                    postEventListenerCurrentTemperatures(listener, new Integer(type));
                     return true;
                 } finally {
                     Binder.restoreCallingIdentity(token);
@@ -398,10 +394,8 @@
                     if (!mThermalStatusListeners.register(listener)) {
                         return false;
                     }
-                    if (mHalReady.get()) {
-                        // Notify its callback after new client registered.
-                        postStatusListener(listener);
-                    }
+                    // Notify its callback after new client registered.
+                    postStatusListener(listener);
                     return true;
                 } finally {
                     Binder.restoreCallingIdentity(token);
diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java
index b2ac1b8..654c477 100644
--- a/services/core/java/com/android/server/role/RoleManagerService.java
+++ b/services/core/java/com/android/server/role/RoleManagerService.java
@@ -147,6 +147,8 @@
 
         mLegacyRoleResolver = legacyRoleResolver;
 
+        RoleControllerManager.initializeRemoteServiceComponentName(context);
+
         mUserManagerInternal = LocalServices.getService(UserManagerInternal.class);
         mAppOpsManager = context.getSystemService(AppOpsManager.class);
 
@@ -231,7 +233,7 @@
             // Run grants again
             Slog.i(LOG_TAG, "Granting default permissions...");
             CompletableFuture<Void> result = new CompletableFuture<>();
-            getOrCreateControllerService(userId).grantDefaultRoles(FgThread.getExecutor(),
+            getOrCreateController(userId).grantDefaultRoles(FgThread.getExecutor(),
                     successful -> {
                         if (successful) {
                             userState.setPackagesHash(packagesHash);
@@ -318,7 +320,7 @@
     }
 
     @NonNull
-    private RoleControllerManager getOrCreateControllerService(@UserIdInt int userId) {
+    private RoleControllerManager getOrCreateController(@UserIdInt int userId) {
         synchronized (mLock) {
             RoleControllerManager controller = mControllers.get(userId);
             if (controller == null) {
@@ -330,7 +332,8 @@
                 } catch (NameNotFoundException e) {
                     throw new RuntimeException(e);
                 }
-                controller = new RoleControllerManager(context, FgThread.getHandler());
+                controller = RoleControllerManager.createWithInitializedRemoteServiceComponentName(
+                        FgThread.getHandler(), context);
                 mControllers.put(userId, controller);
             }
             return controller;
@@ -474,7 +477,7 @@
             Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
             Preconditions.checkNotNull(callback, "callback cannot be null");
 
-            getOrCreateControllerService(userId).onAddRoleHolder(roleName, packageName, flags,
+            getOrCreateController(userId).onAddRoleHolder(roleName, packageName, flags,
                     callback);
         }
 
@@ -494,7 +497,7 @@
             Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
             Preconditions.checkNotNull(callback, "callback cannot be null");
 
-            getOrCreateControllerService(userId).onRemoveRoleHolder(roleName, packageName, flags,
+            getOrCreateController(userId).onRemoveRoleHolder(roleName, packageName, flags,
                     callback);
         }
 
@@ -513,7 +516,7 @@
             Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
             Preconditions.checkNotNull(callback, "callback cannot be null");
 
-            getOrCreateControllerService(userId).onClearRoleHolders(roleName, flags, callback);
+            getOrCreateController(userId).onClearRoleHolders(roleName, flags, callback);
         }
 
         @Override
@@ -738,10 +741,10 @@
                 }
             });
             if (packageName != null) {
-                getOrCreateControllerService(userId).onAddRoleHolder(RoleManager.ROLE_BROWSER,
+                getOrCreateController(userId).onAddRoleHolder(RoleManager.ROLE_BROWSER,
                         packageName, 0, callback);
             } else {
-                getOrCreateControllerService(userId).onClearRoleHolders(RoleManager.ROLE_BROWSER, 0,
+                getOrCreateController(userId).onClearRoleHolders(RoleManager.ROLE_BROWSER, 0,
                         callback);
             }
             try {
@@ -762,10 +765,10 @@
                 }
             });
             if (packageName != null) {
-                getOrCreateControllerService(userId).onAddRoleHolder(RoleManager.ROLE_BROWSER,
+                getOrCreateController(userId).onAddRoleHolder(RoleManager.ROLE_BROWSER,
                         packageName, 0, callback);
             } else {
-                getOrCreateControllerService(userId).onClearRoleHolders(RoleManager.ROLE_BROWSER, 0,
+                getOrCreateController(userId).onClearRoleHolders(RoleManager.ROLE_BROWSER, 0,
                         callback);
             }
         }
@@ -791,10 +794,10 @@
                 callback.accept(successful);
             });
             if (packageName != null) {
-                getOrCreateControllerService(userId).onAddRoleHolder(RoleManager.ROLE_HOME,
+                getOrCreateController(userId).onAddRoleHolder(RoleManager.ROLE_HOME,
                         packageName, 0, remoteCallback);
             } else {
-                getOrCreateControllerService(userId).onClearRoleHolders(RoleManager.ROLE_HOME, 0,
+                getOrCreateController(userId).onClearRoleHolders(RoleManager.ROLE_HOME, 0,
                         remoteCallback);
             }
         }
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index 44ed070..da9bc16 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -64,6 +64,7 @@
 import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
+import android.os.CoolingDevice;
 import android.os.Environment;
 import android.os.FileUtils;
 import android.os.Handler;
@@ -1798,6 +1799,28 @@
                 e.writeInt(temp.getType());
                 e.writeString(temp.getName());
                 e.writeInt((int) (temp.getValue() * 10));
+                e.writeInt(temp.getStatus());
+                pulledData.add(e);
+            }
+        } catch (RemoteException e) {
+            // Should not happen.
+            Slog.e(TAG, "Disconnected from thermal service. Cannot pull temperatures.");
+        } finally {
+            Binder.restoreCallingIdentity(callingToken);
+        }
+    }
+
+    private void pullCoolingDevices(int tagId, long elapsedNanos, long wallClockNanos,
+            List<StatsLogEventWrapper> pulledData) {
+        long callingToken = Binder.clearCallingIdentity();
+        try {
+            List<CoolingDevice> devices = sThermalService.getCurrentCoolingDevices();
+            for (CoolingDevice device : devices) {
+                StatsLogEventWrapper e =
+                        new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
+                e.writeInt(device.getType());
+                e.writeString(device.getName());
+                e.writeInt((int) (device.getValue()));
                 pulledData.add(e);
             }
         } catch (RemoteException e) {
@@ -2271,6 +2294,10 @@
                 pullTemperature(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
+            case StatsLog.COOLING_DEVICE: {
+                pullCoolingDevices(tagId, elapsedNanos, wallClockNanos, ret);
+                break;
+            }
             case StatsLog.DEBUG_ELAPSED_CLOCK: {
                 pullDebugElapsedClock(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
@@ -2535,12 +2562,9 @@
     private static final class ThermalEventListener extends IThermalEventListener.Stub {
         @Override
         public void notifyThrottling(Temperature temp) {
-            boolean isThrottling = temp.getStatus() >= Temperature.THROTTLING_SEVERE;
             StatsLog.write(StatsLog.THERMAL_THROTTLING, temp.getType(),
-                    isThrottling ?
-                            StatsLog.THERMAL_THROTTLING_STATE_CHANGED__STATE__START :
-                            StatsLog.THERMAL_THROTTLING_STATE_CHANGED__STATE__STOP,
-                    temp.getValue());
+                    StatsLog.THERMAL_THROTTLING_STATE_CHANGED__STATE__UNKNOWN,
+                    temp.getValue(), temp.getStatus(), temp.getName());
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index ea9477f..4ef8753 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -971,8 +971,9 @@
                 : (realCallingUid == Process.SYSTEM_UID)
                         || realCallingUidProcState <= ActivityManager.PROCESS_STATE_PERSISTENT_UI;
         if (realCallingUid != callingUid) {
-            // don't abort if the realCallingUid has a visible window
-            if (realCallingUidHasAnyVisibleWindow) {
+            // don't abort if the realCallingUid has a visible window, unless realCallingUid is
+            // SYSTEM_UID, in which case it start needs to be explicitly whitelisted
+            if (realCallingUidHasAnyVisibleWindow && realCallingUid != Process.SYSTEM_UID) {
                 return false;
             }
             // if the realCallingUid is a persistent system process, abort if the IntentSender
diff --git a/services/core/java/com/android/server/wm/BoundsAnimationController.java b/services/core/java/com/android/server/wm/BoundsAnimationController.java
index c1d872f..b5e7067 100644
--- a/services/core/java/com/android/server/wm/BoundsAnimationController.java
+++ b/services/core/java/com/android/server/wm/BoundsAnimationController.java
@@ -435,6 +435,18 @@
                 moveFromFullscreen, moveToFullscreen, animationType);
     }
 
+    /**
+     * Cancel existing animation if the destination was modified.
+     */
+    void cancel(final BoundsAnimationTarget target) {
+        final BoundsAnimator existing = mRunningAnimations.get(target);
+        if (existing != null) {
+            // Cancel animation. Since its already started, send animation end to client.
+            if (DEBUG) Slog.d(TAG, "cancel: mTarget= " + target);
+            existing.cancelAndCallAnimationEnd();
+        }
+    }
+
     @VisibleForTesting
     BoundsAnimator animateBoundsImpl(final BoundsAnimationTarget target, Rect from, Rect to,
             int animationDuration, @SchedulePipModeChangedState int schedulePipModeChangedState,
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index f9fd541..9f42324 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -22,6 +22,7 @@
 import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SUSTAINED_PERFORMANCE_MODE;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
 import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
 import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
@@ -312,11 +313,12 @@
 
     /**
      * Returns true if the callingUid has any non-toast window currently visible to the user.
+     * Also ignores TYPE_APPLICATION_STARTING, since those windows don't belong to apps.
      */
     boolean isAnyNonToastWindowVisibleForUid(int callingUid) {
         return forAllWindows(w ->
                         w.getOwningUid() == callingUid && w.mAttrs.type != TYPE_TOAST
-                        && w.isVisibleNow(),
+                        && w.mAttrs.type != TYPE_APPLICATION_STARTING && w.isVisibleNow(),
                 true /* traverseTopToBottom */);
     }
 
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index bdb4d04..7515b3f 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -388,7 +388,9 @@
      * @return true if bounds were updated to some non-empty value.
      */
     boolean calculatePinnedBoundsForConfigChange(Rect inOutBounds) {
+        boolean animating = false;
         if ((mBoundsAnimatingRequested || mBoundsAnimating) && !mBoundsAnimationTarget.isEmpty()) {
+            animating = true;
             getFinalAnimationBounds(mTmpRect2);
         } else {
             mTmpRect2.set(inOutBounds);
@@ -398,6 +400,13 @@
         if (updated) {
             inOutBounds.set(mTmpRect3);
 
+            // The final boundary is updated while there is an existing boundary animation. Let's
+            // cancel this animation to prevent the obsolete animation overwritten updated bounds.
+            if (animating && !inOutBounds.equals(mBoundsAnimationTarget)) {
+                final DisplayContent displayContent = getDisplayContent();
+                displayContent.mBoundsAnimationController.getHandler().post(() ->
+                        displayContent.mBoundsAnimationController.cancel(this));
+            }
             // Once we've set the bounds based on the rotation of the old bounds in the new
             // orientation, clear the animation target bounds since they are obsolete, and
             // cancel any currently running animations
@@ -1585,7 +1594,6 @@
 
             mBoundsAnimatingRequested = false;
             mBoundsAnimating = true;
-            mCancelCurrentBoundsAnimation = false;
             mAnimationType = animationType;
 
             // If we are changing UI mode, as in the PiP to fullscreen
@@ -1645,7 +1653,7 @@
                         mBoundsAnimationTarget, false /* forceUpdate */);
             }
 
-            if (finalStackSize != null) {
+            if (finalStackSize != null && !mCancelCurrentBoundsAnimation) {
                 setPinnedStackSize(finalStackSize, null);
             } else {
                 // We have been canceled, so the final stack size is null, still run the
@@ -1758,6 +1766,7 @@
         }
 
         final @BoundsAnimationController.AnimationType int animationType = intendedAnimationType;
+        mCancelCurrentBoundsAnimation = false;
         displayContent.mBoundsAnimationController.getHandler().post(() -> {
             displayContent.mBoundsAnimationController.animateBounds(this, fromBounds,
                     finalToBounds, animationDuration, finalSchedulePipModeChangedState,
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 0cd730b..2a2de77 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -32,7 +32,6 @@
 import android.content.Intent;
 import android.content.pm.PackageItemInfo;
 import android.content.pm.PackageManager;
-import android.content.pm.PackageManagerInternal;
 import android.content.res.Configuration;
 import android.content.res.Resources.Theme;
 import android.database.sqlite.SQLiteCompatibilityWalFlags;
@@ -1248,11 +1247,6 @@
             mSystemServiceManager.startService(CONTENT_SUGGESTIONS_SERVICE_CLASS);
             traceEnd();
 
-            // NOTE: ClipboardService indirectly depends on IntelligenceService
-            traceBeginAndSlog("StartClipboardService");
-            mSystemServiceManager.startService(ClipboardService.class);
-            traceEnd();
-
             traceBeginAndSlog("InitNetworkStackClient");
             try {
                 NetworkStackClient.getInstance().init();
@@ -1887,6 +1881,11 @@
             traceEnd();
         }
 
+        // NOTE: ClipboardService depends on ContentCapture and Autofill
+        traceBeginAndSlog("StartClipboardService");
+        mSystemServiceManager.startService(ClipboardService.class);
+        traceEnd();
+
         traceBeginAndSlog("AppServiceManager");
         mSystemServiceManager.startService(AppBindingService.Lifecycle.class);
         traceEnd();
diff --git a/services/net/java/android/net/ip/RouterAdvertisementDaemon.java b/services/net/java/android/net/ip/RouterAdvertisementDaemon.java
index 339607b..59aea21 100644
--- a/services/net/java/android/net/ip/RouterAdvertisementDaemon.java
+++ b/services/net/java/android/net/ip/RouterAdvertisementDaemon.java
@@ -36,6 +36,7 @@
 import android.util.Log;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.util.TrafficStatsConstants;
 
 import libcore.io.IoBridge;
 
@@ -586,7 +587,8 @@
     private boolean createSocket() {
         final int SEND_TIMEOUT_MS = 300;
 
-        final int oldTag = TrafficStats.getAndSetThreadStatsTag(TrafficStats.TAG_SYSTEM_NEIGHBOR);
+        final int oldTag = TrafficStats.getAndSetThreadStatsTag(
+                TrafficStatsConstants.TAG_SYSTEM_NEIGHBOR);
         try {
             mSocket = Os.socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6);
             // Setting SNDTIMEO is purely for defensive purposes.
diff --git a/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java b/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java
index c8d1eb4..74fe81c 100644
--- a/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java
@@ -30,6 +30,7 @@
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 import static org.robolectric.Shadows.shadowOf;
@@ -38,6 +39,7 @@
 import android.app.backup.BackupManager;
 import android.app.backup.IBackupObserver;
 import android.app.backup.ISelectBackupTransportCallback;
+import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.ContextWrapper;
@@ -48,6 +50,7 @@
 import android.os.HandlerThread;
 import android.os.PowerManager;
 import android.os.PowerSaveState;
+import android.os.UserHandle;
 import android.platform.test.annotations.Presubmit;
 import android.provider.Settings;
 
@@ -66,6 +69,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
+import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
@@ -1130,6 +1134,31 @@
                                 /* transportManager */ null));
     }
 
+    /**
+     * Test verifying that creating a new instance registers the broadcast receiver for package
+     * tracking
+     */
+    @Test
+    public void testCreateAndInitializeService_registersPackageTrackingReceiver() throws Exception {
+        Context contextSpy = Mockito.spy(mContext);
+
+        UserBackupManagerService service = UserBackupManagerService.createAndInitializeService(
+                USER_ID,
+                contextSpy,
+                new Trampoline(mContext),
+                mBackupThread,
+                mBaseStateDir,
+                mDataDir,
+                mTransportManager);
+
+        BroadcastReceiver packageTrackingReceiver = service.getPackageTrackingReceiver();
+        assertThat(packageTrackingReceiver).isNotNull();
+
+        // One call for package changes and one call for sd card events.
+        verify(contextSpy, times(2)).registerReceiverAsUser(
+                eq(packageTrackingReceiver), eq(UserHandle.of(USER_ID)), any(), any(), any());
+    }
+
     private UserBackupManagerService createUserBackupManagerServiceAndRunTasks() {
         return BackupManagerServiceTestUtils.createUserBackupManagerServiceAndRunTasks(
                 USER_ID, mContext, mBackupThread, mBaseStateDir, mDataDir, mTransportManager);
diff --git a/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java b/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
index 164570a..cc64323 100644
--- a/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/keyvalue/KeyValueBackupTaskTest.java
@@ -86,6 +86,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
+import android.content.pm.PackageManagerInternal;
 import android.net.Uri;
 import android.os.ConditionVariable;
 import android.os.DeadObjectException;
@@ -100,6 +101,7 @@
 
 import com.android.internal.backup.IBackupTransport;
 import com.android.server.EventLogTags;
+import com.android.server.LocalServices;
 import com.android.server.backup.BackupRestoreTask;
 import com.android.server.backup.DataChangedJournal;
 import com.android.server.backup.KeyValueBackupJob;
@@ -116,7 +118,6 @@
 import com.android.server.backup.testing.TransportTestUtils.TransportMock;
 import com.android.server.testing.shadows.FrameworkShadowLooper;
 import com.android.server.testing.shadows.ShadowApplicationPackageManager;
-import com.android.server.testing.shadows.ShadowBackupActivityThread;
 import com.android.server.testing.shadows.ShadowBackupDataInput;
 import com.android.server.testing.shadows.ShadowBackupDataOutput;
 import com.android.server.testing.shadows.ShadowEventLog;
@@ -163,8 +164,7 @@
             ShadowBackupDataInput.class,
             ShadowBackupDataOutput.class,
             ShadowEventLog.class,
-            ShadowQueuedWork.class,
-            ShadowBackupActivityThread.class,
+            ShadowQueuedWork.class
         })
 @Presubmit
 public class KeyValueBackupTaskTest {
@@ -179,6 +179,7 @@
     @Mock private IBackupObserver mObserver;
     @Mock private IBackupManagerMonitor mMonitor;
     @Mock private OnTaskFinishedListener mListener;
+    @Mock private PackageManagerInternal mPackageManagerInternal;
     private UserBackupManagerService mBackupManagerService;
     private TransportData mTransport;
     private ShadowLooper mShadowBackupLooper;
@@ -243,6 +244,11 @@
         mShadowBackupLooper = shadowOf(mBackupHandler.getLooper());
         ShadowEventLog.setUp();
         mReporter = spy(new KeyValueBackupReporter(mBackupManagerService, mObserver, mMonitor));
+
+        when(mPackageManagerInternal.getApplicationEnabledState(any(), anyInt()))
+                .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
+        LocalServices.removeServiceForTest(PackageManagerInternal.class);
+        LocalServices.addService(PackageManagerInternal.class, mPackageManagerInternal);
     }
 
     @After
@@ -471,7 +477,7 @@
         TransportMock transportMock = setUpInitializedTransport(mTransport);
         setUpAgentWithData(PACKAGE_1);
         BackupAgent pmAgent = spy(createPmAgent());
-        when(mBackupManagerService.makeMetadataAgent()).thenReturn(forward(pmAgent));
+        doReturn(forward(pmAgent)).when(mBackupManagerService).makeMetadataAgent();
         KeyValueBackupTask task = createKeyValueBackupTask(transportMock, true, PACKAGE_1);
 
         runTask(task);
@@ -484,7 +490,7 @@
         TransportMock transportMock = setUpInitializedTransport(mTransport);
         setUpAgentWithData(PACKAGE_1);
         BackupAgent pmAgent = spy(createPmAgent());
-        when(mBackupManagerService.makeMetadataAgent()).thenReturn(forward(pmAgent));
+        doReturn(forward(pmAgent)).when(mBackupManagerService).makeMetadataAgent();
         KeyValueBackupTask task =
                 createKeyValueBackupTask(transportMock, true, PACKAGE_1, PM_PACKAGE);
 
@@ -498,7 +504,7 @@
         TransportMock transportMock = setUpInitializedTransport(mTransport);
         setUpAgentWithData(PACKAGE_1);
         BackupAgent pmAgent = spy(createPmAgent());
-        when(mBackupManagerService.makeMetadataAgent()).thenReturn(forward(pmAgent));
+        doReturn(forward(pmAgent)).when(mBackupManagerService).makeMetadataAgent();
         KeyValueBackupTask task = createKeyValueBackupTask(transportMock, false, PACKAGE_1);
 
         runTask(task);
@@ -1307,7 +1313,7 @@
                         argThat(packageInfo(PM_PACKAGE)), any(), anyInt()))
                 .then(copyBackupDataTo(backupDataPath));
         BackupAgent pmAgent = spy(createPmAgent());
-        when(mBackupManagerService.makeMetadataAgent()).thenReturn(forward(pmAgent));
+        doReturn(forward(pmAgent)).when(mBackupManagerService).makeMetadataAgent();
         agentOnBackupDo(
                 pmAgent,
                 (oldState, dataOutput, newState) -> {
@@ -1371,7 +1377,7 @@
         setUpAgent(PACKAGE_1);
         when(transportMock.transport.finishBackup()).thenReturn(BackupTransport.TRANSPORT_OK);
         BackupAgent pmAgent = spy(createPmAgent());
-        when(mBackupManagerService.makeMetadataAgent()).thenReturn(forward(pmAgent));
+        doReturn(forward(pmAgent)).when(mBackupManagerService).makeMetadataAgent();
         agentOnBackupDo(
                 pmAgent,
                 (oldState, dataOutput, newState) -> {
@@ -1395,7 +1401,7 @@
         setUpAgent(PACKAGE_1);
         when(transportMock.transport.finishBackup()).thenReturn(BackupTransport.TRANSPORT_OK);
         BackupAgent pmAgent = spy(createPmAgent());
-        when(mBackupManagerService.makeMetadataAgent()).thenReturn(forward(pmAgent));
+        doReturn(forward(pmAgent)).when(mBackupManagerService).makeMetadataAgent();
         agentOnBackupDo(
                 pmAgent,
                 (oldState, dataOutput, newState) -> {
@@ -1957,7 +1963,7 @@
         TransportMock transportMock = setUpInitializedTransport(mTransport);
         setUpAgent(PACKAGE_1);
         BackupAgent pmAgent = createThrowingPmAgent(new RuntimeException());
-        when(mBackupManagerService.makeMetadataAgent()).thenReturn(pmAgent);
+        doReturn(pmAgent).when(mBackupManagerService).makeMetadataAgent();
         KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
 
         runTask(task);
@@ -1970,7 +1976,7 @@
         TransportMock transportMock = setUpInitializedTransport(mTransport);
         setUpAgent(PACKAGE_1);
         BackupAgent pmAgent = createThrowingPmAgent(new RuntimeException());
-        when(mBackupManagerService.makeMetadataAgent()).thenReturn(pmAgent);
+        doReturn(pmAgent).when(mBackupManagerService).makeMetadataAgent();
         KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
 
         runTask(task);
@@ -1983,7 +1989,7 @@
         TransportMock transportMock = setUpInitializedTransport(mTransport);
         setUpAgent(PACKAGE_1);
         BackupAgent pmAgent = createThrowingPmAgent(new RuntimeException());
-        when(mBackupManagerService.makeMetadataAgent()).thenReturn(pmAgent);
+        doReturn(pmAgent).when(mBackupManagerService).makeMetadataAgent();
         KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
 
         runTask(task);
@@ -1996,7 +2002,7 @@
         TransportMock transportMock = setUpInitializedTransport(mTransport);
         setUpAgent(PACKAGE_1);
         BackupAgent pmAgent = spy(createPmAgent());
-        when(mBackupManagerService.makeMetadataAgent()).thenReturn(forward(pmAgent));
+        doReturn(forward(pmAgent)).when(mBackupManagerService).makeMetadataAgent();
         KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
         agentOnBackupDo(
                 pmAgent, (oldState, dataOutput, newState) -> runInWorkerThread(task::markCancel));
@@ -2011,7 +2017,7 @@
         TransportMock transportMock = setUpInitializedTransport(mTransport);
         setUpAgent(PACKAGE_1);
         BackupAgent pmAgent = spy(createPmAgent());
-        when(mBackupManagerService.makeMetadataAgent()).thenReturn(forward(pmAgent));
+        doReturn(forward(pmAgent)).when(mBackupManagerService).makeMetadataAgent();
         KeyValueBackupTask task = createKeyValueBackupTask(transportMock, PACKAGE_1);
         agentOnBackupDo(
                 pmAgent, (oldState, dataOutput, newState) -> runInWorkerThread(task::markCancel));
diff --git a/services/robotests/src/com/android/server/testing/shadows/ShadowBackupActivityThread.java b/services/robotests/src/com/android/server/testing/shadows/ShadowBackupActivityThread.java
deleted file mode 100644
index ca2e3b6..0000000
--- a/services/robotests/src/com/android/server/testing/shadows/ShadowBackupActivityThread.java
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * 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.testing.shadows;
-
-import android.app.ActivityThread;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.IPackageManager;
-import android.content.pm.PackageManager;
-import android.os.RemoteException;
-
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.Implementation;
-import org.robolectric.annotation.Implements;
-import org.robolectric.shadows.ShadowActivityThread;
-
-import java.lang.reflect.InvocationHandler;
-import java.lang.reflect.Method;
-import java.lang.reflect.Proxy;
-
-import javax.annotation.Nonnull;
-
-/**
- * Extends the existing {@link ShadowActivityThread} to add support for
- * {@link PackageManager#getApplicationEnabledSetting(String)} in the shadow {@link PackageManager}
- * returned  by {@link ShadowBackupActivityThread#getPackageManager()}.
- */
-@Implements(value = ActivityThread.class, isInAndroidSdk = false, looseSignatures = true)
-public class ShadowBackupActivityThread extends ShadowActivityThread {
-    @Implementation
-    public static Object getPackageManager() {
-        ClassLoader classLoader = ShadowActivityThread.class.getClassLoader();
-        Class<?> iPackageManagerClass;
-        try {
-            iPackageManagerClass = classLoader.loadClass("android.content.pm.IPackageManager");
-        } catch (ClassNotFoundException e) {
-            throw new RuntimeException(e);
-        }
-
-        return Proxy.newProxyInstance(
-                classLoader,
-                new Class[] {iPackageManagerClass},
-                new InvocationHandler() {
-                    @Override
-                    public Object invoke(Object proxy, @Nonnull Method method, Object[] args)
-                            throws Exception {
-                        if (method.getName().equals("getApplicationInfo")) {
-                            String packageName = (String) args[0];
-                            int flags = (Integer) args[1];
-
-                            try {
-                                return RuntimeEnvironment.application
-                                        .getPackageManager()
-                                        .getApplicationInfo(packageName, flags);
-                            } catch (PackageManager.NameNotFoundException e) {
-                                throw new RemoteException(e.getMessage());
-                            }
-                        } else if (method.getName().equals("getApplicationEnabledSetting")) {
-                            return 0;
-                        } else {
-                            return null;
-                        }
-                    }
-                });
-    }
-}
diff --git a/services/tests/servicestests/src/com/android/server/attention/AttentionManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/attention/AttentionManagerServiceTest.java
new file mode 100644
index 0000000..8426a0b
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/attention/AttentionManagerServiceTest.java
@@ -0,0 +1,145 @@
+/*
+ * 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.attention;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.anyLong;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.verify;
+
+import android.attention.AttentionManagerInternal.AttentionCallbackInternal;
+import android.content.ComponentName;
+import android.content.Context;
+import android.os.IBinder;
+import android.os.IPowerManager;
+import android.os.PowerManager;
+import android.os.RemoteException;
+import android.service.attention.IAttentionCallback;
+import android.service.attention.IAttentionService;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.server.attention.AttentionManagerService.AttentionCheck;
+import com.android.server.attention.AttentionManagerService.AttentionHandler;
+import com.android.server.attention.AttentionManagerService.UserState;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Tests for {@link com.android.server.attention.AttentionManagerService}
+ */
+@SmallTest
+public class AttentionManagerServiceTest {
+    private AttentionManagerService mSpyAttentionManager;
+    private UserState mSpyUserState;
+    private final int mTimeout = 1000;
+    @Mock private AttentionCallbackInternal mMockAttentionCallbackInternal;
+    @Mock private AttentionHandler mMockHandler;
+    @Mock private IAttentionCallback mMockIAttentionCallback;
+    @Mock private IPowerManager mMockIPowerManager;
+    @Mock Context mContext;
+
+    @Before
+    public void setUp() throws RemoteException {
+        MockitoAnnotations.initMocks(this);
+        // setup context mock
+        doReturn(true).when(mContext).bindServiceAsUser(any(), any(), anyInt(), any());
+        // setup power manager mock
+        PowerManager mPowerManager;
+        doReturn(true).when(mMockIPowerManager).isInteractive();
+        mPowerManager = new PowerManager(mContext, mMockIPowerManager, null);
+
+        Object mLock = new Object();
+        // setup a spy on attention manager
+        AttentionManagerService mAttentionManager = new AttentionManagerService(
+                mContext,
+                mPowerManager,
+                mLock,
+                mMockHandler);
+        mSpyAttentionManager = Mockito.spy(mAttentionManager);
+        // setup a spy on user state
+        ComponentName componentName = new ComponentName("a", "b");
+        mSpyAttentionManager.mComponentName = componentName;
+        UserState mUserState = new UserState(0,
+                mContext,
+                mLock,
+                componentName);
+        mUserState.mService = new MockIAttentionService();
+        mSpyUserState = spy(mUserState);
+    }
+
+    @Test
+    public void testCancelAttentionCheck_noCrashWhenNoUserStateLocked() {
+        mSpyAttentionManager.cancelAttentionCheck(null);
+    }
+
+    @Test
+    public void testCancelAttentionCheck_noCrashWhenCallbackMismatched() {
+        mSpyUserState.mCurrentAttentionCheck =
+                new AttentionCheck(mMockAttentionCallbackInternal, mMockIAttentionCallback);
+        doReturn(mSpyUserState).when(mSpyAttentionManager).peekCurrentUserStateLocked();
+        mSpyAttentionManager.cancelAttentionCheck(null);
+    }
+
+    @Test
+    public void testCancelAttentionCheck_cancelCallbackWhenMatched() {
+        mSpyUserState.mCurrentAttentionCheck =
+                new AttentionCheck(mMockAttentionCallbackInternal, mMockIAttentionCallback);
+        doReturn(mSpyUserState).when(mSpyAttentionManager).peekCurrentUserStateLocked();
+        mSpyAttentionManager.cancelAttentionCheck(mMockAttentionCallbackInternal);
+        verify(mSpyAttentionManager).cancel(any());
+    }
+
+    @Test
+    public void testCheckAttention_returnFalseWhenPowerManagerNotInteract() throws RemoteException {
+        doReturn(false).when(mMockIPowerManager).isInteractive();
+        AttentionCallbackInternal callback = Mockito.mock(AttentionCallbackInternal.class);
+        assertThat(mSpyAttentionManager.checkAttention(mTimeout, callback)).isFalse();
+    }
+
+    @Test
+    public void testCheckAttention_callOnSuccess() throws RemoteException {
+        doReturn(true).when(mSpyAttentionManager).isServiceEnabled();
+        doReturn(true).when(mMockIPowerManager).isInteractive();
+        doReturn(mSpyUserState).when(mSpyAttentionManager).getOrCreateCurrentUserStateLocked();
+        doNothing().when(mSpyAttentionManager).freeIfInactiveLocked();
+
+        AttentionCallbackInternal callback = Mockito.mock(AttentionCallbackInternal.class);
+        mSpyAttentionManager.checkAttention(mTimeout, callback);
+        verify(callback).onSuccess(anyInt(), anyLong());
+    }
+
+    private class MockIAttentionService implements IAttentionService {
+        public void checkAttention(IAttentionCallback callback) throws RemoteException {
+            callback.onSuccess(0, 0);
+        }
+        public void cancelAttentionCheck(IAttentionCallback callback) {
+        }
+        public IBinder asBinder() {
+            return null;
+        }
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java b/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java
deleted file mode 100644
index 97a6e66..0000000
--- a/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java
+++ /dev/null
@@ -1,1217 +0,0 @@
-/*
- * 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.backup.testutils;
-
-import android.content.ComponentName;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.IntentSender;
-import android.content.pm.ActivityInfo;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.ChangedPackages;
-import android.content.pm.IDexModuleRegisterCallback;
-import android.content.pm.IOnPermissionsChangeListener;
-import android.content.pm.IPackageDataObserver;
-import android.content.pm.IPackageDeleteObserver;
-import android.content.pm.IPackageDeleteObserver2;
-import android.content.pm.IPackageInstaller;
-import android.content.pm.IPackageManager;
-import android.content.pm.IPackageMoveObserver;
-import android.content.pm.IPackageStatsObserver;
-import android.content.pm.InstrumentationInfo;
-import android.content.pm.KeySet;
-import android.content.pm.ModuleInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.ParceledListSlice;
-import android.content.pm.PermissionGroupInfo;
-import android.content.pm.PermissionInfo;
-import android.content.pm.ProviderInfo;
-import android.content.pm.ResolveInfo;
-import android.content.pm.ServiceInfo;
-import android.content.pm.SuspendDialogInfo;
-import android.content.pm.VerifierDeviceIdentity;
-import android.content.pm.VersionedPackage;
-import android.content.pm.dex.IArtManager;
-import android.graphics.Bitmap;
-import android.os.IBinder;
-import android.os.PersistableBundle;
-import android.os.RemoteException;
-
-import java.util.List;
-
-/**
- * Stub for IPackageManager to use in tests.
- */
-public class IPackageManagerStub implements IPackageManager {
-    public static PackageInfo sPackageInfo;
-    public static int sApplicationEnabledSetting = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
-
-    @Override
-    public PackageInfo getPackageInfo(String packageName, int flags, int userId)
-        throws RemoteException {
-        return sPackageInfo;
-    }
-
-    @Override
-    public int getApplicationEnabledSetting(String packageName, int userId) throws RemoteException {
-        return sApplicationEnabledSetting;
-    }
-
-    @Override
-    public void checkPackageStartable(String packageName, int userId) throws RemoteException {
-
-    }
-
-    @Override
-    public boolean isPackageAvailable(String packageName, int userId) throws RemoteException {
-        return false;
-    }
-
-    @Override
-    public PackageInfo getPackageInfoVersioned(VersionedPackage versionedPackage, int flags,
-        int userId) throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public int getPackageUid(String packageName, int flags, int userId) throws RemoteException {
-        return 0;
-    }
-
-    @Override
-    public int[] getPackageGids(String packageName, int flags, int userId) throws RemoteException {
-        return new int[0];
-    }
-
-    @Override
-    public String[] currentToCanonicalPackageNames(String[] names) throws RemoteException {
-        return new String[0];
-    }
-
-    @Override
-    public String[] canonicalToCurrentPackageNames(String[] names) throws RemoteException {
-        return new String[0];
-    }
-
-    @Override
-    public PermissionInfo getPermissionInfo(String name, String packageName, int flags)
-        throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public ParceledListSlice queryPermissionsByGroup(String group, int flags)
-        throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public PermissionGroupInfo getPermissionGroupInfo(String name, int flags)
-        throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public ParceledListSlice getAllPermissionGroups(int flags) throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public ApplicationInfo getApplicationInfo(String packageName, int flags, int userId)
-        throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public ActivityInfo getActivityInfo(ComponentName className, int flags, int userId)
-        throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public boolean activitySupportsIntent(ComponentName className, Intent intent,
-        String resolvedType)
-        throws RemoteException {
-        return false;
-    }
-
-    @Override
-    public ActivityInfo getReceiverInfo(ComponentName className, int flags, int userId)
-        throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public ServiceInfo getServiceInfo(ComponentName className, int flags, int userId)
-        throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public ProviderInfo getProviderInfo(ComponentName className, int flags, int userId)
-        throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public int checkPermission(String permName, String pkgName, int userId) throws RemoteException {
-        return 0;
-    }
-
-    @Override
-    public int checkUidPermission(String permName, int uid) throws RemoteException {
-        return 0;
-    }
-
-    @Override
-    public boolean addPermission(PermissionInfo info) throws RemoteException {
-        return false;
-    }
-
-    @Override
-    public void removePermission(String name) throws RemoteException {
-
-    }
-
-    @Override
-    public void grantRuntimePermission(String packageName, String permissionName, int userId)
-        throws RemoteException {
-
-    }
-
-    @Override
-    public void revokeRuntimePermission(String packageName, String permissionName, int userId)
-        throws RemoteException {
-
-    }
-
-    @Override
-    public void resetRuntimePermissions() throws RemoteException {
-
-    }
-
-    @Override
-    public int getPermissionFlags(String permissionName, String packageName, int userId)
-        throws RemoteException {
-        return 0;
-    }
-
-    @Override
-    public void updatePermissionFlags(String permissionName, String packageName, int flagMask,
-            int flagValues, boolean checkAdjustPolicyFlagPermission, int userId)
-            throws RemoteException {
-
-    }
-
-    @Override
-    public void updatePermissionFlagsForAllApps(int flagMask, int flagValues, int userId)
-        throws RemoteException {
-
-    }
-
-    @Override
-    public List<String> getWhitelistedRestrictedPermissions(String packageName, int flags,
-            int userId) throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public boolean addWhitelistedRestrictedPermission(String packageName, String permission,
-            int whitelistFlags, int userId) throws RemoteException {
-        return false;
-    }
-
-    @Override
-    public boolean removeWhitelistedRestrictedPermission(String packageName, String permission,
-            int whitelistFlags, int userId) throws RemoteException {
-        return false;
-    }
-
-    @Override
-    public boolean shouldShowRequestPermissionRationale(String permissionName, String packageName,
-        int userId) throws RemoteException {
-        return false;
-    }
-
-    @Override
-    public boolean isProtectedBroadcast(String actionName) throws RemoteException {
-        return false;
-    }
-
-    @Override
-    public int checkSignatures(String pkg1, String pkg2) throws RemoteException {
-        return 0;
-    }
-
-    @Override
-    public int checkUidSignatures(int uid1, int uid2) throws RemoteException {
-        return 0;
-    }
-
-    @Override
-    public List<String> getAllPackages() throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public String[] getPackagesForUid(int uid) throws RemoteException {
-        return new String[0];
-    }
-
-    @Override
-    public String getNameForUid(int uid) throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public String[] getNamesForUids(int[] uids) throws RemoteException {
-        return new String[0];
-    }
-
-    @Override
-    public int getUidForSharedUser(String sharedUserName) throws RemoteException {
-        return 0;
-    }
-
-    @Override
-    public int getFlagsForUid(int uid) throws RemoteException {
-        return 0;
-    }
-
-    @Override
-    public int getPrivateFlagsForUid(int uid) throws RemoteException {
-        return 0;
-    }
-
-    @Override
-    public boolean isUidPrivileged(int uid) throws RemoteException {
-        return false;
-    }
-
-    @Override
-    public String[] getAppOpPermissionPackages(String permissionName) throws RemoteException {
-        return new String[0];
-    }
-
-    @Override
-    public ResolveInfo resolveIntent(Intent intent, String resolvedType, int flags, int userId)
-        throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public ResolveInfo findPersistentPreferredActivity(Intent intent, int userId)
-        throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public boolean canForwardTo(Intent intent, String resolvedType, int sourceUserId,
-        int targetUserId) throws RemoteException {
-        return false;
-    }
-
-    @Override
-    public ParceledListSlice queryIntentActivities(Intent intent, String resolvedType, int flags,
-        int userId) throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public ParceledListSlice queryIntentActivityOptions(ComponentName caller, Intent[] specifics,
-        String[] specificTypes, Intent intent, String resolvedType, int flags, int userId)
-        throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public ParceledListSlice queryIntentReceivers(Intent intent, String resolvedType, int flags,
-        int userId) throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public ResolveInfo resolveService(Intent intent, String resolvedType, int flags, int userId)
-        throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public ParceledListSlice queryIntentServices(Intent intent, String resolvedType, int flags,
-        int userId) throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public ParceledListSlice queryIntentContentProviders(Intent intent, String resolvedType,
-        int flags, int userId) throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public ParceledListSlice getInstalledPackages(int flags, int userId) throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public ParceledListSlice getPackagesHoldingPermissions(String[] permissions, int flags,
-        int userId) throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public ParceledListSlice getInstalledApplications(int flags, int userId)
-        throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public ParceledListSlice getPersistentApplications(int flags) throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public ProviderInfo resolveContentProvider(String name, int flags, int userId)
-        throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public void querySyncProviders(List<String> outNames, List<ProviderInfo> outInfo)
-        throws RemoteException {
-
-    }
-
-    @Override
-    public ParceledListSlice queryContentProviders(String processName, int uid, int flags,
-        String metaDataKey) throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public InstrumentationInfo getInstrumentationInfo(ComponentName className, int flags)
-        throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public ParceledListSlice queryInstrumentation(String targetPackage, int flags)
-        throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public void finishPackageInstall(int token, boolean didLaunch) throws RemoteException {
-
-    }
-
-    @Override
-    public void setInstallerPackageName(String targetPackage, String installerPackageName)
-        throws RemoteException {
-
-    }
-
-    @Override
-    public void setApplicationCategoryHint(String packageName, int categoryHint,
-        String callerPackageName) throws RemoteException {
-
-    }
-
-    @Override
-    public void deletePackageAsUser(String packageName, int versionCode,
-        IPackageDeleteObserver observer, int userId, int flags) throws RemoteException {
-
-    }
-
-    @Override
-    public void deletePackageVersioned(VersionedPackage versionedPackage,
-        IPackageDeleteObserver2 observer, int userId, int flags) throws RemoteException {
-
-    }
-
-    @Override
-    public String getInstallerPackageName(String packageName) throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public void resetApplicationPreferences(int userId) throws RemoteException {
-
-    }
-
-    @Override
-    public ResolveInfo getLastChosenActivity(Intent intent, String resolvedType, int flags)
-        throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public void setLastChosenActivity(Intent intent, String resolvedType, int flags,
-        IntentFilter filter, int match, ComponentName activity) throws RemoteException {
-
-    }
-
-    @Override
-    public void addPreferredActivity(IntentFilter filter, int match, ComponentName[] set,
-        ComponentName activity, int userId) throws RemoteException {
-
-    }
-
-    @Override
-    public void replacePreferredActivity(IntentFilter filter, int match, ComponentName[] set,
-        ComponentName activity, int userId) throws RemoteException {
-
-    }
-
-    @Override
-    public void clearPackagePreferredActivities(String packageName) throws RemoteException {
-
-    }
-
-    @Override
-    public int getPreferredActivities(List<IntentFilter> outFilters,
-        List<ComponentName> outActivities, String packageName) throws RemoteException {
-        return 0;
-    }
-
-    @Override
-    public void addPersistentPreferredActivity(IntentFilter filter, ComponentName activity,
-        int userId) throws RemoteException {
-
-    }
-
-    @Override
-    public void clearPackagePersistentPreferredActivities(String packageName, int userId)
-        throws RemoteException {
-
-    }
-
-    @Override
-    public void addCrossProfileIntentFilter(IntentFilter intentFilter, String ownerPackage,
-        int sourceUserId, int targetUserId, int flags) throws RemoteException {
-
-    }
-
-    @Override
-    public void clearCrossProfileIntentFilters(int sourceUserId, String ownerPackage)
-        throws RemoteException {
-
-    }
-
-    @Override
-    public String[] setDistractingPackageRestrictionsAsUser(String[] packageNames,
-        int restrictionFlags, int userId) throws RemoteException {
-        return new String[0];
-    }
-
-    @Override
-    public String[] setPackagesSuspendedAsUser(String[] packageNames, boolean suspended,
-        PersistableBundle appExtras, PersistableBundle launcherExtras, SuspendDialogInfo dialogInfo,
-        String callingPackage, int userId) throws RemoteException {
-        return new String[0];
-    }
-
-    @Override
-    public String[] getUnsuspendablePackagesForUser(String[] packageNames, int userId)
-        throws RemoteException {
-        return new String[0];
-    }
-
-    @Override
-    public boolean isPackageSuspendedForUser(String packageName, int userId)
-        throws RemoteException {
-        return false;
-    }
-
-    @Override
-    public PersistableBundle getSuspendedPackageAppExtras(String packageName, int userId)
-        throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public byte[] getPreferredActivityBackup(int userId) throws RemoteException {
-        return new byte[0];
-    }
-
-    @Override
-    public void restorePreferredActivities(byte[] backup, int userId) throws RemoteException {
-
-    }
-
-    @Override
-    public byte[] getDefaultAppsBackup(int userId) throws RemoteException {
-        return new byte[0];
-    }
-
-    @Override
-    public void restoreDefaultApps(byte[] backup, int userId) throws RemoteException {
-
-    }
-
-    @Override
-    public byte[] getIntentFilterVerificationBackup(int userId) throws RemoteException {
-        return new byte[0];
-    }
-
-    @Override
-    public void restoreIntentFilterVerification(byte[] backup, int userId) throws RemoteException {
-
-    }
-
-    @Override
-    public ComponentName getHomeActivities(List<ResolveInfo> outHomeCandidates)
-        throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public void setHomeActivity(ComponentName className, int userId) throws RemoteException {
-
-    }
-
-    @Override
-    public void setComponentEnabledSetting(ComponentName componentName, int newState, int flags,
-        int userId) throws RemoteException {
-
-    }
-
-    @Override
-    public int getComponentEnabledSetting(ComponentName componentName, int userId)
-        throws RemoteException {
-        return 0;
-    }
-
-    @Override
-    public void setApplicationEnabledSetting(String packageName, int newState, int flags,
-        int userId,
-        String callingPackage) throws RemoteException {
-
-    }
-
-    @Override
-    public void logAppProcessStartIfNeeded(String processName, int uid, String seinfo,
-        String apkFile,
-        int pid) throws RemoteException {
-
-    }
-
-    @Override
-    public void flushPackageRestrictionsAsUser(int userId) throws RemoteException {
-
-    }
-
-    @Override
-    public void setPackageStoppedState(String packageName, boolean stopped, int userId)
-        throws RemoteException {
-
-    }
-
-    @Override
-    public void freeStorageAndNotify(String volumeUuid, long freeStorageSize, int storageFlags,
-        IPackageDataObserver observer) throws RemoteException {
-
-    }
-
-    @Override
-    public void freeStorage(String volumeUuid, long freeStorageSize, int storageFlags,
-        IntentSender pi) throws RemoteException {
-
-    }
-
-    @Override
-    public void deleteApplicationCacheFiles(String packageName, IPackageDataObserver observer)
-        throws RemoteException {
-
-    }
-
-    @Override
-    public void deleteApplicationCacheFilesAsUser(String packageName, int userId,
-        IPackageDataObserver observer) throws RemoteException {
-
-    }
-
-    @Override
-    public void clearApplicationUserData(String packageName, IPackageDataObserver observer,
-        int userId) throws RemoteException {
-
-    }
-
-    @Override
-    public void clearApplicationProfileData(String packageName) throws RemoteException {
-
-    }
-
-    @Override
-    public void getPackageSizeInfo(String packageName, int userHandle,
-        IPackageStatsObserver observer)
-        throws RemoteException {
-
-    }
-
-    @Override
-    public String[] getSystemSharedLibraryNames() throws RemoteException {
-        return new String[0];
-    }
-
-    @Override
-    public ParceledListSlice getSystemAvailableFeatures() throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public boolean hasSystemFeature(String name, int version) throws RemoteException {
-        return false;
-    }
-
-    @Override
-    public void enterSafeMode() throws RemoteException {
-
-    }
-
-    @Override
-    public boolean isSafeMode() throws RemoteException {
-        return false;
-    }
-
-    @Override
-    public void systemReady() throws RemoteException {
-
-    }
-
-    @Override
-    public boolean hasSystemUidErrors() throws RemoteException {
-        return false;
-    }
-
-    @Override
-    public void performFstrimIfNeeded() throws RemoteException {
-
-    }
-
-    @Override
-    public void updatePackagesIfNeeded() throws RemoteException {
-
-    }
-
-    @Override
-    public void notifyPackageUse(String packageName, int reason) throws RemoteException {
-
-    }
-
-    @Override
-    public void notifyDexLoad(String loadingPackageName, List<String> classLoadersNames,
-        List<String> classPaths, String loaderIsa) throws RemoteException {
-
-    }
-
-    @Override
-    public void registerDexModule(String packageName, String dexModulePath, boolean isSharedModule,
-        IDexModuleRegisterCallback callback) throws RemoteException {
-
-    }
-
-    @Override
-    public boolean performDexOptMode(String packageName, boolean checkProfiles,
-        String targetCompilerFilter, boolean force, boolean bootComplete, String splitName)
-        throws RemoteException {
-        return false;
-    }
-
-    @Override
-    public boolean performDexOptSecondary(String packageName, String targetCompilerFilter,
-        boolean force) throws RemoteException {
-        return false;
-    }
-
-    @Override
-    public boolean compileLayouts(String packageName) throws RemoteException {
-        return false;
-    }
-
-    @Override
-    public void dumpProfiles(String packageName) throws RemoteException {
-
-    }
-
-    @Override
-    public void forceDexOpt(String packageName) throws RemoteException {
-
-    }
-
-    @Override
-    public boolean runBackgroundDexoptJob(List<String> packageNames) throws RemoteException {
-        return false;
-    }
-
-    @Override
-    public void reconcileSecondaryDexFiles(String packageName) throws RemoteException {
-
-    }
-
-    @Override
-    public int getMoveStatus(int moveId) throws RemoteException {
-        return 0;
-    }
-
-    @Override
-    public void registerMoveCallback(IPackageMoveObserver callback) throws RemoteException {
-
-    }
-
-    @Override
-    public void unregisterMoveCallback(IPackageMoveObserver callback) throws RemoteException {
-
-    }
-
-    @Override
-    public int movePackage(String packageName, String volumeUuid) throws RemoteException {
-        return 0;
-    }
-
-    @Override
-    public int movePrimaryStorage(String volumeUuid) throws RemoteException {
-        return 0;
-    }
-
-    @Override
-    public boolean addPermissionAsync(PermissionInfo info) throws RemoteException {
-        return false;
-    }
-
-    @Override
-    public boolean setInstallLocation(int loc) throws RemoteException {
-        return false;
-    }
-
-    @Override
-    public int getInstallLocation() throws RemoteException {
-        return 0;
-    }
-
-    @Override
-    public int installExistingPackageAsUser(String packageName, int userId, int installFlags,
-        int installReason) throws RemoteException {
-        return 0;
-    }
-
-    @Override
-    public void verifyPendingInstall(int id, int verificationCode) throws RemoteException {
-
-    }
-
-    @Override
-    public void extendVerificationTimeout(int id, int verificationCodeAtTimeout,
-        long millisecondsToDelay) throws RemoteException {
-
-    }
-
-    @Override
-    public void verifyIntentFilter(int id, int verificationCode, List<String> failedDomains)
-        throws RemoteException {
-
-    }
-
-    @Override
-    public int getIntentVerificationStatus(String packageName, int userId) throws RemoteException {
-        return 0;
-    }
-
-    @Override
-    public boolean updateIntentVerificationStatus(String packageName, int status, int userId)
-        throws RemoteException {
-        return false;
-    }
-
-    @Override
-    public ParceledListSlice getIntentFilterVerifications(String packageName)
-        throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public ParceledListSlice getAllIntentFilters(String packageName) throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public boolean setDefaultBrowserPackageName(String packageName, int userId)
-        throws RemoteException {
-        return false;
-    }
-
-    @Override
-    public String getDefaultBrowserPackageName(int userId) throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public VerifierDeviceIdentity getVerifierDeviceIdentity() throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public boolean isFirstBoot() throws RemoteException {
-        return false;
-    }
-
-    @Override
-    public boolean isOnlyCoreApps() throws RemoteException {
-        return false;
-    }
-
-    @Override
-    public boolean isDeviceUpgrading() throws RemoteException {
-        return false;
-    }
-
-    @Override
-    public void setPermissionEnforced(String permission, boolean enforced) throws RemoteException {
-
-    }
-
-    @Override
-    public boolean isPermissionEnforced(String permission) throws RemoteException {
-        return false;
-    }
-
-    @Override
-    public boolean isStorageLow() throws RemoteException {
-        return false;
-    }
-
-    @Override
-    public boolean setApplicationHiddenSettingAsUser(String packageName, boolean hidden, int userId)
-        throws RemoteException {
-        return false;
-    }
-
-    @Override
-    public boolean getApplicationHiddenSettingAsUser(String packageName, int userId)
-        throws RemoteException {
-        return false;
-    }
-
-    @Override
-    public void setSystemAppHiddenUntilInstalled(String packageName, boolean hidden)
-        throws RemoteException {
-
-    }
-
-    @Override
-    public boolean setSystemAppInstallState(String packageName, boolean installed, int userId)
-        throws RemoteException {
-        return false;
-    }
-
-    @Override
-    public IPackageInstaller getPackageInstaller() throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public boolean setBlockUninstallForUser(String packageName, boolean blockUninstall, int userId)
-        throws RemoteException {
-        return false;
-    }
-
-    @Override
-    public boolean getBlockUninstallForUser(String packageName, int userId) throws RemoteException {
-        return false;
-    }
-
-    @Override
-    public KeySet getKeySetByAlias(String packageName, String alias) throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public KeySet getSigningKeySet(String packageName) throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public boolean isPackageSignedByKeySet(String packageName, KeySet ks) throws RemoteException {
-        return false;
-    }
-
-    @Override
-    public boolean isPackageSignedByKeySetExactly(String packageName, KeySet ks)
-        throws RemoteException {
-        return false;
-    }
-
-    @Override
-    public void addOnPermissionsChangeListener(IOnPermissionsChangeListener listener)
-        throws RemoteException {
-
-    }
-
-    @Override
-    public void removeOnPermissionsChangeListener(IOnPermissionsChangeListener listener)
-        throws RemoteException {
-
-    }
-
-    @Override
-    public void grantDefaultPermissionsToEnabledCarrierApps(String[] packageNames, int userId)
-        throws RemoteException {
-
-    }
-
-    @Override
-    public void grantDefaultPermissionsToEnabledImsServices(String[] packageNames, int userId)
-        throws RemoteException {
-
-    }
-
-    @Override
-    public void grantDefaultPermissionsToEnabledTelephonyDataServices(String[] packageNames,
-        int userId) throws RemoteException {
-
-    }
-
-    @Override
-    public void revokeDefaultPermissionsFromDisabledTelephonyDataServices(String[] packageNames,
-        int userId) throws RemoteException {
-
-    }
-
-    @Override
-    public void grantDefaultPermissionsToActiveLuiApp(String packageName, int userId)
-        throws RemoteException {
-
-    }
-
-    @Override
-    public void revokeDefaultPermissionsFromLuiApps(String[] packageNames, int userId)
-        throws RemoteException {
-
-    }
-
-    @Override
-    public boolean isPermissionRevokedByPolicy(String permission, String packageName, int userId)
-        throws RemoteException {
-        return false;
-    }
-
-    @Override
-    public String getPermissionControllerPackageName() throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public ParceledListSlice getInstantApps(int userId) throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public byte[] getInstantAppCookie(String packageName, int userId) throws RemoteException {
-        return new byte[0];
-    }
-
-    @Override
-    public boolean setInstantAppCookie(String packageName, byte[] cookie, int userId)
-        throws RemoteException {
-        return false;
-    }
-
-    @Override
-    public Bitmap getInstantAppIcon(String packageName, int userId) throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public boolean isInstantApp(String packageName, int userId) throws RemoteException {
-        return false;
-    }
-
-    @Override
-    public boolean setRequiredForSystemUser(String packageName, boolean systemUserApp)
-        throws RemoteException {
-        return false;
-    }
-
-    @Override
-    public void setUpdateAvailable(String packageName, boolean updateAvaialble)
-        throws RemoteException {
-
-    }
-
-    @Override
-    public String getServicesSystemSharedLibraryPackageName() throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public String getSharedSystemSharedLibraryPackageName() throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public ChangedPackages getChangedPackages(int sequenceNumber, int userId)
-        throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public boolean isPackageDeviceAdminOnAnyUser(String packageName) throws RemoteException {
-        return false;
-    }
-
-    @Override
-    public int getInstallReason(String packageName, int userId) throws RemoteException {
-        return 0;
-    }
-
-    @Override
-    public ParceledListSlice getSharedLibraries(String packageName, int flags, int userId)
-        throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public ParceledListSlice getDeclaredSharedLibraries(String packageName, int flags, int userId)
-            throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public boolean canRequestPackageInstalls(String packageName, int userId)
-        throws RemoteException {
-        return false;
-    }
-
-    @Override
-    public void deletePreloadsFileCache() throws RemoteException {
-
-    }
-
-    @Override
-    public ComponentName getInstantAppResolverComponent() throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public ComponentName getInstantAppResolverSettingsComponent() throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public ComponentName getInstantAppInstallerComponent() throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public String getInstantAppAndroidId(String packageName, int userId) throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public IArtManager getArtManager() throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public void setHarmfulAppWarning(String packageName, CharSequence warning, int userId)
-        throws RemoteException {
-
-    }
-
-    @Override
-    public CharSequence getHarmfulAppWarning(String packageName, int userId)
-        throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public boolean hasSigningCertificate(String packageName, byte[] signingCertificate, int flags)
-        throws RemoteException {
-        return false;
-    }
-
-    @Override
-    public boolean hasUidSigningCertificate(int uid, byte[] signingCertificate, int flags)
-        throws RemoteException {
-        return false;
-    }
-
-    @Override
-    public String getSystemTextClassifierPackageName() throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public String getWellbeingPackageName() throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public String getSystemCaptionsServicePackageName() throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public String getAttentionServicePackageName() throws RemoteException {
-        return null;
-    }
-
-    public String getIncidentReportApproverPackageName() throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public String getAppPredictionServicePackageName() {
-        return null;
-    }
-
-    @Override
-    public boolean isPackageStateProtected(String packageName, int userId) throws RemoteException {
-        return false;
-    }
-
-    @Override
-    public void sendDeviceCustomizationReadyBroadcast() throws RemoteException {
-
-    }
-
-    @Override
-    public List<ModuleInfo> getInstalledModules(int flags) throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public ModuleInfo getModuleInfo(String packageName, int flags) throws RemoteException {
-        return null;
-    }
-
-    @Override
-    public int getRuntimePermissionsVersion(int userId) throws RemoteException {
-        return 0;
-    }
-
-    @Override
-    public void setRuntimePermissionsVersion(int version, int userId) throws RemoteException {
-
-    }
-
-    @Override
-    public IBinder asBinder() {
-        return null;
-    }
-}
diff --git a/services/tests/servicestests/src/com/android/server/backup/utils/AppBackupUtilsTest.java b/services/tests/servicestests/src/com/android/server/backup/utils/AppBackupUtilsTest.java
index a92b576..a901175 100644
--- a/services/tests/servicestests/src/com/android/server/backup/utils/AppBackupUtilsTest.java
+++ b/services/tests/servicestests/src/com/android/server/backup/utils/AppBackupUtilsTest.java
@@ -20,6 +20,7 @@
 
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
 
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
@@ -36,7 +37,6 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.server.backup.UserBackupManagerService;
-import com.android.server.backup.testutils.IPackageManagerStub;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -54,14 +54,12 @@
     private static final Signature SIGNATURE_3 = generateSignature((byte) 3);
     private static final Signature SIGNATURE_4 = generateSignature((byte) 4);
 
-    private IPackageManagerStub mPackageManagerStub;
     private PackageManagerInternal mMockPackageManagerInternal;
 
     private int mUserId;
 
     @Before
     public void setUp() throws Exception {
-        mPackageManagerStub = new IPackageManagerStub();
         mMockPackageManagerInternal = mock(PackageManagerInternal.class);
 
         mUserId = UserHandle.USER_SYSTEM;
@@ -76,7 +74,7 @@
         applicationInfo.packageName = TEST_PACKAGE_NAME;
 
         boolean isEligible = AppBackupUtils.appIsEligibleForBackup(applicationInfo,
-                mPackageManagerStub, mUserId);
+                mMockPackageManagerInternal, mUserId);
 
         assertThat(isEligible).isFalse();
     }
@@ -91,7 +89,7 @@
         applicationInfo.packageName = TEST_PACKAGE_NAME;
 
         boolean isEligible = AppBackupUtils.appIsEligibleForBackup(applicationInfo,
-                mPackageManagerStub, mUserId);
+                mMockPackageManagerInternal, mUserId);
 
         assertThat(isEligible).isFalse();
     }
@@ -105,7 +103,7 @@
         applicationInfo.packageName = UserBackupManagerService.SHARED_BACKUP_AGENT_PACKAGE;
 
         boolean isEligible = AppBackupUtils.appIsEligibleForBackup(applicationInfo,
-                mPackageManagerStub, mUserId);
+                mMockPackageManagerInternal, mUserId);
 
         assertThat(isEligible).isFalse();
     }
@@ -118,12 +116,11 @@
         applicationInfo.uid = Process.SYSTEM_UID;
         applicationInfo.backupAgentName = CUSTOM_BACKUP_AGENT_NAME;
         applicationInfo.packageName = TEST_PACKAGE_NAME;
-
-        IPackageManagerStub.sApplicationEnabledSetting =
-                PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
+        when(mMockPackageManagerInternal.getApplicationEnabledState(TEST_PACKAGE_NAME, mUserId))
+                .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
 
         boolean isEligible = AppBackupUtils.appIsEligibleForBackup(applicationInfo,
-                mPackageManagerStub, mUserId);
+                mMockPackageManagerInternal, mUserId);
 
         assertThat(isEligible).isTrue();
     }
@@ -136,12 +133,11 @@
         applicationInfo.uid = Process.FIRST_APPLICATION_UID;
         applicationInfo.backupAgentName = null;
         applicationInfo.packageName = TEST_PACKAGE_NAME;
-
-        IPackageManagerStub.sApplicationEnabledSetting =
-                PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
+        when(mMockPackageManagerInternal.getApplicationEnabledState(TEST_PACKAGE_NAME, mUserId))
+                .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
 
         boolean isEligible = AppBackupUtils.appIsEligibleForBackup(applicationInfo,
-                mPackageManagerStub, mUserId);
+                mMockPackageManagerInternal, mUserId);
 
         assertThat(isEligible).isTrue();
     }
@@ -154,12 +150,11 @@
         applicationInfo.uid = Process.FIRST_APPLICATION_UID;
         applicationInfo.backupAgentName = CUSTOM_BACKUP_AGENT_NAME;
         applicationInfo.packageName = TEST_PACKAGE_NAME;
-
-        IPackageManagerStub.sApplicationEnabledSetting =
-                PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
+        when(mMockPackageManagerInternal.getApplicationEnabledState(TEST_PACKAGE_NAME, mUserId))
+                .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
 
         boolean isEligible = AppBackupUtils.appIsEligibleForBackup(applicationInfo,
-                mPackageManagerStub, mUserId);
+                mMockPackageManagerInternal, mUserId);
 
         assertThat(isEligible).isTrue();
     }
@@ -172,12 +167,11 @@
         applicationInfo.uid = Process.SYSTEM_UID;
         applicationInfo.backupAgentName = CUSTOM_BACKUP_AGENT_NAME;
         applicationInfo.packageName = TEST_PACKAGE_NAME;
-
-        IPackageManagerStub.sApplicationEnabledSetting =
-                PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
+        when(mMockPackageManagerInternal.getApplicationEnabledState(TEST_PACKAGE_NAME, mUserId))
+                .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DISABLED);
 
         boolean isEligible = AppBackupUtils.appIsEligibleForBackup(applicationInfo,
-                mPackageManagerStub, mUserId);
+                mMockPackageManagerInternal, mUserId);
 
         assertThat(isEligible).isFalse();
     }
@@ -190,12 +184,11 @@
         applicationInfo.uid = Process.FIRST_APPLICATION_UID;
         applicationInfo.backupAgentName = null;
         applicationInfo.packageName = TEST_PACKAGE_NAME;
-
-        IPackageManagerStub.sApplicationEnabledSetting =
-                PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
+        when(mMockPackageManagerInternal.getApplicationEnabledState(TEST_PACKAGE_NAME, mUserId))
+                .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DISABLED);
 
         boolean isEligible = AppBackupUtils.appIsEligibleForBackup(applicationInfo,
-                mPackageManagerStub, mUserId);
+                mMockPackageManagerInternal, mUserId);
 
         assertThat(isEligible).isFalse();
     }
@@ -208,12 +201,11 @@
         applicationInfo.uid = Process.FIRST_APPLICATION_UID;
         applicationInfo.backupAgentName = CUSTOM_BACKUP_AGENT_NAME;
         applicationInfo.packageName = TEST_PACKAGE_NAME;
-
-        IPackageManagerStub.sApplicationEnabledSetting =
-                PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
+        when(mMockPackageManagerInternal.getApplicationEnabledState(TEST_PACKAGE_NAME, mUserId))
+                .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DISABLED);
 
         boolean isEligible = AppBackupUtils.appIsEligibleForBackup(applicationInfo,
-                mPackageManagerStub, mUserId);
+                mMockPackageManagerInternal, mUserId);
 
         assertThat(isEligible).isFalse();
     }
@@ -226,12 +218,11 @@
         applicationInfo.backupAgentName = CUSTOM_BACKUP_AGENT_NAME;
         applicationInfo.packageName = TEST_PACKAGE_NAME;
         applicationInfo.enabled = true;
+        when(mMockPackageManagerInternal.getApplicationEnabledState(TEST_PACKAGE_NAME, mUserId))
+                .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT);
 
-        IPackageManagerStub.sApplicationEnabledSetting =
-                PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
-
-        boolean isDisabled = AppBackupUtils.appIsDisabled(applicationInfo, mPackageManagerStub,
-            mUserId);
+        boolean isDisabled =
+                AppBackupUtils.appIsDisabled(applicationInfo, mMockPackageManagerInternal, mUserId);
 
         assertThat(isDisabled).isFalse();
     }
@@ -244,12 +235,12 @@
         applicationInfo.backupAgentName = CUSTOM_BACKUP_AGENT_NAME;
         applicationInfo.packageName = TEST_PACKAGE_NAME;
         applicationInfo.enabled = false;
+        when(mMockPackageManagerInternal.getApplicationEnabledState(TEST_PACKAGE_NAME, mUserId))
+                .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT);
 
-        IPackageManagerStub.sApplicationEnabledSetting =
-                PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
 
-        boolean isDisabled = AppBackupUtils.appIsDisabled(applicationInfo, mPackageManagerStub,
-            mUserId);
+        boolean isDisabled =
+                AppBackupUtils.appIsDisabled(applicationInfo, mMockPackageManagerInternal, mUserId);
 
         assertThat(isDisabled).isTrue();
     }
@@ -261,12 +252,12 @@
         applicationInfo.uid = Process.FIRST_APPLICATION_UID;
         applicationInfo.backupAgentName = CUSTOM_BACKUP_AGENT_NAME;
         applicationInfo.packageName = TEST_PACKAGE_NAME;
+        when(mMockPackageManagerInternal.getApplicationEnabledState(TEST_PACKAGE_NAME, mUserId))
+                .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
 
-        IPackageManagerStub.sApplicationEnabledSetting =
-                PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
 
-        boolean isDisabled = AppBackupUtils.appIsDisabled(applicationInfo, mPackageManagerStub,
-            mUserId);
+        boolean isDisabled =
+                AppBackupUtils.appIsDisabled(applicationInfo, mMockPackageManagerInternal, mUserId);
 
         assertThat(isDisabled).isFalse();
     }
@@ -278,12 +269,12 @@
         applicationInfo.uid = Process.FIRST_APPLICATION_UID;
         applicationInfo.backupAgentName = CUSTOM_BACKUP_AGENT_NAME;
         applicationInfo.packageName = TEST_PACKAGE_NAME;
+        when(mMockPackageManagerInternal.getApplicationEnabledState(TEST_PACKAGE_NAME, mUserId))
+                .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DISABLED);
 
-        IPackageManagerStub.sApplicationEnabledSetting =
-                PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
 
-        boolean isDisabled = AppBackupUtils.appIsDisabled(applicationInfo, mPackageManagerStub,
-            mUserId);
+        boolean isDisabled =
+                AppBackupUtils.appIsDisabled(applicationInfo, mMockPackageManagerInternal, mUserId);
 
         assertThat(isDisabled).isTrue();
     }
@@ -295,12 +286,11 @@
         applicationInfo.uid = Process.FIRST_APPLICATION_UID;
         applicationInfo.backupAgentName = CUSTOM_BACKUP_AGENT_NAME;
         applicationInfo.packageName = TEST_PACKAGE_NAME;
+        when(mMockPackageManagerInternal.getApplicationEnabledState(TEST_PACKAGE_NAME, mUserId))
+                .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER);
 
-        IPackageManagerStub.sApplicationEnabledSetting =
-                PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;
-
-        boolean isDisabled = AppBackupUtils.appIsDisabled(applicationInfo, mPackageManagerStub,
-            mUserId);
+        boolean isDisabled =
+                AppBackupUtils.appIsDisabled(applicationInfo, mMockPackageManagerInternal, mUserId);
 
         assertThat(isDisabled).isTrue();
     }
@@ -312,12 +302,11 @@
         applicationInfo.uid = Process.FIRST_APPLICATION_UID;
         applicationInfo.backupAgentName = CUSTOM_BACKUP_AGENT_NAME;
         applicationInfo.packageName = TEST_PACKAGE_NAME;
+        when(mMockPackageManagerInternal.getApplicationEnabledState(TEST_PACKAGE_NAME, mUserId))
+                .thenReturn(PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED);
 
-        IPackageManagerStub.sApplicationEnabledSetting =
-                PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
-
-        boolean isDisabled = AppBackupUtils.appIsDisabled(applicationInfo, mPackageManagerStub,
-            mUserId);
+        boolean isDisabled =
+                AppBackupUtils.appIsDisabled(applicationInfo, mMockPackageManagerInternal, mUserId);
 
         assertThat(isDisabled).isTrue();
     }
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 355ff63..2d101dd 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -349,6 +349,7 @@
         when(mUgmInternal.newUriPermissionOwner(anyString())).thenReturn(mPermOwner);
         when(mPackageManager.getPackagesForUid(mUid)).thenReturn(new String[]{PKG});
         when(mPackageManagerClient.getPackagesForUid(anyInt())).thenReturn(new String[]{PKG});
+        mContext.addMockSystemService(AppOpsManager.class, mock(AppOpsManager.class));
 
         // write to a test file; the system file isn't readable from tests
         mFile = new File(mContext.getCacheDir(), "test.xml");
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
index 91d3e5e..7e3d4b4 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
@@ -206,6 +206,7 @@
 
         LocalServices.removeServiceForTest(WindowManagerInternal.class);
         LocalServices.addService(WindowManagerInternal.class, mock(WindowManagerInternal.class));
+        mContext.addMockSystemService(AppOpsManager.class, mock(AppOpsManager.class));
 
         mUsers = new ArrayList<>();
         mUsers.add(new UserInfo(0, "system", 0));
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index 08d8333..8936450 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -110,6 +110,7 @@
     private ZenModeHelper mZenModeHelperSpy;
     private Context mContext;
     private ContentResolver mContentResolver;
+    @Mock AppOpsManager mAppOps;
 
     @Before
     public void setUp() {
@@ -127,6 +128,7 @@
                     e.toString());
         }
 
+        when(mContext.getSystemService(AppOpsManager.class)).thenReturn(mAppOps);
         when(mContext.getSystemService(NotificationManager.class)).thenReturn(mNotificationManager);
         mConditionProviders = new ConditionProviders(mContext, new UserProfiles(),
                 AppGlobals.getPackageManager());
@@ -219,10 +221,10 @@
                 Policy.PRIORITY_CATEGORY_MEDIA, 0, 0, 0, 0);
         mZenModeHelperSpy.applyRestrictions();
 
-        doNothing().when(mZenModeHelperSpy).applyRestrictions(anyBoolean(), anyInt());
-        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false,
+        doNothing().when(mZenModeHelperSpy).applyRestrictions(eq(false), anyBoolean(), anyInt());
+        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, false,
                 AudioAttributes.USAGE_ALARM);
-        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false,
+        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, false,
                 AudioAttributes.USAGE_MEDIA);
     }
 
@@ -233,9 +235,9 @@
                 Policy.PRIORITY_CATEGORY_MEDIA, 0, 0, 0, 0);
 
         mZenModeHelperSpy.applyRestrictions();
-        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false,
+        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, false,
                 AudioAttributes.USAGE_ALARM);
-        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false,
+        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, false,
                 AudioAttributes.USAGE_MEDIA);
     }
 
@@ -244,13 +246,13 @@
         mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
         mZenModeHelperSpy.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0);
         mZenModeHelperSpy.applyRestrictions();
-        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true,
+        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, true,
                 AudioAttributes.USAGE_ALARM);
 
         // Media is a catch-all that includes games
-        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true,
+        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, true,
                 AudioAttributes.USAGE_MEDIA);
-        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true,
+        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, true,
                 AudioAttributes.USAGE_GAME);
     }
 
@@ -262,17 +264,17 @@
         mZenModeHelperSpy.applyRestrictions();
 
         // Total silence will silence alarms, media and system noises (but not vibrations)
-        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true,
+        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, true,
                 AudioAttributes.USAGE_ALARM);
-        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true,
+        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, true,
                 AudioAttributes.USAGE_MEDIA);
-        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true,
+        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, true,
                 AudioAttributes.USAGE_GAME);
-        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true,
+        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, true,
                 AudioAttributes.USAGE_ASSISTANCE_SONIFICATION, AppOpsManager.OP_PLAY_AUDIO);
-        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false,
+        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, false,
                 AudioAttributes.USAGE_ASSISTANCE_SONIFICATION, AppOpsManager.OP_VIBRATE);
-        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true,
+        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, true,
                 AudioAttributes.USAGE_UNKNOWN);
     }
 
@@ -283,19 +285,19 @@
         mZenModeHelperSpy.applyRestrictions();
 
         // Alarms only mode will not silence alarms
-        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false,
+        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, false,
                 AudioAttributes.USAGE_ALARM);
 
         // Alarms only mode will not silence media
-        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false,
+        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, false,
                 AudioAttributes.USAGE_MEDIA);
-        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false,
+        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, false,
                 AudioAttributes.USAGE_GAME);
-        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false,
+        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, false,
                 AudioAttributes.USAGE_UNKNOWN);
 
         // Alarms only will silence system noises (but not vibrations)
-        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true,
+        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, true,
                 AudioAttributes.USAGE_ASSISTANCE_SONIFICATION, AppOpsManager.OP_PLAY_AUDIO);
     }
 
@@ -306,9 +308,9 @@
         mZenModeHelperSpy.applyRestrictions();
 
         // Alarms only mode will silence calls despite priority-mode config
-        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true,
+        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, true,
                 AudioAttributes.USAGE_NOTIFICATION_RINGTONE);
-        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true,
+        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, true,
                 AudioAttributes.USAGE_NOTIFICATION_COMMUNICATION_REQUEST);
     }
 
@@ -319,7 +321,7 @@
         mZenModeHelperSpy.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0);
         mZenModeHelperSpy.applyRestrictions();
 
-        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false,
+        verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, false,
                 AudioAttributes.USAGE_ALARM);
     }
 
@@ -334,19 +336,64 @@
         for (int usage : AudioAttributes.SDK_USAGES) {
             if (usage == AudioAttributes.USAGE_ASSISTANCE_SONIFICATION) {
                 // only mute audio, not vibrations
-                verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, usage,
+                verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, true, usage,
                         AppOpsManager.OP_PLAY_AUDIO);
-                verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(false, usage,
+                verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, false, usage,
                         AppOpsManager.OP_VIBRATE);
             } else {
                 boolean shouldMute = AudioAttributes.SUPPRESSIBLE_USAGES.get(usage)
                         != AudioAttributes.SUPPRESSIBLE_NEVER;
-                verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(shouldMute, usage);
+                verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, shouldMute, usage);
             }
         }
     }
 
     @Test
+    public void testApplyRestrictions_whitelist_priorityOnlyMode() {
+        mZenModeHelperSpy.setPriorityOnlyDndExemptPackages(new String[] {PKG_O});
+        mZenModeHelperSpy.mZenMode = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+        mZenModeHelperSpy.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0);
+        mZenModeHelperSpy.applyRestrictions();
+
+        for (int usage : AudioAttributes.SDK_USAGES) {
+            verify(mAppOps).setRestriction(
+                    eq(AppOpsManager.OP_PLAY_AUDIO), eq(usage), anyInt(), eq(new String[]{PKG_O}));
+            verify(mAppOps).setRestriction(
+                    eq(AppOpsManager.OP_VIBRATE), eq(usage), anyInt(), eq(new String[]{PKG_O}));
+        }
+    }
+
+    @Test
+    public void testApplyRestrictions_whitelist_alarmsOnlyMode() {
+        mZenModeHelperSpy.setPriorityOnlyDndExemptPackages(new String[] {PKG_O});
+        mZenModeHelperSpy.mZenMode = Global.ZEN_MODE_ALARMS;
+        mZenModeHelperSpy.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0);
+        mZenModeHelperSpy.applyRestrictions();
+
+        for (int usage : AudioAttributes.SDK_USAGES) {
+            verify(mAppOps).setRestriction(
+                    eq(AppOpsManager.OP_PLAY_AUDIO), eq(usage), anyInt(), eq(null));
+            verify(mAppOps).setRestriction(
+                    eq(AppOpsManager.OP_VIBRATE), eq(usage), anyInt(), eq(null));
+        }
+    }
+
+    @Test
+    public void testApplyRestrictions_whitelist_totalSilenceMode() {
+        mZenModeHelperSpy.setPriorityOnlyDndExemptPackages(new String[] {PKG_O});
+        mZenModeHelperSpy.mZenMode = Global.ZEN_MODE_NO_INTERRUPTIONS;
+        mZenModeHelperSpy.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0);
+        mZenModeHelperSpy.applyRestrictions();
+
+        for (int usage : AudioAttributes.SDK_USAGES) {
+            verify(mAppOps).setRestriction(
+                    eq(AppOpsManager.OP_PLAY_AUDIO), eq(usage), anyInt(), eq(null));
+            verify(mAppOps).setRestriction(
+                    eq(AppOpsManager.OP_VIBRATE), eq(usage), anyInt(), eq(null));
+        }
+    }
+
+    @Test
     public void testZenUpgradeNotification() {
         // shows zen upgrade notification if stored settings says to shows,
         // zen has not been updated, boot is completed
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
index 263f650..f51ce13 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
@@ -17,6 +17,7 @@
 package com.android.server.wm;
 
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
 import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
 
@@ -44,14 +45,18 @@
     private static final int FAKE_CALLING_UID = 667;
 
     @Test
-    public void testIsAnyNonToastWindowVisibleForUid_oneToastOneNonToastBothVisible() {
+    public void testIsAnyNonToastWindowVisibleForUid_oneToastOneAppStartOneNonToastBothVisible() {
         final WindowState toastyToast = createWindow(null, TYPE_TOAST, "toast", FAKE_CALLING_UID);
         final WindowState app = createWindow(null, TYPE_APPLICATION, "app", FAKE_CALLING_UID);
+        final WindowState appStart = createWindow(null, TYPE_APPLICATION_STARTING, "appStarting",
+                FAKE_CALLING_UID);
         toastyToast.mHasSurface = true;
         app.mHasSurface = true;
+        appStart.mHasSurface = true;
 
         assertTrue(toastyToast.isVisibleNow());
         assertTrue(app.isVisibleNow());
+        assertTrue(appStart.isVisibleNow());
         assertTrue(mWm.mRoot.isAnyNonToastWindowVisibleForUid(FAKE_CALLING_UID));
     }
 
@@ -65,6 +70,16 @@
     }
 
     @Test
+    public void testIsAnyNonToastWindowVisibleForUid_onlyAppStartingVisible() {
+        final WindowState appStart = createWindow(null, TYPE_APPLICATION_STARTING, "appStarting",
+                FAKE_CALLING_UID);
+        appStart.mHasSurface = true;
+
+        assertTrue(appStart.isVisibleNow());
+        assertFalse(mWm.mRoot.isAnyNonToastWindowVisibleForUid(FAKE_CALLING_UID));
+    }
+
+    @Test
     public void testIsAnyNonToastWindowVisibleForUid_aFewNonToastButNoneVisible() {
         final WindowState topBar = createWindow(null, TYPE_STATUS_BAR, "topBar", FAKE_CALLING_UID);
         final WindowState app = createWindow(null, TYPE_APPLICATION, "app", FAKE_CALLING_UID);
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index 79e6851..5b7d816 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -1095,6 +1095,14 @@
                     Slog.d(TAG, "Clear notification");
                     mUsbNotificationId = 0;
                 }
+                // Not relevant for automotive.
+                if (mContext.getPackageManager().hasSystemFeature(
+                        PackageManager.FEATURE_AUTOMOTIVE)
+                        && id == SystemMessage.NOTE_USB_CHARGING) {
+                    mUsbNotificationId = 0;
+                    return;
+                }
+
                 if (id != 0) {
                     CharSequence title = r.getText(titleRes);
                     PendingIntent pi;
diff --git a/telecomm/java/android/telecom/Conference.java b/telecomm/java/android/telecom/Conference.java
index 6382acf..6000b56 100644
--- a/telecomm/java/android/telecom/Conference.java
+++ b/telecomm/java/android/telecom/Conference.java
@@ -68,6 +68,7 @@
         public void onExtrasRemoved(Conference c, List<String> keys) {}
         public void onConferenceStateChanged(Conference c, boolean isConference) {}
         public void onAddressChanged(Conference c, Uri newAddress, int presentation) {}
+        public void onConnectionEvent(Conference c, String event, Bundle extras) {}
         public void onCallerDisplayNameChanged(
                 Conference c, String callerDisplayName, int presentation) {}
     }
@@ -1024,4 +1025,14 @@
         }
         onExtrasChanged(b);
     }
+
+    /**
+     * See {@link Connection#sendConnectionEvent(String, Bundle)}
+     * @hide
+     */
+    public void sendConnectionEvent(String event, Bundle extras) {
+        for (Listener l : mListeners) {
+            l.onConnectionEvent(this, event, extras);
+        }
+    }
 }
diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java
index 9bafbe0..49b34b3 100644
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -1279,6 +1279,14 @@
                 mAdapter.setCallerDisplayName(id, callerDisplayName, presentation);
             }
         }
+
+        @Override
+        public void onConnectionEvent(Conference c, String event, Bundle extras) {
+            String id = mIdByConference.get(c);
+            if (id != null) {
+                mAdapter.onConnectionEvent(id, event, extras);
+            }
+        }
     };
 
     private final Connection.Listener mConnectionListener = new Connection.Listener() {
diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java
index 037e475..9bba2e8 100644
--- a/telephony/java/android/provider/Telephony.java
+++ b/telephony/java/android/provider/Telephony.java
@@ -3039,6 +3039,7 @@
              * The {@code content://} style URL for this table. Can be appended with a part ID to
              * address individual parts.
              */
+            @NonNull
             public static final Uri CONTENT_URI = Uri.withAppendedPath(Mms.CONTENT_URI, "part");
 
             /**
diff --git a/telephony/java/android/telephony/CellIdentity.java b/telephony/java/android/telephony/CellIdentity.java
index 3087516..258a873 100644
--- a/telephony/java/android/telephony/CellIdentity.java
+++ b/telephony/java/android/telephony/CellIdentity.java
@@ -243,4 +243,23 @@
     protected void log(String s) {
         Rlog.w(mTag, s);
     }
+
+    /** @hide */
+    protected static final int inRangeOrUnavailable(int value, int rangeMin, int rangeMax) {
+        if (value < rangeMin || value > rangeMax) return CellInfo.UNAVAILABLE;
+        return value;
+    }
+
+    /** @hide */
+    protected static final long inRangeOrUnavailable(long value, long rangeMin, long rangeMax) {
+        if (value < rangeMin || value > rangeMax) return CellInfo.UNAVAILABLE_LONG;
+        return value;
+    }
+
+    /** @hide */
+    protected static final int inRangeOrUnavailable(
+            int value, int rangeMin, int rangeMax, int special) {
+        if ((value < rangeMin || value > rangeMax) && value != special) return CellInfo.UNAVAILABLE;
+        return value;
+    }
 }
diff --git a/telephony/java/android/telephony/CellIdentityCdma.java b/telephony/java/android/telephony/CellIdentityCdma.java
index 4c00611..880d3db 100644
--- a/telephony/java/android/telephony/CellIdentityCdma.java
+++ b/telephony/java/android/telephony/CellIdentityCdma.java
@@ -28,12 +28,25 @@
     private static final String TAG = CellIdentityCdma.class.getSimpleName();
     private static final boolean DBG = false;
 
+    private static final int NETWORK_ID_MAX = 65535;
+    private static final int SYSTEM_ID_MAX = 32767;
+    private static final int BASESTATION_ID_MAX = 65535;
+
+    private static final int LONGITUDE_MIN = -2592000;
+    private static final int LONGITUDE_MAX = 2592000;
+
+    private static final int LATITUDE_MIN = -1296000;
+    private static final int LATITUDE_MAX = 1296000;
+
     // Network Id 0..65535
     private final int mNetworkId;
+
     // CDMA System Id 0..32767
     private final int mSystemId;
+
     // Base Station Id 0..65535
     private final int mBasestationId;
+
     /**
      * Longitude is a decimal number as specified in 3GPP2 C.S0005-A v6.0.
      * It is represented in units of 0.25 seconds and ranges from -2592000
@@ -41,6 +54,7 @@
      * to +180 degrees).
      */
     private final int mLongitude;
+
     /**
      * Latitude is a decimal number as specified in 3GPP2 C.S0005-A v6.0.
      * It is represented in units of 0.25 seconds and ranges from -1296000
@@ -78,9 +92,12 @@
     public CellIdentityCdma(
             int nid, int sid, int bid, int lon, int lat, String alphal, String alphas) {
         super(TAG, CellInfo.TYPE_CDMA, null, null, alphal, alphas);
-        mNetworkId = nid;
-        mSystemId = sid;
-        mBasestationId = bid;
+        mNetworkId = inRangeOrUnavailable(nid, 0, NETWORK_ID_MAX);
+        mSystemId = inRangeOrUnavailable(sid, 0, SYSTEM_ID_MAX);
+        mBasestationId = inRangeOrUnavailable(bid, 0, BASESTATION_ID_MAX);
+        lat = inRangeOrUnavailable(lat, LATITUDE_MIN, LATITUDE_MAX);
+        lon = inRangeOrUnavailable(lon, LONGITUDE_MIN, LONGITUDE_MAX);
+
         if (!isNullIsland(lat, lon)) {
             mLongitude = lon;
             mLatitude = lat;
diff --git a/telephony/java/android/telephony/CellIdentityGsm.java b/telephony/java/android/telephony/CellIdentityGsm.java
index 864540d..25c6577 100644
--- a/telephony/java/android/telephony/CellIdentityGsm.java
+++ b/telephony/java/android/telephony/CellIdentityGsm.java
@@ -31,6 +31,11 @@
     private static final String TAG = CellIdentityGsm.class.getSimpleName();
     private static final boolean DBG = false;
 
+    private static final int MAX_LAC = 65535;
+    private static final int MAX_CID = 65535;
+    private static final int MAX_ARFCN = 65535;
+    private static final int MAX_BSIC = 63;
+
     // 16-bit Location Area Code, 0..65535
     private final int mLac;
     // 16-bit GSM Cell Identity described in TS 27.007, 0..65535
@@ -68,10 +73,10 @@
     public CellIdentityGsm(int lac, int cid, int arfcn, int bsic, String mccStr,
                             String mncStr, String alphal, String alphas) {
         super(TAG, CellInfo.TYPE_GSM, mccStr, mncStr, alphal, alphas);
-        mLac = lac;
-        mCid = cid;
-        mArfcn = arfcn;
-        mBsic = bsic;
+        mLac = inRangeOrUnavailable(lac, 0, MAX_LAC);
+        mCid = inRangeOrUnavailable(cid, 0, MAX_CID);
+        mArfcn = inRangeOrUnavailable(arfcn, 0, MAX_ARFCN);
+        mBsic = inRangeOrUnavailable(bsic, 0, MAX_BSIC);
     }
 
     /** @hide */
diff --git a/telephony/java/android/telephony/CellIdentityLte.java b/telephony/java/android/telephony/CellIdentityLte.java
index 14503c7..997b19f 100644
--- a/telephony/java/android/telephony/CellIdentityLte.java
+++ b/telephony/java/android/telephony/CellIdentityLte.java
@@ -32,6 +32,12 @@
     private static final String TAG = CellIdentityLte.class.getSimpleName();
     private static final boolean DBG = false;
 
+    private static final int MAX_CI = 268435455;
+    private static final int MAX_PCI = 503;
+    private static final int MAX_TAC = 65535;
+    private static final int MAX_EARFCN = 262143;
+    private static final int MAX_BANDWIDTH = 20000;
+
     // 28-bit cell identity
     private final int mCi;
     // physical cell id 0..503
@@ -89,11 +95,11 @@
     public CellIdentityLte(int ci, int pci, int tac, int earfcn, int bandwidth, String mccStr,
             String mncStr, String alphal, String alphas) {
         super(TAG, CellInfo.TYPE_LTE, mccStr, mncStr, alphal, alphas);
-        mCi = ci;
-        mPci = pci;
-        mTac = tac;
-        mEarfcn = earfcn;
-        mBandwidth = bandwidth;
+        mCi = inRangeOrUnavailable(ci, 0, MAX_CI);
+        mPci = inRangeOrUnavailable(pci, 0, MAX_PCI);
+        mTac = inRangeOrUnavailable(tac, 0, MAX_TAC);
+        mEarfcn = inRangeOrUnavailable(earfcn, 0, MAX_EARFCN);
+        mBandwidth = inRangeOrUnavailable(bandwidth, 0, MAX_BANDWIDTH);
     }
 
     /** @hide */
diff --git a/telephony/java/android/telephony/CellIdentityNr.java b/telephony/java/android/telephony/CellIdentityNr.java
index 62d23ce..6df60ba 100644
--- a/telephony/java/android/telephony/CellIdentityNr.java
+++ b/telephony/java/android/telephony/CellIdentityNr.java
@@ -29,6 +29,11 @@
 public final class CellIdentityNr extends CellIdentity {
     private static final String TAG = "CellIdentityNr";
 
+    private static final int MAX_PCI = 1007;
+    private static final int MAX_TAC = 65535;
+    private static final int MAX_NRARFCN = 3279165;
+    private static final long MAX_NCI = 68719476735L;
+
     private final int mNrArfcn;
     private final int mPci;
     private final int mTac;
@@ -41,6 +46,7 @@
      * @param nrArfcn NR Absolute Radio Frequency Channel Number, in range [0, 3279165].
      * @param mccStr 3-digit Mobile Country Code in string format.
      * @param mncStr 2 or 3-digit Mobile Network Code in string format.
+     * @param nci The 36-bit NR Cell Identity in range [0, 68719476735].
      * @param alphal long alpha Operator Name String or Enhanced Operator Name String.
      * @param alphas short alpha Operator Name String or Enhanced Operator Name String.
      *
@@ -49,10 +55,10 @@
     public CellIdentityNr(int pci, int tac, int nrArfcn, String mccStr, String mncStr,
             long nci, String alphal, String alphas) {
         super(TAG, CellInfo.TYPE_NR, mccStr, mncStr, alphal, alphas);
-        mPci = pci;
-        mTac = tac;
-        mNrArfcn = nrArfcn;
-        mNci = nci;
+        mPci = inRangeOrUnavailable(pci, 0, MAX_PCI);
+        mTac = inRangeOrUnavailable(tac, 0, MAX_TAC);
+        mNrArfcn = inRangeOrUnavailable(nrArfcn, 0, MAX_NRARFCN);
+        mNci = inRangeOrUnavailable(nci, 0, MAX_NCI);
     }
 
     /** @hide */
diff --git a/telephony/java/android/telephony/CellIdentityTdscdma.java b/telephony/java/android/telephony/CellIdentityTdscdma.java
index 937de70..558e346 100644
--- a/telephony/java/android/telephony/CellIdentityTdscdma.java
+++ b/telephony/java/android/telephony/CellIdentityTdscdma.java
@@ -30,12 +30,18 @@
     private static final String TAG = CellIdentityTdscdma.class.getSimpleName();
     private static final boolean DBG = false;
 
+    private static final int MAX_LAC = 65535;
+    private static final int MAX_CID = 268435455;
+    private static final int MAX_CPID = 127;
+    private static final int MAX_UARFCN = 65535;
+
     // 16-bit Location Area Code, 0..65535, CellInfo.UNAVAILABLE if unknown.
     private final int mLac;
     // 28-bit UMTS Cell Identity described in TS 25.331, 0..268435455, CellInfo.UNAVAILABLE
     // if unknown.
     private final int mCid;
-    // 8-bit Cell Parameters ID described in TS 25.331, 0..127, CellInfo.UNAVAILABLE if unknown.
+    // 8-bit Cell Parameters ID described in TS 25.331 sec 10.3.6.9,
+    // 0..127, CellInfo.UNAVAILABLE if unknown.
     private final int mCpid;
     // 16-bit UMTS Absolute RF Channel Number described in TS 25.101 sec. 5.4.3
     private final int mUarfcn;
@@ -68,10 +74,10 @@
     public CellIdentityTdscdma(String mcc, String mnc, int lac, int cid, int cpid, int uarfcn,
             String alphal, String alphas) {
         super(TAG, CellInfo.TYPE_TDSCDMA, mcc, mnc, alphal, alphas);
-        mLac = lac;
-        mCid = cid;
-        mCpid = cpid;
-        mUarfcn = uarfcn;
+        mLac = inRangeOrUnavailable(lac, 0, MAX_LAC);
+        mCid = inRangeOrUnavailable(cid, 0, MAX_CID);
+        mCpid = inRangeOrUnavailable(cpid, 0, MAX_CPID);
+        mUarfcn = inRangeOrUnavailable(uarfcn, 0, MAX_UARFCN);
     }
 
     private CellIdentityTdscdma(CellIdentityTdscdma cid) {
diff --git a/telephony/java/android/telephony/CellIdentityWcdma.java b/telephony/java/android/telephony/CellIdentityWcdma.java
index b4a2ead..031fed1 100644
--- a/telephony/java/android/telephony/CellIdentityWcdma.java
+++ b/telephony/java/android/telephony/CellIdentityWcdma.java
@@ -31,6 +31,11 @@
     private static final String TAG = CellIdentityWcdma.class.getSimpleName();
     private static final boolean DBG = false;
 
+    private static final int MAX_LAC = 65535;
+    private static final int MAX_CID = 268435455;
+    private static final int MAX_PSC = 511;
+    private static final int MAX_UARFCN = 16383; // a 14 bit number; TS 25.331 ex sec 10.3.8.15
+
     // 16-bit Location Area Code, 0..65535
     private final int mLac;
     // 28-bit UMTS Cell Identity described in TS 25.331, 0..268435455
@@ -68,10 +73,10 @@
     public CellIdentityWcdma (int lac, int cid, int psc, int uarfcn,
                               String mccStr, String mncStr, String alphal, String alphas) {
         super(TAG, CellInfo.TYPE_WCDMA, mccStr, mncStr, alphal, alphas);
-        mLac = lac;
-        mCid = cid;
-        mPsc = psc;
-        mUarfcn = uarfcn;
+        mLac = inRangeOrUnavailable(lac, 0, MAX_LAC);
+        mCid = inRangeOrUnavailable(cid, 0, MAX_CID);
+        mPsc = inRangeOrUnavailable(psc, 0, MAX_PSC);
+        mUarfcn = inRangeOrUnavailable(uarfcn, 0, MAX_UARFCN);
     }
 
     /** @hide */
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 0808adf..d4f9874 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -294,6 +294,19 @@
     public static final String SUBSCRIPTION_TYPE = "subscription_type";
 
     /**
+     * TelephonyProvider column name white_listed_apn_data.
+     * It's a bitmask of APN types that will be allowed on this subscription even if it's metered
+     * and mobile data is turned off by the user.
+     * <P>Type: INTEGER (int)</P> For example, if TYPE_MMS is is true, Telephony will allow MMS
+     * data connection to setup even if MMS is metered and mobile_data is turned off on that
+     * subscription.
+     *
+     * Default value is 0.
+     */
+    /** @hide */
+    public static final String WHITE_LISTED_APN_DATA = "white_listed_apn_data";
+
+    /**
      * This constant is to designate a subscription as a Local-SIM Subscription.
      * <p> A Local-SIM can be a physical SIM inserted into a sim-slot in the device, or eSIM on the
      * device.
@@ -3086,6 +3099,31 @@
         return subId;
     }
 
+    /**
+     * Set whether a subscription always allows MMS connection. If true, MMS network
+     * request will be accepted by telephony even if user turns "mobile data" off
+     * on this subscription.
+     *
+     * @param subId which subscription it's setting to.
+     * @param alwaysAllow whether Mms data is always allowed.
+     * @return whether operation is successful.
+     *
+     * @hide
+     */
+    public boolean setAlwaysAllowMmsData(int subId, boolean alwaysAllow) {
+        try {
+            ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
+            if (iSub != null) {
+                return iSub.setAlwaysAllowMmsData(subId, alwaysAllow);
+            }
+        } catch (RemoteException ex) {
+            if (!isSystemProcess()) {
+                ex.rethrowAsRuntimeException();
+            }
+        }
+        return false;
+    }
+
     private interface CallISubMethodHelper {
         int callMethod(ISub iSub) throws RemoteException;
     }
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 2bd4f8f..18b9fbb 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -10948,4 +10948,33 @@
         }
         return new Pair<Integer, Integer>(-1, -1);
     }
+
+
+    /**
+     * Return whether MMS data is enabled. This will tell if framework will accept a MMS network
+     * request on a subId.
+     *
+     *  Mms is enabled if:
+     *  1) user data is turned on, or
+     *  2) MMS is un-metered for this subscription, or
+     *  3) alwaysAllowMms setting {@link SubscriptionManager#setAlwaysAllowMmsData} is turned on.
+     *
+     * @return whether MMS data is allowed.
+     *
+     * @hide
+     */
+    public boolean isMmsDataEnabled() {
+        String pkgForDebug = mContext != null ? mContext.getOpPackageName() : "<unknown>";
+        try {
+            ITelephony service = getITelephony();
+            if (service != null) {
+                return service.isMmsDataEnabled(getSubId(), pkgForDebug);
+            }
+        } catch (RemoteException ex) {
+            if (!isSystemProcess()) {
+                ex.rethrowAsRuntimeException();
+            }
+        }
+        return false;
+    }
 }
diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java
index e9aede7..be58723 100644
--- a/telephony/java/android/telephony/ims/ImsMmTelManager.java
+++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java
@@ -781,8 +781,13 @@
     }
 
     /**
-     * Change the user's setting for RTT capability of this device.
-     * @param isEnabled if true RTT will be enabled during calls.
+     * Sets the capability of RTT for IMS calls placed on this subscription.
+     *
+     * Note: This does not affect the value of
+     * {@link android.provider.Settings.Secure#RTT_CALLING_MODE}, which is the global user setting
+     * for RTT. That value is enabled/disabled separately by the user through the Accessibility
+     * settings.
+     * @param isEnabled if true RTT should be enabled during calls made on this subscription.
      */
     @RequiresPermission(Manifest.permission.MODIFY_PHONE_STATE)
     public void setRttCapabilitySetting(boolean isEnabled) {
diff --git a/telephony/java/android/telephony/ims/ImsService.java b/telephony/java/android/telephony/ims/ImsService.java
index c008711..e6777c17 100644
--- a/telephony/java/android/telephony/ims/ImsService.java
+++ b/telephony/java/android/telephony/ims/ImsService.java
@@ -40,8 +40,6 @@
 import com.android.ims.internal.IImsFeatureStatusCallback;
 import com.android.internal.annotations.VisibleForTesting;
 
-import static android.Manifest.permission.MODIFY_PHONE_STATE;
-
 /**
  * Main ImsService implementation, which binds via the Telephony ImsResolver. Services that extend
  * ImsService must register the service in their AndroidManifest to be detected by the framework.
@@ -229,8 +227,8 @@
 
     private void setupFeature(ImsFeature f, int slotId, int featureType,
             IImsFeatureStatusCallback c) {
-        f.addImsFeatureStatusCallback(c);
         f.initialize(this, slotId);
+        f.addImsFeatureStatusCallback(c);
         addImsFeature(slotId, featureType, f);
     }
 
diff --git a/telephony/java/android/telephony/ims/compat/feature/ImsFeature.java b/telephony/java/android/telephony/ims/compat/feature/ImsFeature.java
index e8fcac1..de4f174 100644
--- a/telephony/java/android/telephony/ims/compat/feature/ImsFeature.java
+++ b/telephony/java/android/telephony/ims/compat/feature/ImsFeature.java
@@ -19,7 +19,6 @@
 import android.annotation.IntDef;
 import android.annotation.UnsupportedAppUsage;
 import android.content.Context;
-import android.content.Intent;
 import android.os.IInterface;
 import android.os.RemoteException;
 import android.telephony.SubscriptionManager;
@@ -42,32 +41,6 @@
 
     private static final String LOG_TAG = "ImsFeature";
 
-    /**
-     * Action to broadcast when ImsService is up.
-     * Internal use only.
-     * Only defined here separately compatibility purposes with the old ImsService.
-     * @hide
-     */
-    public static final String ACTION_IMS_SERVICE_UP =
-            "com.android.ims.IMS_SERVICE_UP";
-
-    /**
-     * Action to broadcast when ImsService is down.
-     * Internal use only.
-     * Only defined here separately for compatibility purposes with the old ImsService.
-     * @hide
-     */
-    public static final String ACTION_IMS_SERVICE_DOWN =
-            "com.android.ims.IMS_SERVICE_DOWN";
-
-    /**
-     * Part of the ACTION_IMS_SERVICE_UP or _DOWN intents.
-     * A long value; the phone ID corresponding to the IMS service coming up or down.
-     * Only defined here separately for compatibility purposes with the old ImsService.
-     * @hide
-     */
-    public static final String EXTRA_PHONE_ID = "android:phone_id";
-
     // Invalid feature value
     public static final int INVALID = -1;
     // ImsFeatures that are defined in the Manifests. Ensure that these values match the previously
@@ -162,30 +135,6 @@
                 }
             }
         }
-        sendImsServiceIntent(state);
-    }
-
-    /**
-     * Provide backwards compatibility using deprecated service UP/DOWN intents.
-     */
-    private void sendImsServiceIntent(@ImsState int state) {
-        if(mContext == null || mSlotId == SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
-            return;
-        }
-        Intent intent;
-        switch (state) {
-            case ImsFeature.STATE_NOT_AVAILABLE:
-            case ImsFeature.STATE_INITIALIZING:
-                intent = new Intent(ACTION_IMS_SERVICE_DOWN);
-                break;
-            case ImsFeature.STATE_READY:
-                intent = new Intent(ACTION_IMS_SERVICE_UP);
-                break;
-            default:
-                intent = new Intent(ACTION_IMS_SERVICE_DOWN);
-        }
-        intent.putExtra(EXTRA_PHONE_ID, mSlotId);
-        mContext.sendBroadcast(intent);
     }
 
     /**
diff --git a/telephony/java/android/telephony/ims/feature/ImsFeature.java b/telephony/java/android/telephony/ims/feature/ImsFeature.java
index 5e3f398..74af6bf 100644
--- a/telephony/java/android/telephony/ims/feature/ImsFeature.java
+++ b/telephony/java/android/telephony/ims/feature/ImsFeature.java
@@ -20,7 +20,6 @@
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.content.Context;
-import android.content.Intent;
 import android.os.IInterface;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
@@ -395,30 +394,6 @@
                 }
             }
         }
-        sendImsServiceIntent(state);
-    }
-
-    /**
-     * Provide backwards compatibility using deprecated service UP/DOWN intents.
-     */
-    private void sendImsServiceIntent(@ImsState int state) {
-        if (mContext == null || mSlotId == SubscriptionManager.INVALID_SIM_SLOT_INDEX) {
-            return;
-        }
-        Intent intent;
-        switch (state) {
-            case ImsFeature.STATE_UNAVAILABLE:
-            case ImsFeature.STATE_INITIALIZING:
-                intent = new Intent(ACTION_IMS_SERVICE_DOWN);
-                break;
-            case ImsFeature.STATE_READY:
-                intent = new Intent(ACTION_IMS_SERVICE_UP);
-                break;
-            default:
-                intent = new Intent(ACTION_IMS_SERVICE_DOWN);
-        }
-        intent.putExtra(EXTRA_PHONE_ID, mSlotId);
-        mContext.sendBroadcast(intent);
     }
 
     /**
diff --git a/telephony/java/com/android/internal/telephony/DctConstants.java b/telephony/java/com/android/internal/telephony/DctConstants.java
index 6e8d038..bb5c251 100644
--- a/telephony/java/com/android/internal/telephony/DctConstants.java
+++ b/telephony/java/com/android/internal/telephony/DctConstants.java
@@ -94,6 +94,7 @@
     public static final int EVENT_ROAMING_SETTING_CHANGE = BASE + 48;
     public static final int EVENT_DATA_SERVICE_BINDING_CHANGED = BASE + 49;
     public static final int EVENT_DEVICE_PROVISIONED_CHANGE = BASE + 50;
+    public static final int EVENT_APN_WHITE_LIST_CHANGE = BASE + 51;
 
     /***** Constants *****/
 
diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl
index cfba052..b081228 100755
--- a/telephony/java/com/android/internal/telephony/ISub.aidl
+++ b/telephony/java/com/android/internal/telephony/ISub.aidl
@@ -279,4 +279,6 @@
     int getSimStateForSlotIndex(int slotIndex);
 
     boolean isActiveSubId(int subId, String callingPackage);
+
+    boolean setAlwaysAllowMmsData(int subId, boolean alwaysAllow);
 }
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index ecbbd6a..536c514 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1966,4 +1966,6 @@
     int getRadioHalVersion();
 
     boolean isModemEnabledForSlot(int slotIndex, String callingPackage);
+
+    boolean isMmsDataEnabled(int subId, String callingPackage);
 }
diff --git a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
index 80fb58d..12b20ef 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyPermissions.java
@@ -344,10 +344,22 @@
             return true;
         }
         // if the calling package is null then return now as there's no way to perform the
-        // DevicePolicyManager device / profile owner checks.
+        // DevicePolicyManager device / profile owner and AppOp checks
         if (callingPackage == null) {
             return false;
         }
+        // Allow access to an app that has been granted the READ_DEVICE_IDENTIFIERS app op.
+        long token = Binder.clearCallingIdentity();
+        AppOpsManager appOpsManager = (AppOpsManager) context.getSystemService(
+                Context.APP_OPS_SERVICE);
+        try {
+            if (appOpsManager.noteOpNoThrow(AppOpsManager.OPSTR_READ_DEVICE_IDENTIFIERS, uid,
+                    callingPackage) == AppOpsManager.MODE_ALLOWED) {
+                return true;
+            }
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
         // Allow access to a device / profile owner app.
         DevicePolicyManager devicePolicyManager = (DevicePolicyManager) context.getSystemService(
                 Context.DEVICE_POLICY_SERVICE);
diff --git a/tests/FlickerTests/lib/Android.bp b/tests/FlickerTests/lib/Android.bp
index 982fcba..5d8ed2c 100644
--- a/tests/FlickerTests/lib/Android.bp
+++ b/tests/FlickerTests/lib/Android.bp
@@ -20,7 +20,7 @@
     srcs: ["src/**/*.java"],
     static_libs: [
         "androidx.test.janktesthelper",
-        "cts-amwm-util",
+        "cts-wm-util",
         "platformprotosnano",
         "layersprotosnano",
         "truth-prebuilt",
diff --git a/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java b/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java
index e0d74e0..c9e3404 100644
--- a/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java
+++ b/tests/utils/testutils/java/com/android/server/wm/test/filters/FrameworksTestsFilter.java
@@ -34,6 +34,8 @@
 public final class FrameworksTestsFilter extends SelectTest {
 
     private static final String[] SELECTED_TESTS = {
+            // Test specifications for FrameworksMockingCoreTests.
+            "android.app.activity.ActivityThreadClientTest",
             // Test specifications for FrameworksCoreTests.
             "android.app.servertransaction.", // all tests under the package.
             "android.view.DisplayCutoutTest",
diff --git a/tools/aapt2/Debug.cpp b/tools/aapt2/Debug.cpp
index 9832485..3da22b4 100644
--- a/tools/aapt2/Debug.cpp
+++ b/tools/aapt2/Debug.cpp
@@ -129,12 +129,20 @@
     constexpr uint32_t kMask = android::ResTable_map::TYPE_ENUM | android::ResTable_map::TYPE_FLAGS;
     if (attr->type_mask & kMask) {
       for (const auto& symbol : attr->symbols) {
-        printer_->Print(symbol.symbol.name.value().entry);
-        if (symbol.symbol.id) {
-          printer_->Print("(");
+        if (symbol.symbol.name) {
+          printer_->Print(symbol.symbol.name.value().entry);
+
+          if (symbol.symbol.id) {
+            printer_->Print("(");
+            printer_->Print(symbol.symbol.id.value().to_string());
+            printer_->Print(")");
+          }
+        } else if (symbol.symbol.id) {
           printer_->Print(symbol.symbol.id.value().to_string());
-          printer_->Print(")");
+        } else {
+          printer_->Print("???");
         }
+
         printer_->Println(StringPrintf("=0x%08x", symbol.value));
       }
     }
diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
index 950c6f8..9d4b837 100644
--- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
+++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
@@ -967,6 +967,10 @@
      * from the top-level domain and all the labels in domain_suffix_match shall be included in the
      * certificate. The certificate may include additional sub-level labels in addition to the
      * required labels.
+     * <p>More than one match string can be provided by using semicolons to separate the strings
+     * (e.g., example.org;example.com). When multiple strings are specified, a match with any one of
+     * the values is considered a sufficient match for the certificate, i.e., the conditions are
+     * ORed ogether.
      * <p>For example, domain_suffix_match=example.com would match test.example.com but would not
      * match test-example.com.
      * @param domain The domain value