Merge "Do not generate smart suggestions if the last message is from local user"
diff --git a/Android.bp b/Android.bp
index b075f5c..7bdedc7 100644
--- a/Android.bp
+++ b/Android.bp
@@ -77,7 +77,6 @@
         "core/java/android/app/ISearchManager.aidl",
         "core/java/android/app/ISearchManagerCallback.aidl",
         "core/java/android/app/IServiceConnection.aidl",
-        "core/java/android/app/ISmsAppService.aidl",
         "core/java/android/app/IStopUserCallback.aidl",
         "core/java/android/app/job/IJobCallback.aidl",
         "core/java/android/app/job/IJobScheduler.aidl",
@@ -288,6 +287,7 @@
         "core/java/android/service/carrier/ICarrierService.aidl",
         "core/java/android/service/carrier/ICarrierMessagingCallback.aidl",
         "core/java/android/service/carrier/ICarrierMessagingService.aidl",
+        "core/java/android/service/carrier/ICarrierMessagingClientService.aidl",
         "core/java/android/service/contentsuggestions/IContentSuggestionsService.aidl",
         "core/java/android/service/euicc/IDeleteSubscriptionCallback.aidl",
         "core/java/android/service/euicc/IDownloadSubscriptionCallback.aidl",
diff --git a/Android.mk b/Android.mk
index 65d4d24..9c65948 100644
--- a/Android.mk
+++ b/Android.mk
@@ -79,34 +79,6 @@
 
 # ==== hiddenapi lists =======================================
 ifneq ($(UNSAFE_DISABLE_HIDDENAPI_FLAGS),true)
-.KATI_RESTAT: $(INTERNAL_PLATFORM_HIDDENAPI_FLAGS)
-$(INTERNAL_PLATFORM_HIDDENAPI_FLAGS): \
-    PRIVATE_FLAGS_INPUTS := $(PRIVATE_FLAGS_INPUTS) $(SOONG_HIDDENAPI_FLAGS)
-$(INTERNAL_PLATFORM_HIDDENAPI_FLAGS): \
-    frameworks/base/tools/hiddenapi/generate_hiddenapi_lists.py \
-    frameworks/base/config/hiddenapi-greylist.txt \
-    frameworks/base/config/hiddenapi-greylist-max-p.txt \
-    frameworks/base/config/hiddenapi-greylist-max-o.txt \
-    frameworks/base/config/hiddenapi-force-blacklist.txt \
-    $(INTERNAL_PLATFORM_HIDDENAPI_STUB_FLAGS) \
-    $(INTERNAL_PLATFORM_REMOVED_DEX_API_FILE) \
-    $(SOONG_HIDDENAPI_FLAGS)
-	frameworks/base/tools/hiddenapi/generate_hiddenapi_lists.py \
-	    --csv $(INTERNAL_PLATFORM_HIDDENAPI_STUB_FLAGS) $(PRIVATE_FLAGS_INPUTS) \
-	    --greylist frameworks/base/config/hiddenapi-greylist.txt \
-	    --greylist-ignore-conflicts $(INTERNAL_PLATFORM_REMOVED_DEX_API_FILE) \
-	    --greylist-max-p frameworks/base/config/hiddenapi-greylist-max-p.txt \
-	    --greylist-max-o-ignore-conflicts \
-	        frameworks/base/config/hiddenapi-greylist-max-o.txt \
-	    --blacklist frameworks/base/config/hiddenapi-force-blacklist.txt \
-	    --output $@.tmp
-	$(call commit-change-for-toc,$@)
-
-$(INTERNAL_PLATFORM_HIDDENAPI_GREYLIST_METADATA): \
-    frameworks/base/tools/hiddenapi/merge_csv.py \
-    $(PRIVATE_METADATA_INPUTS)
-	frameworks/base/tools/hiddenapi/merge_csv.py $(PRIVATE_METADATA_INPUTS) > $@
-
 $(call dist-for-goals,droidcore,$(INTERNAL_PLATFORM_HIDDENAPI_FLAGS))
 $(call dist-for-goals,droidcore,$(INTERNAL_PLATFORM_HIDDENAPI_GREYLIST_METADATA))
 endif  # UNSAFE_DISABLE_HIDDENAPI_FLAGS
diff --git a/api/TEST_MAPPING b/api/TEST_MAPPING
new file mode 100644
index 0000000..8a676e9
--- /dev/null
+++ b/api/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsCurrentApiSignatureTestCases"
+    }
+  ]
+}
diff --git a/api/current.txt b/api/current.txt
index 1ae87e3..18274a2 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -26,6 +26,7 @@
     field public static final String BIND_APPWIDGET = "android.permission.BIND_APPWIDGET";
     field public static final String BIND_AUTOFILL_SERVICE = "android.permission.BIND_AUTOFILL_SERVICE";
     field public static final String BIND_CALL_REDIRECTION_SERVICE = "android.permission.BIND_CALL_REDIRECTION_SERVICE";
+    field public static final String BIND_CARRIER_MESSAGING_CLIENT_SERVICE = "android.permission.BIND_CARRIER_MESSAGING_CLIENT_SERVICE";
     field @Deprecated public static final String BIND_CARRIER_MESSAGING_SERVICE = "android.permission.BIND_CARRIER_MESSAGING_SERVICE";
     field public static final String BIND_CARRIER_SERVICES = "android.permission.BIND_CARRIER_SERVICES";
     field public static final String BIND_CHOOSER_TARGET_SERVICE = "android.permission.BIND_CHOOSER_TARGET_SERVICE";
@@ -41,7 +42,6 @@
     field public static final String BIND_QUICK_SETTINGS_TILE = "android.permission.BIND_QUICK_SETTINGS_TILE";
     field public static final String BIND_REMOTEVIEWS = "android.permission.BIND_REMOTEVIEWS";
     field public static final String BIND_SCREENING_SERVICE = "android.permission.BIND_SCREENING_SERVICE";
-    field public static final String BIND_SMS_APP_SERVICE = "android.permission.BIND_SMS_APP_SERVICE";
     field public static final String BIND_TELECOM_CONNECTION_SERVICE = "android.permission.BIND_TELECOM_CONNECTION_SERVICE";
     field public static final String BIND_TEXT_SERVICE = "android.permission.BIND_TEXT_SERVICE";
     field public static final String BIND_TV_INPUT = "android.permission.BIND_TV_INPUT";
@@ -224,6 +224,11 @@
 
   public static final class R.attr {
     ctor public R.attr();
+    field public static final int __removed1 = 16844185; // 0x1010599
+    field public static final int __removed2 = 16844186; // 0x101059a
+    field public static final int __removed3 = 16844187; // 0x101059b
+    field public static final int __removed4 = 16844188; // 0x101059c
+    field public static final int __removed5 = 16844189; // 0x101059d
     field public static final int absListViewStyle = 16842858; // 0x101006a
     field public static final int accessibilityEventTypes = 16843648; // 0x1010380
     field public static final int accessibilityFeedbackType = 16843650; // 0x1010382
@@ -484,10 +489,6 @@
     field public static final int dashGap = 16843175; // 0x10101a7
     field public static final int dashWidth = 16843174; // 0x10101a6
     field public static final int data = 16842798; // 0x101002e
-    field public static final int dataRetentionTime = 16844189; // 0x101059d
-    field public static final int dataSentOffDevice = 16844186; // 0x101059a
-    field public static final int dataSharedWithThirdParty = 16844187; // 0x101059b
-    field public static final int dataUsedForMonetization = 16844188; // 0x101059c
     field public static final int datePickerDialogTheme = 16843948; // 0x10104ac
     field public static final int datePickerMode = 16843955; // 0x10104b3
     field public static final int datePickerStyle = 16843612; // 0x101035c
@@ -645,6 +646,7 @@
     field public static final int footerDividersEnabled = 16843311; // 0x101022f
     field public static final int forceDarkAllowed = 16844172; // 0x101058c
     field public static final int forceHasOverlappingRendering = 16844065; // 0x1010521
+    field public static final int forceUriPermissions = 16844197; // 0x10105a5
     field public static final int foreground = 16843017; // 0x1010109
     field public static final int foregroundGravity = 16843264; // 0x1010200
     field public static final int foregroundServiceType = 16844191; // 0x101059f
@@ -1507,7 +1509,6 @@
     field @Deprecated public static final int unfocusedMonthDateColor = 16843588; // 0x1010344
     field public static final int unselectedAlpha = 16843278; // 0x101020e
     field public static final int updatePeriodMillis = 16843344; // 0x1010250
-    field public static final int usageInfoRequired = 16844185; // 0x1010599
     field public static final int use32bitAbi = 16844053; // 0x1010515
     field public static final int useAppZygote = 16844184; // 0x1010598
     field public static final int useDefaultMargins = 16843641; // 0x1010379
@@ -6210,11 +6211,6 @@
     method public void onSharedElementsReady();
   }
 
-  public class SmsAppService extends android.app.Service {
-    ctor public SmsAppService();
-    method public final android.os.IBinder onBind(android.content.Intent);
-  }
-
   public class StatusBarManager {
   }
 
@@ -6742,6 +6738,7 @@
     method public void setCrossProfileCalendarPackages(@NonNull android.content.ComponentName, @Nullable java.util.Set<java.lang.String>);
     method public void setCrossProfileCallerIdDisabled(@NonNull android.content.ComponentName, boolean);
     method public void setCrossProfileContactsSearchDisabled(@NonNull android.content.ComponentName, boolean);
+    method public void setDefaultSmsApplication(@NonNull android.content.ComponentName, @NonNull String);
     method public void setDelegatedScopes(@NonNull android.content.ComponentName, @NonNull String, @NonNull java.util.List<java.lang.String>);
     method public void setDeviceOwnerLockScreenInfo(@NonNull android.content.ComponentName, CharSequence);
     method public void setEndUserSessionMessage(@NonNull android.content.ComponentName, @Nullable CharSequence);
@@ -7252,6 +7249,7 @@
     ctor public BackupManager(android.content.Context);
     method public void dataChanged();
     method public static void dataChanged(String);
+    method @Nullable public android.os.UserHandle getUserForAncestralSerialNumber(long);
     method @Deprecated public int requestRestore(android.app.backup.RestoreObserver);
   }
 
@@ -10267,7 +10265,6 @@
     field public static final String ACTION_PACKAGE_RESTARTED = "android.intent.action.PACKAGE_RESTARTED";
     field public static final String ACTION_PACKAGE_VERIFIED = "android.intent.action.PACKAGE_VERIFIED";
     field public static final String ACTION_PASTE = "android.intent.action.PASTE";
-    field public static final String ACTION_PERMISSION_USAGE_DETAILS = "android.intent.action.PERMISSION_USAGE_DETAILS";
     field public static final String ACTION_PICK = "android.intent.action.PICK";
     field public static final String ACTION_PICK_ACTIVITY = "android.intent.action.PICK_ACTIVITY";
     field public static final String ACTION_POWER_CONNECTED = "android.intent.action.ACTION_POWER_CONNECTED";
@@ -10393,7 +10390,6 @@
     field public static final String EXTRA_NOT_UNKNOWN_SOURCE = "android.intent.extra.NOT_UNKNOWN_SOURCE";
     field public static final String EXTRA_ORIGINATING_URI = "android.intent.extra.ORIGINATING_URI";
     field public static final String EXTRA_PACKAGE_NAME = "android.intent.extra.PACKAGE_NAME";
-    field public static final String EXTRA_PERMISSION_USAGE_PERMISSIONS = "android.intent.extra.PERMISSION_USAGE_PERMISSIONS";
     field public static final String EXTRA_PHONE_NUMBER = "android.intent.extra.PHONE_NUMBER";
     field public static final String EXTRA_PROCESS_TEXT = "android.intent.extra.PROCESS_TEXT";
     field public static final String EXTRA_PROCESS_TEXT_READONLY = "android.intent.extra.PROCESS_TEXT_READONLY";
@@ -11358,8 +11354,8 @@
     field public android.content.pm.ProviderInfo[] providers;
     field public android.content.pm.ActivityInfo[] receivers;
     field public android.content.pm.FeatureInfo[] reqFeatures;
-    field @Deprecated public String[] requestedPermissions;
-    field @Deprecated public int[] requestedPermissionsFlags;
+    field public String[] requestedPermissions;
+    field public int[] requestedPermissionsFlags;
     field public android.content.pm.ServiceInfo[] services;
     field public String sharedUserId;
     field public int sharedUserLabel;
@@ -11367,7 +11363,6 @@
     field public android.content.pm.SigningInfo signingInfo;
     field public String[] splitNames;
     field public int[] splitRevisionCodes;
-    field public android.content.pm.UsesPermissionInfo[] usesPermissions;
     field @Deprecated public int versionCode;
     field public String versionName;
   }
@@ -11867,7 +11862,6 @@
     field public String group;
     field public CharSequence nonLocalizedDescription;
     field @Deprecated public int protectionLevel;
-    field public boolean usageInfoRequired;
   }
 
   public final class ProviderInfo extends android.content.pm.ComponentInfo implements android.os.Parcelable {
@@ -11879,6 +11873,7 @@
     field public static final int FLAG_SINGLE_USER = 1073741824; // 0x40000000
     field public String authority;
     field public int flags;
+    field public boolean forceUriPermissions;
     field public boolean grantUriPermissions;
     field public int initOrder;
     field @Deprecated public boolean isSyncable;
@@ -12058,28 +12053,6 @@
     field public static final android.os.Parcelable.Creator<android.content.pm.SigningInfo> CREATOR;
   }
 
-  public final class UsesPermissionInfo extends android.content.pm.PackageItemInfo implements android.os.Parcelable {
-    method public int describeContents();
-    method public int getDataRetention();
-    method public int getDataRetentionWeeks();
-    method public int getDataSentOffDevice();
-    method public int getDataSharedWithThirdParty();
-    method public int getDataUsedForMonetization();
-    method public int getFlags();
-    method public String getPermission();
-    field public static final android.os.Parcelable.Creator<android.content.pm.UsesPermissionInfo> CREATOR;
-    field public static final int FLAG_REQUESTED_PERMISSION_GRANTED = 2; // 0x2
-    field public static final int RETENTION_NOT_RETAINED = 1; // 0x1
-    field public static final int RETENTION_SPECIFIED = 4; // 0x4
-    field public static final int RETENTION_UNDEFINED = 0; // 0x0
-    field public static final int RETENTION_UNLIMITED = 3; // 0x3
-    field public static final int RETENTION_USER_SELECTED = 2; // 0x2
-    field public static final int USAGE_NO = 3; // 0x3
-    field public static final int USAGE_UNDEFINED = 0; // 0x0
-    field public static final int USAGE_USER_TRIGGERED = 2; // 0x2
-    field public static final int USAGE_YES = 1; // 0x1
-  }
-
   public final class VersionedPackage implements android.os.Parcelable {
     ctor public VersionedPackage(@NonNull String, int);
     ctor public VersionedPackage(@NonNull String, long);
@@ -12357,8 +12330,10 @@
   public final class Resources.Theme {
     method public void applyStyle(int, boolean);
     method public void dump(int, String, String);
+    method public int[] getAttributeResolutionStack(@AttrRes int, @StyleRes int, @StyleRes int);
     method public int getChangingConfigurations();
     method public android.graphics.drawable.Drawable getDrawable(@DrawableRes int) throws android.content.res.Resources.NotFoundException;
+    method @StyleRes public int getExplicitStyle(@Nullable android.util.AttributeSet);
     method public android.content.res.Resources getResources();
     method @NonNull public android.content.res.TypedArray obtainStyledAttributes(@NonNull @StyleableRes int[]);
     method @NonNull public android.content.res.TypedArray obtainStyledAttributes(@StyleRes int, @NonNull @StyleableRes int[]) throws android.content.res.Resources.NotFoundException;
@@ -14197,6 +14172,7 @@
     field public static final int DEPTH_POINT_CLOUD = 257; // 0x101
     field public static final int FLEX_RGBA_8888 = 42; // 0x2a
     field public static final int FLEX_RGB_888 = 41; // 0x29
+    field public static final int HEIC = 1212500294; // 0x48454946
     field public static final int JPEG = 256; // 0x100
     field public static final int NV16 = 16; // 0x10
     field public static final int NV21 = 17; // 0x11
@@ -14215,13 +14191,16 @@
     field public static final int YV12 = 842094169; // 0x32315659
   }
 
-  public final class Insets {
+  public final class Insets implements android.os.Parcelable {
     method @NonNull public static android.graphics.Insets add(@NonNull android.graphics.Insets, @NonNull android.graphics.Insets);
+    method public int describeContents();
     method @NonNull public static android.graphics.Insets max(@NonNull android.graphics.Insets, @NonNull android.graphics.Insets);
     method @NonNull public static android.graphics.Insets min(@NonNull android.graphics.Insets, @NonNull android.graphics.Insets);
     method @NonNull public static android.graphics.Insets of(int, int, int, int);
     method @NonNull public static android.graphics.Insets of(@Nullable android.graphics.Rect);
     method @NonNull public static android.graphics.Insets subtract(@NonNull android.graphics.Insets, @NonNull android.graphics.Insets);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.graphics.Insets> CREATOR;
     field public static final android.graphics.Insets NONE;
     field public final int bottom;
     field public final int left;
@@ -16513,6 +16492,7 @@
     field public static final int BIOMETRIC_ERROR_LOCKOUT = 7; // 0x7
     field public static final int BIOMETRIC_ERROR_LOCKOUT_PERMANENT = 9; // 0x9
     field public static final int BIOMETRIC_ERROR_NO_BIOMETRICS = 11; // 0xb
+    field public static final int BIOMETRIC_ERROR_NO_DEVICE_CREDENTIAL = 14; // 0xe
     field public static final int BIOMETRIC_ERROR_NO_SPACE = 4; // 0x4
     field public static final int BIOMETRIC_ERROR_TIMEOUT = 3; // 0x3
     field public static final int BIOMETRIC_ERROR_UNABLE_TO_PROCESS = 2; // 0x2
@@ -16535,8 +16515,8 @@
   public static class BiometricPrompt.Builder {
     ctor public BiometricPrompt.Builder(android.content.Context);
     method public android.hardware.biometrics.BiometricPrompt build();
+    method public android.hardware.biometrics.BiometricPrompt.Builder setAllowDeviceCredential(boolean);
     method public android.hardware.biometrics.BiometricPrompt.Builder setDescription(@NonNull CharSequence);
-    method public android.hardware.biometrics.BiometricPrompt.Builder setEnableFallback(boolean);
     method public android.hardware.biometrics.BiometricPrompt.Builder setNegativeButton(@NonNull CharSequence, @NonNull java.util.concurrent.Executor, @NonNull android.content.DialogInterface.OnClickListener);
     method public android.hardware.biometrics.BiometricPrompt.Builder setRequireConfirmation(boolean);
     method public android.hardware.biometrics.BiometricPrompt.Builder setSubtitle(@NonNull CharSequence);
@@ -19447,9 +19427,9 @@
     method public static android.icu.text.BreakIterator getSentenceInstance(java.util.Locale);
     method public static android.icu.text.BreakIterator getSentenceInstance(android.icu.util.ULocale);
     method public abstract java.text.CharacterIterator getText();
-    method public static android.icu.text.BreakIterator getTitleInstance();
-    method public static android.icu.text.BreakIterator getTitleInstance(java.util.Locale);
-    method public static android.icu.text.BreakIterator getTitleInstance(android.icu.util.ULocale);
+    method @Deprecated public static android.icu.text.BreakIterator getTitleInstance();
+    method @Deprecated public static android.icu.text.BreakIterator getTitleInstance(java.util.Locale);
+    method @Deprecated public static android.icu.text.BreakIterator getTitleInstance(android.icu.util.ULocale);
     method public static android.icu.text.BreakIterator getWordInstance();
     method public static android.icu.text.BreakIterator getWordInstance(java.util.Locale);
     method public static android.icu.text.BreakIterator getWordInstance(android.icu.util.ULocale);
@@ -19466,7 +19446,7 @@
     field public static final int KIND_CHARACTER = 0; // 0x0
     field public static final int KIND_LINE = 2; // 0x2
     field public static final int KIND_SENTENCE = 3; // 0x3
-    field public static final int KIND_TITLE = 4; // 0x4
+    field @Deprecated public static final int KIND_TITLE = 4; // 0x4
     field public static final int KIND_WORD = 1; // 0x1
     field public static final int WORD_IDEO = 400; // 0x190
     field public static final int WORD_IDEO_LIMIT = 500; // 0x1f4
@@ -22644,6 +22624,7 @@
     method public int getCodeType();
     method public int getConstellationType();
     method public int getMultipathIndicator();
+    method @NonNull public String getOtherCodeTypeName();
     method public double getPseudorangeRateMetersPerSecond();
     method public double getPseudorangeRateUncertaintyMetersPerSecond();
     method public long getReceivedSvTimeNanos();
@@ -22669,10 +22650,11 @@
     field public static final int CODE_TYPE_A = 0; // 0x0
     field public static final int CODE_TYPE_B = 1; // 0x1
     field public static final int CODE_TYPE_C = 2; // 0x2
-    field public static final int CODE_TYPE_CODELESS = 13; // 0xd
     field public static final int CODE_TYPE_I = 3; // 0x3
     field public static final int CODE_TYPE_L = 4; // 0x4
     field public static final int CODE_TYPE_M = 5; // 0x5
+    field public static final int CODE_TYPE_N = 13; // 0xd
+    field public static final int CODE_TYPE_OTHER = 255; // 0xff
     field public static final int CODE_TYPE_P = 6; // 0x6
     field public static final int CODE_TYPE_Q = 7; // 0x7
     field public static final int CODE_TYPE_S = 8; // 0x8
@@ -23747,6 +23729,7 @@
     ctor public ExifInterface(@NonNull java.io.InputStream) throws java.io.IOException;
     method public double getAltitude(double);
     method @Nullable public String getAttribute(@NonNull String);
+    method @Nullable public byte[] getAttributeBytes(@NonNull String);
     method public double getAttributeDouble(@NonNull String, double);
     method public int getAttributeInt(@NonNull String, int);
     method @Nullable public long[] getAttributeRange(@NonNull String);
@@ -23902,6 +23885,7 @@
     field public static final String TAG_USER_COMMENT = "UserComment";
     field public static final String TAG_WHITE_BALANCE = "WhiteBalance";
     field public static final String TAG_WHITE_POINT = "WhitePoint";
+    field public static final String TAG_XMP = "Xmp";
     field public static final String TAG_X_RESOLUTION = "XResolution";
     field public static final String TAG_Y_CB_CR_COEFFICIENTS = "YCbCrCoefficients";
     field public static final String TAG_Y_CB_CR_POSITIONING = "YCbCrPositioning";
@@ -24555,7 +24539,9 @@
   }
 
   public static final class MediaCodecInfo.VideoCapabilities.PerformancePoint {
+    ctor public MediaCodecInfo.VideoCapabilities.PerformancePoint(int, int, int);
     method public boolean covers(@NonNull android.media.MediaFormat);
+    method public boolean covers(@NonNull android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint);
     field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_100;
     field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_120;
     field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint FHD_200;
@@ -24590,8 +24576,8 @@
     field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_50;
     field public static final android.media.MediaCodecInfo.VideoCapabilities.PerformancePoint UHD_60;
     field public final int frameRate;
-    field public final int height;
-    field public final int width;
+    field public final long macroBlockRate;
+    field public final int macroBlocks;
   }
 
   public final class MediaCodecList {
@@ -34202,7 +34188,6 @@
   }
 
   public static class Build.Partition {
-    ctor public Build.Partition();
     method public long getBuildTimeMillis();
     method @NonNull public String getFingerprint();
     method @NonNull public String getName();
@@ -38361,11 +38346,7 @@
     method @NonNull public static String getVolumeName(@NonNull android.net.Uri);
     method @NonNull public static android.provider.MediaStore.PendingSession openPending(@NonNull android.content.Context, @NonNull android.net.Uri);
     method @NonNull public static android.net.Uri setIncludePending(@NonNull android.net.Uri);
-    method @NonNull public static android.net.Uri setIncludeTrashed(@NonNull android.net.Uri);
     method @NonNull public static android.net.Uri setRequireOriginal(@NonNull android.net.Uri);
-    method public static void trash(@NonNull android.content.Context, @NonNull android.net.Uri);
-    method public static void trash(@NonNull android.content.Context, @NonNull android.net.Uri, long);
-    method public static void untrash(@NonNull android.content.Context, @NonNull android.net.Uri);
     field public static final String ACTION_IMAGE_CAPTURE = "android.media.action.IMAGE_CAPTURE";
     field public static final String ACTION_IMAGE_CAPTURE_SECURE = "android.media.action.IMAGE_CAPTURE_SECURE";
     field public static final String ACTION_REVIEW = "android.provider.action.REVIEW";
@@ -38636,14 +38617,14 @@
   public static interface MediaStore.MediaColumns extends android.provider.BaseColumns {
     field @Deprecated public static final String DATA = "_data";
     field public static final String DATE_ADDED = "date_added";
-    field public static final String DATE_EXPIRES = "date_expires";
     field public static final String DATE_MODIFIED = "date_modified";
     field public static final String DISPLAY_NAME = "_display_name";
-    field public static final String HASH = "_hash";
+    field public static final String DOCUMENT_ID = "document_id";
     field public static final String HEIGHT = "height";
+    field public static final String INSTANCE_ID = "instance_id";
     field public static final String IS_PENDING = "is_pending";
-    field public static final String IS_TRASHED = "is_trashed";
     field public static final String MIME_TYPE = "mime_type";
+    field public static final String ORIGINAL_DOCUMENT_ID = "original_document_id";
     field public static final String OWNER_PACKAGE_NAME = "owner_package_name";
     field public static final String PRIMARY_DIRECTORY = "primary_directory";
     field public static final String SECONDARY_DIRECTORY = "secondary_directory";
@@ -41360,6 +41341,11 @@
     field public static final android.os.Parcelable.Creator<android.service.carrier.CarrierIdentifier> CREATOR;
   }
 
+  public class CarrierMessagingClientService extends android.app.Service {
+    ctor public CarrierMessagingClientService();
+    method public final android.os.IBinder onBind(android.content.Intent);
+  }
+
   public abstract class CarrierMessagingService extends android.app.Service {
     ctor public CarrierMessagingService();
     method @Nullable public android.os.IBinder onBind(@NonNull android.content.Intent);
@@ -41701,6 +41687,7 @@
 
   public static class NotificationListenerService.Ranking {
     ctor public NotificationListenerService.Ranking();
+    method public boolean canBubble();
     method public boolean canShowBadge();
     method public android.app.NotificationChannel getChannel();
     method public int getImportance();
@@ -45165,13 +45152,13 @@
     method @Deprecated public void setVoicemailVibrationEnabled(android.telecom.PhoneAccountHandle, boolean);
     method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void switchMultiSimConfig(int);
     method public boolean updateAvailableNetworks(java.util.List<android.telephony.AvailableNetworkInfo>);
+    field public static final String ACTION_CARRIER_MESSAGING_CLIENT_SERVICE = "android.telephony.action.CARRIER_MESSAGING_CLIENT_SERVICE";
     field public static final String ACTION_CONFIGURE_VOICEMAIL = "android.telephony.action.CONFIGURE_VOICEMAIL";
     field public static final String ACTION_NETWORK_COUNTRY_CHANGED = "android.telephony.action.NETWORK_COUNTRY_CHANGED";
     field @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public static final String ACTION_PHONE_STATE_CHANGED = "android.intent.action.PHONE_STATE";
     field public static final String ACTION_RESPOND_VIA_MESSAGE = "android.intent.action.RESPOND_VIA_MESSAGE";
     field public static final String ACTION_SECRET_CODE = "android.telephony.action.SECRET_CODE";
     field public static final String ACTION_SHOW_VOICEMAIL_NOTIFICATION = "android.telephony.action.SHOW_VOICEMAIL_NOTIFICATION";
-    field public static final String ACTION_SMS_APP_SERVICE = "android.telephony.action.SMS_APP_SERVICE";
     field public static final String ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED = "android.telephony.action.SUBSCRIPTION_CARRIER_IDENTITY_CHANGED";
     field public static final String ACTION_SUBSCRIPTION_PRECISE_CARRIER_IDENTITY_CHANGED = "android.telephony.action.SUBSCRIPTION_PRECISE_CARRIER_IDENTITY_CHANGED";
     field public static final int APPTYPE_CSIM = 4; // 0x4
@@ -49010,6 +48997,7 @@
     method public boolean[] hasKeys(int...);
     method public boolean hasMicrophone();
     method public boolean isEnabled();
+    method public boolean isExternal();
     method public boolean isVirtual();
     method public boolean supportsSource(int);
     method public void writeToParcel(android.os.Parcel, int);
@@ -49565,6 +49553,7 @@
     ctor protected LayoutInflater(android.view.LayoutInflater, android.content.Context);
     method public abstract android.view.LayoutInflater cloneInContext(android.content.Context);
     method public final android.view.View createView(String, String, android.util.AttributeSet) throws java.lang.ClassNotFoundException, android.view.InflateException;
+    method @Nullable public final android.view.View createView(@NonNull android.content.Context, @NonNull String, @Nullable String, @Nullable android.util.AttributeSet) throws java.lang.ClassNotFoundException, android.view.InflateException;
     method public static android.view.LayoutInflater from(android.content.Context);
     method public android.content.Context getContext();
     method public final android.view.LayoutInflater.Factory getFactory();
@@ -49576,6 +49565,7 @@
     method public android.view.View inflate(org.xmlpull.v1.XmlPullParser, @Nullable android.view.ViewGroup, boolean);
     method protected android.view.View onCreateView(String, android.util.AttributeSet) throws java.lang.ClassNotFoundException;
     method protected android.view.View onCreateView(android.view.View, String, android.util.AttributeSet) throws java.lang.ClassNotFoundException;
+    method @Nullable public android.view.View onCreateView(@NonNull android.content.Context, @Nullable android.view.View, @NonNull String, @Nullable android.util.AttributeSet) throws java.lang.ClassNotFoundException;
     method public void setFactory(android.view.LayoutInflater.Factory);
     method public void setFactory2(android.view.LayoutInflater.Factory2);
     method public void setFilter(android.view.LayoutInflater.Filter);
@@ -50321,6 +50311,8 @@
     method @android.view.ViewDebug.ExportedProperty(category="drawing") public float getAlpha();
     method public android.view.animation.Animation getAnimation();
     method public android.os.IBinder getApplicationWindowToken();
+    method @NonNull public java.util.List<java.lang.Integer> getAttributeResolutionStack();
+    method @NonNull public java.util.Map<java.lang.Integer,java.lang.Integer> getAttributeSourceResourceMap();
     method @android.view.ViewDebug.ExportedProperty @Nullable public String[] getAutofillHints();
     method public final android.view.autofill.AutofillId getAutofillId();
     method public int getAutofillType();
@@ -50351,6 +50343,7 @@
     method public void getDrawingRect(android.graphics.Rect);
     method public long getDrawingTime();
     method @android.view.ViewDebug.ExportedProperty(category="drawing") public float getElevation();
+    method @StyleRes public int getExplicitStyle();
     method @android.view.ViewDebug.ExportedProperty public boolean getFilterTouchesWhenObscured();
     method @android.view.ViewDebug.ExportedProperty public boolean getFitsSystemWindows();
     method @android.view.ViewDebug.ExportedProperty(mapping={@android.view.ViewDebug.IntToString(from=android.view.View.NOT_FOCUSABLE, to="NOT_FOCUSABLE"), @android.view.ViewDebug.IntToString(from=android.view.View.FOCUSABLE, to="FOCUSABLE"), @android.view.ViewDebug.IntToString(from=android.view.View.FOCUSABLE_AUTO, to="FOCUSABLE_AUTO")}, category="focus") public int getFocusable();
@@ -50645,6 +50638,7 @@
     method public static int resolveSizeAndState(int, int, int);
     method public boolean restoreDefaultFocus();
     method public void restoreHierarchyState(android.util.SparseArray<android.os.Parcelable>);
+    method public final void saveAttributeDataForStyleable(@NonNull android.content.Context, @NonNull int[], @Nullable android.util.AttributeSet, @NonNull android.content.res.TypedArray, int, int);
     method public void saveHierarchyState(android.util.SparseArray<android.os.Parcelable>);
     method public void scheduleDrawable(@NonNull android.graphics.drawable.Drawable, @NonNull Runnable, long);
     method public void scrollBy(int, int);
@@ -51122,6 +51116,7 @@
     method public int getScaledHoverSlop();
     method public int getScaledMaximumDrawingCacheSize();
     method public int getScaledMaximumFlingVelocity();
+    method public int getScaledMinScalingSpan();
     method public int getScaledMinimumFlingVelocity();
     method public int getScaledOverflingDistance();
     method public int getScaledOverscrollDistance();
@@ -52618,7 +52613,6 @@
   public abstract class Animation implements java.lang.Cloneable {
     ctor public Animation();
     ctor public Animation(android.content.Context, android.util.AttributeSet);
-    method public void addAnimationListener(android.view.animation.Animation.AnimationListener);
     method protected void applyTransformation(float, android.view.animation.Transformation);
     method public void cancel();
     method protected android.view.animation.Animation clone() throws java.lang.CloneNotSupportedException;
@@ -52643,7 +52637,6 @@
     method public void initialize(int, int, int, int);
     method public boolean isFillEnabled();
     method public boolean isInitialized();
-    method public void removeAnimationListener(android.view.animation.Animation.AnimationListener);
     method public void reset();
     method protected float resolveSize(int, float, int, int);
     method public void restrictDuration(long);
@@ -54860,6 +54853,7 @@
     method public void deferNotifyDataSetChanged();
     method public void fling(int);
     method public android.widget.AbsListView.LayoutParams generateLayoutParams(android.util.AttributeSet);
+    method @ColorInt public int getBottomEdgeEffectColor();
     method @android.view.ViewDebug.ExportedProperty(category="drawing") @ColorInt public int getCacheColorHint();
     method public int getCheckedItemCount();
     method public long[] getCheckedItemIds();
@@ -54874,6 +54868,7 @@
     method @android.view.ViewDebug.ExportedProperty public android.view.View getSelectedView();
     method public android.graphics.drawable.Drawable getSelector();
     method public CharSequence getTextFilter();
+    method @ColorInt public int getTopEdgeEffectColor();
     method public int getTranscriptMode();
     method protected void handleDataChanged();
     method public boolean hasTextFilter();
@@ -54901,9 +54896,11 @@
     method public void reclaimViews(java.util.List<android.view.View>);
     method public void scrollListBy(int);
     method public void setAdapter(android.widget.ListAdapter);
+    method public void setBottomEdgeEffectColor(@ColorInt int);
     method public void setCacheColorHint(@ColorInt int);
     method public void setChoiceMode(int);
     method public void setDrawSelectorOnTop(boolean);
+    method public void setEdgeEffectColor(@ColorInt int);
     method public void setFastScrollAlwaysVisible(boolean);
     method public void setFastScrollEnabled(boolean);
     method public void setFastScrollStyle(int);
@@ -54922,6 +54919,7 @@
     method public void setSmoothScrollbarEnabled(boolean);
     method public void setStackFromBottom(boolean);
     method public void setTextFilterEnabled(boolean);
+    method public void setTopEdgeEffectColor(@ColorInt int);
     method public void setTranscriptMode(int);
     method public void setVelocityScale(float);
     method public void smoothScrollBy(int, int);
@@ -55251,6 +55249,7 @@
     method public void performCompletion();
     method protected void performFiltering(CharSequence, int);
     method public void performValidation();
+    method public final void refreshAutoCompleteResults();
     method protected void replaceText(CharSequence);
     method public <T extends android.widget.ListAdapter & android.widget.Filterable> void setAdapter(T);
     method public void setCompletionHint(CharSequence);
@@ -55554,6 +55553,7 @@
     ctor public EdgeEffect(android.content.Context);
     method public boolean draw(android.graphics.Canvas);
     method public void finish();
+    method @Nullable public android.graphics.BlendMode getBlendMode();
     method @ColorInt public int getColor();
     method public int getMaxHeight();
     method public boolean isFinished();
@@ -55561,8 +55561,10 @@
     method public void onPull(float);
     method public void onPull(float, float);
     method public void onRelease();
+    method public void setBlendMode(@Nullable android.graphics.BlendMode);
     method public void setColor(@ColorInt int);
     method public void setSize(int, int);
+    field public static final android.graphics.BlendMode DEFAULT_BLEND_MODE;
   }
 
   public class EditText extends android.widget.TextView {
@@ -56012,6 +56014,7 @@
     method @Nullable public android.view.View getAnchorView();
     method @StyleRes public int getAnimationStyle();
     method @Nullable public android.graphics.drawable.Drawable getBackground();
+    method @Nullable public android.graphics.Rect getEpicenterBounds();
     method public int getHeight();
     method public int getHorizontalOffset();
     method public int getInputMethodMode();
@@ -56038,6 +56041,7 @@
     method public void setBackgroundDrawable(@Nullable android.graphics.drawable.Drawable);
     method public void setContentWidth(int);
     method public void setDropDownGravity(int);
+    method public void setEpicenterBounds(@Nullable android.graphics.Rect);
     method public void setHeight(int);
     method public void setHorizontalOffset(int);
     method public void setInputMethodMode(int);
@@ -56298,6 +56302,7 @@
     method public android.view.View getContentView();
     method public float getElevation();
     method @Nullable public android.transition.Transition getEnterTransition();
+    method @Nullable public android.graphics.Rect getEpicenterBounds();
     method @Nullable public android.transition.Transition getExitTransition();
     method public int getHeight();
     method public int getInputMethodMode();
@@ -56310,30 +56315,37 @@
     method public int getWindowLayoutType();
     method public boolean isAboveAnchor();
     method public boolean isAttachedInDecor();
+    method public boolean isClipToScreenEnabled();
     method public boolean isClippingEnabled();
     method public boolean isFocusable();
+    method public boolean isLayoutInScreenEnabled();
     method public boolean isOutsideTouchable();
     method public boolean isShowing();
     method public boolean isSplitTouchEnabled();
+    method public boolean isTouchModal();
     method public boolean isTouchable();
     method public void setAnimationStyle(int);
     method public void setAttachedInDecor(boolean);
     method public void setBackgroundDrawable(android.graphics.drawable.Drawable);
+    method public void setClipToScreenEnabled(boolean);
     method public void setClippingEnabled(boolean);
     method public void setContentView(android.view.View);
     method public void setElevation(float);
     method public void setEnterTransition(@Nullable android.transition.Transition);
+    method public void setEpicenterBounds(@Nullable android.graphics.Rect);
     method public void setExitTransition(@Nullable android.transition.Transition);
     method public void setFocusable(boolean);
     method public void setHeight(int);
     method public void setIgnoreCheekPress();
     method public void setInputMethodMode(int);
+    method public void setLayoutInScreenEnabled(boolean);
     method public void setOnDismissListener(android.widget.PopupWindow.OnDismissListener);
     method public void setOutsideTouchable(boolean);
     method public void setOverlapAnchor(boolean);
     method public void setSoftInputMode(int);
     method public void setSplitTouchEnabled(boolean);
     method public void setTouchInterceptor(android.view.View.OnTouchListener);
+    method public void setTouchModal(boolean);
     method public void setTouchable(boolean);
     method public void setWidth(int);
     method @Deprecated public void setWindowLayoutMode(int, int);
@@ -56362,12 +56374,17 @@
     ctor public ProgressBar(android.content.Context, android.util.AttributeSet);
     ctor public ProgressBar(android.content.Context, android.util.AttributeSet, int);
     ctor public ProgressBar(android.content.Context, android.util.AttributeSet, int, int);
+    method @Nullable public android.graphics.drawable.Drawable getCurrentDrawable();
     method public android.graphics.drawable.Drawable getIndeterminateDrawable();
     method @Nullable public android.content.res.ColorStateList getIndeterminateTintList();
     method @Nullable public android.graphics.PorterDuff.Mode getIndeterminateTintMode();
     method public android.view.animation.Interpolator getInterpolator();
     method @android.view.ViewDebug.ExportedProperty(category="progress") public int getMax();
+    method @Px public int getMaxHeight();
+    method @Px public int getMaxWidth();
     method @android.view.ViewDebug.ExportedProperty(category="progress") public int getMin();
+    method @Px public int getMinHeight();
+    method @Px public int getMinWidth();
     method @android.view.ViewDebug.ExportedProperty(category="progress") public int getProgress();
     method @Nullable public android.content.res.ColorStateList getProgressBackgroundTintList();
     method @Nullable public android.graphics.PorterDuff.Mode getProgressBackgroundTintMode();
@@ -56391,7 +56408,11 @@
     method public void setInterpolator(android.content.Context, @InterpolatorRes int);
     method public void setInterpolator(android.view.animation.Interpolator);
     method public void setMax(int);
+    method public void setMaxHeight(@Px int);
+    method public void setMaxWidth(@Px int);
     method public void setMin(int);
+    method public void setMinHeight(@Px int);
+    method public void setMinWidth(@Px int);
     method public void setProgress(int);
     method public void setProgress(int, boolean);
     method public void setProgressBackgroundTintList(@Nullable android.content.res.ColorStateList);
@@ -56655,6 +56676,7 @@
     method public boolean isFillViewport();
     method public boolean isSmoothScrollingEnabled();
     method public boolean pageScroll(int);
+    method public void scrollToDescendant(android.view.View);
     method public void setFillViewport(boolean);
     method public void setSmoothScrollingEnabled(boolean);
     method public final void smoothScrollBy(int, int);
diff --git a/api/removed.txt b/api/removed.txt
index 9f4b041..f5bd434 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -344,7 +344,7 @@
   public final class PowerManager {
     method public void goToSleep(long);
     method @Deprecated public void userActivity(long, boolean);
-    method public void wakeUp(long);
+    method @Deprecated public void wakeUp(long);
   }
 
   public class RecoverySystem {
@@ -507,6 +507,19 @@
     field @Deprecated public static final String TIMESTAMP = "timestamp";
   }
 
+  public final class MediaStore {
+    method @Deprecated @NonNull public static android.net.Uri setIncludeTrashed(@NonNull android.net.Uri);
+    method @Deprecated public static void trash(@NonNull android.content.Context, @NonNull android.net.Uri);
+    method @Deprecated public static void trash(@NonNull android.content.Context, @NonNull android.net.Uri, long);
+    method @Deprecated public static void untrash(@NonNull android.content.Context, @NonNull android.net.Uri);
+  }
+
+  public static interface MediaStore.MediaColumns extends android.provider.BaseColumns {
+    field @Deprecated public static final String DATE_EXPIRES = "date_expires";
+    field @Deprecated public static final String HASH = "_hash";
+    field @Deprecated public static final String IS_TRASHED = "is_trashed";
+  }
+
   public static final class Settings.Global extends android.provider.Settings.NameValueTable {
     field @Deprecated public static final String CONTACT_METADATA_SYNC = "contact_metadata_sync";
   }
diff --git a/api/system-current.txt b/api/system-current.txt
index a0eef1d..c9b8c38 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -201,7 +201,6 @@
   }
 
   public static final class R.array {
-    field public static final int config_defaultRoleHolders = 17235974; // 0x1070006
     field public static final int config_keySystemUuidMapping = 17235973; // 0x1070005
   }
 
@@ -237,6 +236,12 @@
   }
 
   public static final class R.string {
+    field public static final int config_defaultAssistant = 17039393; // 0x1040021
+    field public static final int config_defaultBrowser = 17039394; // 0x1040022
+    field public static final int config_defaultDialer = 17039395; // 0x1040023
+    field public static final int config_defaultGallery = 17039398; // 0x1040026
+    field public static final int config_defaultMusic = 17039397; // 0x1040025
+    field public static final int config_defaultSms = 17039396; // 0x1040024
     field public static final int config_feedbackIntentExtraKey = 17039391; // 0x104001f
     field public static final int config_feedbackIntentNameKey = 17039392; // 0x1040020
     field public static final int config_helpIntentExtraKey = 17039389; // 0x104001d
@@ -711,6 +716,7 @@
     method @Deprecated public int requestRestore(android.app.backup.RestoreObserver, android.app.backup.BackupManagerMonitor);
     method @Deprecated @RequiresPermission(android.Manifest.permission.BACKUP) public String selectBackupTransport(String);
     method @RequiresPermission(android.Manifest.permission.BACKUP) public void selectBackupTransport(android.content.ComponentName, android.app.backup.SelectBackupTransportCallback);
+    method @RequiresPermission(android.Manifest.permission.BACKUP) public void setAncestralSerialNumber(long);
     method @RequiresPermission(android.Manifest.permission.BACKUP) public void setAutoRestore(boolean);
     method @RequiresPermission(android.Manifest.permission.BACKUP) public void setBackupEnabled(boolean);
     method @RequiresPermission(android.Manifest.permission.BACKUP) public void updateTransportAttributes(android.content.ComponentName, String, @Nullable android.content.Intent, String, @Nullable android.content.Intent, @Nullable String);
@@ -1071,16 +1077,17 @@
 
   public final class RoleManager {
     method @RequiresPermission(android.Manifest.permission.OBSERVE_ROLE_HOLDERS) public void addOnRoleHoldersChangedListenerAsUser(@NonNull java.util.concurrent.Executor, @NonNull android.app.role.OnRoleHoldersChangedListener, @NonNull android.os.UserHandle);
-    method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void addRoleHolderAsUser(@NonNull String, @NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull android.app.role.RoleManagerCallback);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void addRoleHolderAsUser(@NonNull String, @NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull android.app.role.RoleManagerCallback);
     method @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public boolean addRoleHolderFromController(@NonNull String, @NonNull String);
-    method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void clearRoleHoldersAsUser(@NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull android.app.role.RoleManagerCallback);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void clearRoleHoldersAsUser(@NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull android.app.role.RoleManagerCallback);
     method @NonNull @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public java.util.List<java.lang.String> getHeldRolesFromController(@NonNull String);
     method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public java.util.List<java.lang.String> getRoleHolders(@NonNull String);
     method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public java.util.List<java.lang.String> getRoleHoldersAsUser(@NonNull String, @NonNull android.os.UserHandle);
     method @RequiresPermission(android.Manifest.permission.OBSERVE_ROLE_HOLDERS) public void removeOnRoleHoldersChangedListenerAsUser(@NonNull android.app.role.OnRoleHoldersChangedListener, @NonNull android.os.UserHandle);
-    method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void removeRoleHolderAsUser(@NonNull String, @NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull android.app.role.RoleManagerCallback);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_ROLE_HOLDERS) public void removeRoleHolderAsUser(@NonNull String, @NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull android.app.role.RoleManagerCallback);
     method @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public boolean removeRoleHolderFromController(@NonNull String, @NonNull String);
     method @RequiresPermission("com.android.permissioncontroller.permission.MANAGE_ROLES_FROM_CONTROLLER") public void setRoleNamesFromController(@NonNull java.util.List<java.lang.String>);
+    field public static final int MANAGE_HOLDERS_FLAG_DONT_KILL_APP = 1; // 0x1
     field public static final String ROLE_ASSISTANT = "android.app.role.ASSISTANT";
   }
 
@@ -3912,11 +3919,13 @@
 
   public class ConnectivityManager {
     method @RequiresPermission(android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD) public android.net.SocketKeepalive createNattKeepalive(@NonNull android.net.Network, @NonNull java.io.FileDescriptor, @NonNull java.net.InetAddress, @NonNull java.net.InetAddress, @NonNull java.util.concurrent.Executor, @NonNull android.net.SocketKeepalive.Callback);
+    method @RequiresPermission(android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD) public android.net.SocketKeepalive createSocketKeepalive(@NonNull android.net.Network, @NonNull java.net.Socket, @NonNull java.util.concurrent.Executor, @NonNull android.net.SocketKeepalive.Callback);
     method public boolean getAvoidBadWifi();
     method @RequiresPermission(android.Manifest.permission.LOCAL_MAC_ADDRESS) public String getCaptivePortalServerUrl();
     method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void getLatestTetheringEntitlementValue(int, boolean, @NonNull android.net.ConnectivityManager.TetheringEntitlementValueListener, @Nullable android.os.Handler);
     method @RequiresPermission(anyOf={android.Manifest.permission.TETHER_PRIVILEGED, android.Manifest.permission.WRITE_SETTINGS}) public boolean isTetheringSupported();
     method @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", android.Manifest.permission.NETWORK_SETUP_WIZARD, "android.permission.NETWORK_STACK"}) public void setAirplaneMode(boolean);
+    method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void startCaptivePortalApp(android.os.Bundle);
     method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback);
     method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void startTethering(int, boolean, android.net.ConnectivityManager.OnStartTetheringCallback, android.os.Handler);
     method @RequiresPermission(android.Manifest.permission.TETHER_PRIVILEGED) public void stopTethering(int);
@@ -4999,10 +5008,11 @@
     method public boolean getEnableAdjustBrightness();
     method public boolean getEnableDataSaver();
     method public boolean getEnableFirewall();
+    method public boolean getEnableNightMode();
     method public boolean getEnableQuickDoze();
     method public boolean getForceAllAppsStandby();
     method public boolean getForceBackgroundCheck();
-    method public int getGpsMode();
+    method public int getLocationMode();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.os.BatterySaverPolicyConfig> CREATOR;
   }
@@ -5024,10 +5034,11 @@
     method @NonNull public android.os.BatterySaverPolicyConfig.Builder setEnableAdjustBrightness(boolean);
     method @NonNull public android.os.BatterySaverPolicyConfig.Builder setEnableDataSaver(boolean);
     method @NonNull public android.os.BatterySaverPolicyConfig.Builder setEnableFirewall(boolean);
+    method @NonNull public android.os.BatterySaverPolicyConfig.Builder setEnableNightMode(boolean);
     method @NonNull public android.os.BatterySaverPolicyConfig.Builder setEnableQuickDoze(boolean);
     method @NonNull public android.os.BatterySaverPolicyConfig.Builder setForceAllAppsStandby(boolean);
     method @NonNull public android.os.BatterySaverPolicyConfig.Builder setForceBackgroundCheck(boolean);
-    method @NonNull public android.os.BatterySaverPolicyConfig.Builder setGpsMode(int);
+    method @NonNull public android.os.BatterySaverPolicyConfig.Builder setLocationMode(int);
   }
 
   public class Binder implements android.os.IBinder {
@@ -5733,10 +5744,6 @@
     field public static final String SERVICE_ENABLED = "service_enabled";
   }
 
-  public static interface DeviceConfig.ContentCapture {
-    field public static final String NAMESPACE = "content_capture";
-  }
-
   public static interface DeviceConfig.DexBoot {
     field public static final String NAMESPACE = "dex_boot";
     field public static final String PRIV_APPS_OOB_ENABLED = "priv_apps_oob_enabled";
@@ -5771,11 +5778,6 @@
     field public static final String PROPERTY_PERMISSIONS_HUB_ENABLED = "permissions_hub_enabled";
   }
 
-  public static interface DeviceConfig.Runtime {
-    field public static final String NAMESPACE = "runtime";
-    field public static final String USE_PRECOMPILED_LAYOUT = "view.precompiled_layout_enabled";
-  }
-
   public static interface DeviceConfig.RuntimeNative {
     field public static final String NAMESPACE = "runtime_native";
   }
@@ -6035,11 +6037,11 @@
 
   public abstract class RoleControllerService extends android.app.Service {
     ctor public RoleControllerService();
-    method public abstract void onAddRoleHolder(@NonNull String, @NonNull String, @NonNull android.app.role.RoleManagerCallback);
+    method public abstract void onAddRoleHolder(@NonNull String, @NonNull String, int, @NonNull android.app.role.RoleManagerCallback);
     method @Nullable public final android.os.IBinder onBind(@Nullable android.content.Intent);
-    method public abstract void onClearRoleHolders(@NonNull String, @NonNull android.app.role.RoleManagerCallback);
+    method public abstract void onClearRoleHolders(@NonNull String, int, @NonNull android.app.role.RoleManagerCallback);
     method public abstract void onGrantDefaultRoles(@NonNull android.app.role.RoleManagerCallback);
-    method public abstract void onRemoveRoleHolder(@NonNull String, @NonNull String, @NonNull android.app.role.RoleManagerCallback);
+    method public abstract void onRemoveRoleHolder(@NonNull String, @NonNull String, int, @NonNull android.app.role.RoleManagerCallback);
     method public abstract void onSmsKillSwitchToggled(boolean);
     field public static final String SERVICE_INTERFACE = "android.rolecontrollerservice.RoleControllerService";
   }
diff --git a/api/test-current.txt b/api/test-current.txt
index 49c4e68..b2ead4a 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -17,8 +17,9 @@
     field public static final String WRITE_OBB = "android.permission.WRITE_OBB";
   }
 
-  public static final class R.array {
-    field public static final int config_defaultRoleHolders = 17235974; // 0x1070006
+  public static final class R.string {
+    field public static final int config_defaultAssistant = 17039393; // 0x1040021
+    field public static final int config_defaultDialer = 17039395; // 0x1040023
   }
 
 }
@@ -429,11 +430,11 @@
 package android.app.role {
 
   public final class RoleManager {
-    method @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public void addRoleHolderAsUser(@NonNull String, @NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull android.app.role.RoleManagerCallback);
-    method @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public void clearRoleHoldersAsUser(@NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull android.app.role.RoleManagerCallback);
+    method @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public void addRoleHolderAsUser(@NonNull String, @NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull android.app.role.RoleManagerCallback);
+    method @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public void clearRoleHoldersAsUser(@NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull android.app.role.RoleManagerCallback);
     method @NonNull @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public java.util.List<java.lang.String> getRoleHolders(@NonNull String);
     method @NonNull @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public java.util.List<java.lang.String> getRoleHoldersAsUser(@NonNull String, @NonNull android.os.UserHandle);
-    method @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public void removeRoleHolderAsUser(@NonNull String, @NonNull String, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull android.app.role.RoleManagerCallback);
+    method @RequiresPermission("android.permission.MANAGE_ROLE_HOLDERS") public void removeRoleHolderAsUser(@NonNull String, @NonNull String, int, @NonNull android.os.UserHandle, @NonNull java.util.concurrent.Executor, @NonNull android.app.role.RoleManagerCallback);
     field public static final String ROLE_ASSISTANT = "android.app.role.ASSISTANT";
   }
 
@@ -767,6 +768,7 @@
     method public void setCodeType(int);
     method public void setConstellationType(int);
     method public void setMultipathIndicator(int);
+    method public void setOtherCodeTypeName(@NonNull String);
     method public void setPseudorangeRateMetersPerSecond(double);
     method public void setPseudorangeRateUncertaintyMetersPerSecond(double);
     method public void setReceivedSvTimeNanos(long);
@@ -934,6 +936,7 @@
   }
 
   public class ConnectivityManager {
+    method @RequiresPermission(android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK) public void startCaptivePortalApp(android.os.Bundle);
     field public static final String EXTRA_CAPTIVE_PORTAL_PROBE_SPEC = "android.net.extra.CAPTIVE_PORTAL_PROBE_SPEC";
     field public static final String EXTRA_CAPTIVE_PORTAL_USER_AGENT = "android.net.extra.CAPTIVE_PORTAL_USER_AGENT";
   }
@@ -1782,8 +1785,10 @@
   }
 
   public final class DeviceConfig {
+    method @RequiresPermission("android.permission.READ_DEVICE_CONFIG") public static String getProperty(String, String);
     method @RequiresPermission("android.permission.WRITE_DEVICE_CONFIG") public static void resetToDefaults(int, @Nullable String);
     method @RequiresPermission("android.permission.WRITE_DEVICE_CONFIG") public static boolean setProperty(String, String, String, boolean);
+    field public static final String NAMESPACE_CONTENT_CAPTURE = "content_capture";
   }
 
   public static interface DeviceConfig.Privacy {
@@ -1851,6 +1856,8 @@
     field @Deprecated public static final String ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES = "enabled_notification_policy_access_packages";
     field public static final String LOCATION_ACCESS_CHECK_DELAY_MILLIS = "location_access_check_delay_millis";
     field public static final String LOCATION_ACCESS_CHECK_INTERVAL_MILLIS = "location_access_check_interval_millis";
+    field public static final String NOTIFICATION_BADGING = "notification_badging";
+    field public static final String NOTIFICATION_BUBBLES = "notification_bubbles";
     field @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public static final String SYNC_PARENT_SOUNDS = "sync_parent_sounds";
     field public static final String USER_SETUP_COMPLETE = "user_setup_complete";
     field public static final String VOICE_INTERACTION_SERVICE = "voice_interaction_service";
@@ -2149,6 +2156,10 @@
     ctor public CallAudioState(boolean, int, int, @Nullable android.bluetooth.BluetoothDevice, @NonNull java.util.Collection<android.bluetooth.BluetoothDevice>);
   }
 
+  public abstract class Conference extends android.telecom.Conferenceable {
+    method public android.telecom.Connection getPrimaryConnection();
+  }
+
   public final class PhoneAccountSuggestion implements android.os.Parcelable {
     ctor public PhoneAccountSuggestion(android.telecom.PhoneAccountHandle, int, boolean);
   }
@@ -2161,6 +2172,16 @@
     field public static final String SERVICE_INTERFACE = "android.telecom.PhoneAccountSuggestionService";
   }
 
+  public class TelecomManager {
+    method @RequiresPermission("android.permission.READ_PRIVILEGED_PHONE_STATE") public int getCurrentTtyMode();
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public boolean isInEmergencyCall();
+    method @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE) public void setUserSelectedOutgoingPhoneAccount(android.telecom.PhoneAccountHandle);
+    field public static final int TTY_MODE_FULL = 1; // 0x1
+    field public static final int TTY_MODE_HCO = 2; // 0x2
+    field public static final int TTY_MODE_OFF = 0; // 0x0
+    field public static final int TTY_MODE_VCO = 3; // 0x3
+  }
+
 }
 
 package android.telephony {
@@ -2577,6 +2598,10 @@
     method public void setDisplayId(int);
   }
 
+  @java.lang.annotation.Retention(java.lang.annotation.RetentionPolicy.RUNTIME) @java.lang.annotation.Target({java.lang.annotation.ElementType.METHOD}) public @interface RemotableViewMethod {
+    method public abstract String asyncImpl() default "";
+  }
+
   @UiThread public class View implements android.view.accessibility.AccessibilityEventSource android.graphics.drawable.Drawable.Callback android.view.KeyEvent.Callback {
     method public android.view.View getTooltipView();
     method public static boolean isDefaultFocusHighlightEnabled();
@@ -2663,6 +2688,8 @@
   public final class AutofillId implements android.os.Parcelable {
     ctor public AutofillId(int);
     ctor public AutofillId(@NonNull android.view.autofill.AutofillId, int);
+    ctor public AutofillId(int, int);
+    ctor public AutofillId(@NonNull android.view.autofill.AutofillId, long, int);
   }
 
   public final class AutofillManager {
@@ -2708,10 +2735,71 @@
   public final class ContentCaptureManager {
     method public boolean isContentCaptureFeatureEnabled();
     method public void setContentCaptureFeatureEnabled(boolean);
+    field public static final String DEVICE_CONFIG_PROPERTY_SERVICE_EXPLICITLY_ENABLED = "service_explicitly_enabled";
   }
 
   public final class ViewNode extends android.app.assist.AssistStructure.ViewNode {
     method @Nullable public android.view.autofill.AutofillId getParentAutofillId();
+    method @Nullable public static android.view.contentcapture.ViewNode readFromParcel(@NonNull android.os.Parcel);
+    method public static void writeToParcel(@NonNull android.os.Parcel, @Nullable android.view.contentcapture.ViewNode, int);
+  }
+
+  public static final class ViewNode.ViewStructureImpl extends android.view.ViewStructure {
+    ctor public ViewNode.ViewStructureImpl(@NonNull android.view.View);
+    ctor public ViewNode.ViewStructureImpl(@NonNull android.view.autofill.AutofillId, long, int);
+    method public int addChildCount(int);
+    method public void asyncCommit();
+    method public android.view.ViewStructure asyncNewChild(int);
+    method public android.view.autofill.AutofillId getAutofillId();
+    method public int getChildCount();
+    method public android.os.Bundle getExtras();
+    method public CharSequence getHint();
+    method public android.view.contentcapture.ViewNode getNode();
+    method public android.graphics.Rect getTempRect();
+    method public CharSequence getText();
+    method public int getTextSelectionEnd();
+    method public int getTextSelectionStart();
+    method public boolean hasExtras();
+    method public android.view.ViewStructure newChild(int);
+    method public android.view.ViewStructure.HtmlInfo.Builder newHtmlInfoBuilder(String);
+    method public void setAccessibilityFocused(boolean);
+    method public void setActivated(boolean);
+    method public void setAlpha(float);
+    method public void setAssistBlocked(boolean);
+    method public void setAutofillHints(String[]);
+    method public void setAutofillId(android.view.autofill.AutofillId);
+    method public void setAutofillId(android.view.autofill.AutofillId, int);
+    method public void setAutofillOptions(CharSequence[]);
+    method public void setAutofillType(int);
+    method public void setAutofillValue(android.view.autofill.AutofillValue);
+    method public void setCheckable(boolean);
+    method public void setChecked(boolean);
+    method public void setChildCount(int);
+    method public void setClassName(String);
+    method public void setClickable(boolean);
+    method public void setContentDescription(CharSequence);
+    method public void setContextClickable(boolean);
+    method public void setDataIsSensitive(boolean);
+    method public void setDimens(int, int, int, int, int, int);
+    method public void setElevation(float);
+    method public void setEnabled(boolean);
+    method public void setFocusable(boolean);
+    method public void setFocused(boolean);
+    method public void setHint(CharSequence);
+    method public void setHtmlInfo(android.view.ViewStructure.HtmlInfo);
+    method public void setId(int, String, String, String);
+    method public void setInputType(int);
+    method public void setLocaleList(android.os.LocaleList);
+    method public void setLongClickable(boolean);
+    method public void setOpaque(boolean);
+    method public void setSelected(boolean);
+    method public void setText(CharSequence);
+    method public void setText(CharSequence, int, int);
+    method public void setTextLines(int[], int[]);
+    method public void setTextStyle(float, int, int, int);
+    method public void setTransformation(android.graphics.Matrix);
+    method public void setVisibility(int);
+    method public void setWebDomain(String);
   }
 
 }
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 5dcb392b..46917e4 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -252,10 +252,12 @@
 status_t BootAnimation::readyToRun() {
     mAssets.addDefaultAssets();
 
-    sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(
-            ISurfaceComposer::eDisplayIdMain));
+    mDisplayToken = SurfaceComposerClient::getInternalDisplayToken();
+    if (mDisplayToken == nullptr)
+        return -1;
+
     DisplayInfo dinfo;
-    status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &dinfo);
+    status_t status = SurfaceComposerClient::getDisplayInfo(mDisplayToken, &dinfo);
     if (status)
         return -1;
 
@@ -1014,16 +1016,13 @@
         // At the end of the animation, we switch to the viewport that DisplayManager will apply
         // later. This changes the coordinate system, and means we must move the surface up by
         // the inset amount.
-        sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(
-                ISurfaceComposer::eDisplayIdMain));
-
         Rect layerStackRect(0, 0, mWidth, mHeight - mTargetInset);
         Rect displayRect(0, mTargetInset, mWidth, mHeight);
 
         SurfaceComposerClient::Transaction t;
         t.setPosition(mFlingerSurfaceControl, 0, -mTargetInset)
                 .setCrop(mFlingerSurfaceControl, Rect(0, mTargetInset, mWidth, mHeight));
-        t.setDisplayProjection(dtoken, 0 /* orientation */, layerStackRect, displayRect);
+        t.setDisplayProjection(mDisplayToken, 0 /* orientation */, layerStackRect, displayRect);
         t.apply();
 
         mTargetInset = mCurrentInset = 0;
diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h
index 04d4f9a..19616cb 100644
--- a/cmds/bootanimation/BootAnimation.h
+++ b/cmds/bootanimation/BootAnimation.h
@@ -171,6 +171,7 @@
     EGLDisplay  mDisplay;
     EGLDisplay  mContext;
     EGLDisplay  mSurface;
+    sp<IBinder> mDisplayToken;
     sp<SurfaceControl> mFlingerSurfaceControl;
     sp<Surface> mFlingerSurface;
     bool        mClockEnabled;
diff --git a/cmds/idmap2/Android.bp b/cmds/idmap2/Android.bp
index 056add5..d757e46 100644
--- a/cmds/idmap2/Android.bp
+++ b/cmds/idmap2/Android.bp
@@ -43,6 +43,7 @@
         "libidmap2/PrettyPrintVisitor.cpp",
         "libidmap2/RawPrintVisitor.cpp",
         "libidmap2/ResourceUtils.cpp",
+        "libidmap2/Result.cpp",
         "libidmap2/Xml.cpp",
         "libidmap2/ZipFile.cpp",
     ],
@@ -55,6 +56,7 @@
             shared_libs: [
                 "libandroidfw",
                 "libbase",
+                "libcutils",
                 "libutils",
                 "libziparchive",
             ],
@@ -93,6 +95,7 @@
         "tests/PrettyPrintVisitorTests.cpp",
         "tests/RawPrintVisitorTests.cpp",
         "tests/ResourceUtilsTests.cpp",
+        "tests/ResultTests.cpp",
         "tests/XmlTests.cpp",
         "tests/ZipFileTests.cpp",
     ],
@@ -148,6 +151,7 @@
             shared_libs: [
                 "libandroidfw",
                 "libbase",
+                "libcutils",
                 "libidmap2",
                 "libutils",
                 "libziparchive",
diff --git a/cmds/idmap2/idmap2/Create.cpp b/cmds/idmap2/idmap2/Create.cpp
index 0c581f3..6703909 100644
--- a/cmds/idmap2/idmap2/Create.cpp
+++ b/cmds/idmap2/idmap2/Create.cpp
@@ -29,6 +29,7 @@
 #include "idmap2/Idmap.h"
 #include "idmap2/Policies.h"
 #include "idmap2/Result.h"
+#include "idmap2/SysTrace.h"
 
 using android::ApkAssets;
 using android::idmap2::BinaryStreamVisitor;
@@ -42,6 +43,7 @@
 using android::idmap2::utils::UidHasWriteAccessToPath;
 
 bool Create(const std::vector<std::string>& args, std::ostream& out_error) {
+  SYSTRACE << "Create " << args;
   std::string target_apk_path;
   std::string overlay_apk_path;
   std::string idmap_path;
diff --git a/cmds/idmap2/idmap2/Dump.cpp b/cmds/idmap2/idmap2/Dump.cpp
index c8cdcfa..3947703 100644
--- a/cmds/idmap2/idmap2/Dump.cpp
+++ b/cmds/idmap2/idmap2/Dump.cpp
@@ -24,6 +24,7 @@
 #include "idmap2/Idmap.h"
 #include "idmap2/PrettyPrintVisitor.h"
 #include "idmap2/RawPrintVisitor.h"
+#include "idmap2/SysTrace.h"
 
 using android::idmap2::CommandLineOptions;
 using android::idmap2::Idmap;
@@ -31,6 +32,7 @@
 using android::idmap2::RawPrintVisitor;
 
 bool Dump(const std::vector<std::string>& args, std::ostream& out_error) {
+  SYSTRACE << "Dump " << args;
   std::string idmap_path;
   bool verbose;
 
diff --git a/cmds/idmap2/idmap2/Lookup.cpp b/cmds/idmap2/idmap2/Lookup.cpp
index cfb5dd5..553d8ca 100644
--- a/cmds/idmap2/idmap2/Lookup.cpp
+++ b/cmds/idmap2/idmap2/Lookup.cpp
@@ -37,6 +37,7 @@
 #include "idmap2/CommandLineOptions.h"
 #include "idmap2/Idmap.h"
 #include "idmap2/Result.h"
+#include "idmap2/SysTrace.h"
 #include "idmap2/Xml.h"
 #include "idmap2/ZipFile.h"
 
@@ -156,6 +157,7 @@
 }  // namespace
 
 bool Lookup(const std::vector<std::string>& args, std::ostream& out_error) {
+  SYSTRACE << "Lookup " << args;
   std::vector<std::string> idmap_paths;
   std::string config_str;
   std::string resid_str;
diff --git a/cmds/idmap2/idmap2/Main.cpp b/cmds/idmap2/idmap2/Main.cpp
index 445fac5..a0ffccb 100644
--- a/cmds/idmap2/idmap2/Main.cpp
+++ b/cmds/idmap2/idmap2/Main.cpp
@@ -24,6 +24,7 @@
 #include <vector>
 
 #include "idmap2/CommandLineOptions.h"
+#include "idmap2/SysTrace.h"
 
 #include "Commands.h"
 
@@ -48,6 +49,7 @@
 }  // namespace
 
 int main(int argc, char** argv) {
+  SYSTRACE << "main";
   const NameToFunctionMap commands = {
       {"create", Create}, {"dump", Dump}, {"lookup", Lookup}, {"scan", Scan}, {"verify", Verify},
   };
diff --git a/cmds/idmap2/idmap2/Scan.cpp b/cmds/idmap2/idmap2/Scan.cpp
index b1ed42a..873779f 100644
--- a/cmds/idmap2/idmap2/Scan.cpp
+++ b/cmds/idmap2/idmap2/Scan.cpp
@@ -30,6 +30,7 @@
 #include "idmap2/FileUtils.h"
 #include "idmap2/Idmap.h"
 #include "idmap2/ResourceUtils.h"
+#include "idmap2/SysTrace.h"
 #include "idmap2/Xml.h"
 #include "idmap2/ZipFile.h"
 
@@ -67,6 +68,7 @@
 
 std::unique_ptr<std::vector<std::string>> FindApkFiles(const std::vector<std::string>& dirs,
                                                        bool recursive, std::ostream& out_error) {
+  SYSTRACE << "FindApkFiles " << dirs << " " << recursive;
   const auto predicate = [](unsigned char type, const std::string& path) -> bool {
     static constexpr size_t kExtLen = 4;  // strlen(".apk")
     return type == DT_REG && path.size() > kExtLen &&
@@ -104,6 +106,7 @@
 }  // namespace
 
 bool Scan(const std::vector<std::string>& args, std::ostream& out_error) {
+  SYSTRACE << "Scan " << args;
   std::vector<std::string> input_directories;
   std::string target_package_name;
   std::string target_apk_path;
diff --git a/cmds/idmap2/idmap2/Verify.cpp b/cmds/idmap2/idmap2/Verify.cpp
index 4d4a0e7..d8fe7aa 100644
--- a/cmds/idmap2/idmap2/Verify.cpp
+++ b/cmds/idmap2/idmap2/Verify.cpp
@@ -21,11 +21,13 @@
 
 #include "idmap2/CommandLineOptions.h"
 #include "idmap2/Idmap.h"
+#include "idmap2/SysTrace.h"
 
 using android::idmap2::CommandLineOptions;
 using android::idmap2::IdmapHeader;
 
 bool Verify(const std::vector<std::string>& args, std::ostream& out_error) {
+  SYSTRACE << "Verify " << args;
   std::string idmap_path;
 
   const CommandLineOptions opts =
diff --git a/cmds/idmap2/idmap2d/Idmap2Service.cpp b/cmds/idmap2/idmap2d/Idmap2Service.cpp
index f30ce9b..0e4bd89 100644
--- a/cmds/idmap2/idmap2d/Idmap2Service.cpp
+++ b/cmds/idmap2/idmap2d/Idmap2Service.cpp
@@ -29,13 +29,13 @@
 #include "android-base/stringprintf.h"
 #include "binder/IPCThreadState.h"
 #include "utils/String8.h"
-#include "utils/Trace.h"
 
 #include "idmap2/BinaryStreamVisitor.h"
 #include "idmap2/FileUtils.h"
 #include "idmap2/Idmap.h"
 #include "idmap2/Policies.h"
 #include "idmap2/Result.h"
+#include "idmap2/SysTrace.h"
 
 #include "idmap2d/Idmap2Service.h"
 
@@ -72,6 +72,7 @@
 Status Idmap2Service::getIdmapPath(const std::string& overlay_apk_path,
                                    int32_t user_id ATTRIBUTE_UNUSED, std::string* _aidl_return) {
   assert(_aidl_return);
+  SYSTRACE << "Idmap2Service::getIdmapPath " << overlay_apk_path;
   *_aidl_return = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_apk_path);
   return ok();
 }
@@ -79,6 +80,7 @@
 Status Idmap2Service::removeIdmap(const std::string& overlay_apk_path,
                                   int32_t user_id ATTRIBUTE_UNUSED, bool* _aidl_return) {
   assert(_aidl_return);
+  SYSTRACE << "Idmap2Service::removeIdmap " << overlay_apk_path;
   const uid_t uid = IPCThreadState::self()->getCallingUid();
   const std::string idmap_path = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_apk_path);
   if (!UidHasWriteAccessToPath(uid, idmap_path)) {
@@ -98,6 +100,7 @@
                                   int32_t fulfilled_policies ATTRIBUTE_UNUSED,
                                   bool enforce_overlayable ATTRIBUTE_UNUSED,
                                   int32_t user_id ATTRIBUTE_UNUSED, bool* _aidl_return) {
+  SYSTRACE << "Idmap2Service::verifyIdmap " << overlay_apk_path;
   assert(_aidl_return);
   const std::string idmap_path = Idmap::CanonicalIdmapPathFor(kIdmapCacheDir, overlay_apk_path);
   std::ifstream fin(idmap_path);
@@ -113,15 +116,10 @@
 
 Status Idmap2Service::createIdmap(const std::string& target_apk_path,
                                   const std::string& overlay_apk_path, int32_t fulfilled_policies,
-                                  bool enforce_overlayable, int32_t user_id,
+                                  bool enforce_overlayable, int32_t user_id ATTRIBUTE_UNUSED,
                                   std::unique_ptr<std::string>* _aidl_return) {
   assert(_aidl_return);
-  std::stringstream trace;
-  trace << __FUNCTION__ << " " << target_apk_path << " " << overlay_apk_path << " "
-        << std::to_string(user_id);
-  ATRACE_NAME(trace.str().c_str());
-  std::cout << trace.str() << std::endl;
-
+  SYSTRACE << "Idmap2Service::createIdmap " << target_apk_path << " " << overlay_apk_path;
   _aidl_return->reset(nullptr);
 
   const PolicyBitmask policy_bitmask = ConvertAidlArgToPolicyBitmask(fulfilled_policies);
diff --git a/cmds/idmap2/include/idmap2/Result.h b/cmds/idmap2/include/idmap2/Result.h
index 6189ea3..d88dd51 100644
--- a/cmds/idmap2/include/idmap2/Result.h
+++ b/cmds/idmap2/include/idmap2/Result.h
@@ -18,6 +18,11 @@
 #define IDMAP2_INCLUDE_IDMAP2_RESULT_H_
 
 #include <optional>
+#include <string>
+#include <utility>
+#include <variant>
+
+#include "android-base/logging.h"  // CHECK
 
 namespace android::idmap2 {
 
@@ -26,6 +31,125 @@
 
 static constexpr std::nullopt_t kResultError = std::nullopt;
 
+namespace v2 {
+
+using Unit = std::monostate;
+
+class Error {
+ public:
+  explicit Error(const Error& parent) = default;
+
+  // NOLINTNEXTLINE(cert-dcl50-cpp)
+  explicit Error(const char* fmt, ...) __attribute__((__format__(printf, 2, 3)));
+
+  // NOLINTNEXTLINE(cert-dcl50-cpp)
+  explicit Error(const Error& parent, const char* fmt, ...)
+      __attribute__((__format__(printf, 3, 4)));
+
+  inline std::string GetMessage() const {
+    return msg_;
+  }
+
+ private:
+  std::string msg_;
+};
+
+template <typename T>
+class Result {
+ public:
+  Result(const T& value);      // NOLINT(runtime/explicit)
+  Result(T&& value) noexcept;  // NOLINT(runtime/explicit)
+
+  Result(const Error& error);      // NOLINT(runtime/explicit)
+  Result(Error&& error) noexcept;  // NOLINT(runtime/explicit)
+
+  Result(const Result& error) = default;
+
+  Result& operator=(const Result& rhs) = default;
+  Result& operator=(Result&& rhs) noexcept = default;
+
+  explicit operator bool() const;
+
+  constexpr const T& operator*() const&;
+  T& operator*() &;
+
+  constexpr const T* operator->() const&;
+  T* operator->() &;
+
+  std::string GetErrorMessage() const;
+  Error GetError() const;
+
+ private:
+  bool is_ok() const;
+
+  std::variant<T, Error> data_;
+};
+
+template <typename T>
+Result<T>::Result(const T& value) : data_(std::in_place_type<T>, value) {
+}
+
+template <typename T>
+Result<T>::Result(T&& value) noexcept : data_(std::in_place_type<T>, std::forward<T>(value)) {
+}
+
+template <typename T>
+Result<T>::Result(const Error& error) : data_(std::in_place_type<Error>, error) {
+}
+
+template <typename T>
+Result<T>::Result(Error&& error) noexcept
+    : data_(std::in_place_type<Error>, std::forward<Error>(error)) {
+}
+
+template <typename T>
+Result<T>::operator bool() const {
+  return is_ok();
+}
+
+template <typename T>
+constexpr const T& Result<T>::operator*() const& {
+  CHECK(is_ok()) << "Result<T>::operator* called in ERROR state";
+  return std::get<T>(data_);
+}
+
+template <typename T>
+T& Result<T>::operator*() & {
+  CHECK(is_ok()) << "Result<T>::operator* called in ERROR state";
+  return std::get<T>(data_);
+}
+
+template <typename T>
+constexpr const T* Result<T>::operator->() const& {
+  CHECK(is_ok()) << "Result<T>::operator-> called in ERROR state";
+  return &std::get<T>(data_);
+}
+
+template <typename T>
+T* Result<T>::operator->() & {
+  CHECK(is_ok()) << "Result<T>::operator-> called in ERROR state";
+  return &std::get<T>(data_);
+}
+
+template <typename T>
+inline std::string Result<T>::GetErrorMessage() const {
+  CHECK(!is_ok()) << "Result<T>::GetErrorMessage called in OK state";
+  return std::get<Error>(data_).GetMessage();
+}
+
+template <typename T>
+inline Error Result<T>::GetError() const {
+  CHECK(!is_ok()) << "Result<T>::GetError called in OK state";
+  return Error(std::get<Error>(data_));
+}
+
+template <typename T>
+inline bool Result<T>::is_ok() const {
+  return std::holds_alternative<T>(data_);
+}
+
+}  // namespace v2
+
 }  // namespace android::idmap2
 
 #endif  // IDMAP2_INCLUDE_IDMAP2_RESULT_H_
diff --git a/cmds/idmap2/include/idmap2/SysTrace.h b/cmds/idmap2/include/idmap2/SysTrace.h
new file mode 100644
index 0000000..19b4353
--- /dev/null
+++ b/cmds/idmap2/include/idmap2/SysTrace.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#ifndef IDMAP2_INCLUDE_IDMAP2_SYSTRACE_H_
+#define IDMAP2_INCLUDE_IDMAP2_SYSTRACE_H_
+
+#define ATRACE_TAG ATRACE_TAG_RRO
+
+#include <sstream>
+#include <vector>
+
+#include "cutils/trace.h"
+
+namespace android::idmap2::utils {
+#ifdef __ANDROID__
+
+class ScopedTraceNoStart {
+ public:
+  ~ScopedTraceNoStart() {
+    ATRACE_END();
+  }
+};
+
+class ScopedTraceMessageHelper {
+ public:
+  ~ScopedTraceMessageHelper() {
+    ATRACE_BEGIN(buffer_.str().c_str());
+  }
+
+  std::ostream& stream() {
+    return buffer_;
+  }
+
+ private:
+  std::ostringstream buffer_;
+};
+
+#define SYSTRACE                                               \
+  android::idmap2::utils::ScopedTraceNoStart _trace##__LINE__; \
+  (ATRACE_ENABLED()) && android::idmap2::utils::ScopedTraceMessageHelper().stream()
+
+#else
+
+class DummyStream {
+ public:
+  std::ostream& stream() {
+    return buffer_;
+  }
+
+ private:
+  std::ostringstream buffer_;
+};
+
+#define SYSTRACE android::idmap2::utils::DummyStream().stream()
+
+#endif
+}  // namespace android::idmap2::utils
+
+template <typename T>
+std::ostream& operator<<(std::ostream& stream, const std::vector<T>& vector) {
+  bool first = true;
+  stream << "[";
+  for (const auto& item : vector) {
+    if (!first) {
+      stream << ", ";
+    }
+    stream << item;
+    first = false;
+  }
+  stream << "]";
+  return stream;
+}
+
+#endif  // IDMAP2_INCLUDE_IDMAP2_SYSTRACE_H_
diff --git a/cmds/idmap2/libidmap2/Idmap.cpp b/cmds/idmap2/libidmap2/Idmap.cpp
index fa5ac8e..99b5f0f 100644
--- a/cmds/idmap2/libidmap2/Idmap.cpp
+++ b/cmds/idmap2/libidmap2/Idmap.cpp
@@ -34,6 +34,7 @@
 #include "idmap2/Idmap.h"
 #include "idmap2/ResourceUtils.h"
 #include "idmap2/Result.h"
+#include "idmap2/SysTrace.h"
 #include "idmap2/ZipFile.h"
 
 namespace android::idmap2 {
@@ -117,6 +118,12 @@
   return loaded_arsc.GetPackageById(id);
 }
 
+Result<uint32_t> GetCrc(const ZipFile& zip) {
+  const Result<uint32_t> a = zip.Crc("resources.arsc");
+  const Result<uint32_t> b = zip.Crc("AndroidManifest.xml");
+  return a && b ? Result<uint32_t>(*a ^ *b) : kResultError;
+}
+
 }  // namespace
 
 std::unique_ptr<const IdmapHeader> IdmapHeader::FromBinaryStream(std::istream& stream) {
@@ -153,7 +160,7 @@
     return false;
   }
 
-  Result<uint32_t> target_crc = target_zip->Crc("resources.arsc");
+  Result<uint32_t> target_crc = GetCrc(*target_zip);
   if (!target_crc) {
     out_error << "error: failed to get target crc" << std::endl;
     return false;
@@ -173,7 +180,7 @@
     return false;
   }
 
-  Result<uint32_t> overlay_crc = overlay_zip->Crc("resources.arsc");
+  Result<uint32_t> overlay_crc = GetCrc(*overlay_zip);
   if (!overlay_crc) {
     out_error << "error: failed to get overlay crc" << std::endl;
     return false;
@@ -252,6 +259,7 @@
 
 std::unique_ptr<const Idmap> Idmap::FromBinaryStream(std::istream& stream,
                                                      std::ostream& out_error) {
+  SYSTRACE << "Idmap::FromBinaryStream";
   std::unique_ptr<Idmap> idmap(new Idmap());
 
   idmap->header_ = IdmapHeader::FromBinaryStream(stream);
@@ -298,6 +306,7 @@
     const std::string& target_apk_path, const ApkAssets& target_apk_assets,
     const std::string& overlay_apk_path, const ApkAssets& overlay_apk_assets,
     const PolicyBitmask& fulfilled_policies, bool enforce_overlayable, std::ostream& out_error) {
+  SYSTRACE << "Idmap::FromApkAssets";
   AssetManager2 target_asset_manager;
   if (!target_asset_manager.SetApkAssets({&target_apk_assets}, true, false)) {
     out_error << "error: failed to create target asset manager" << std::endl;
@@ -356,14 +365,14 @@
   header->magic_ = kIdmapMagic;
   header->version_ = kIdmapCurrentVersion;
 
-  Result<uint32_t> crc = target_zip->Crc("resources.arsc");
+  Result<uint32_t> crc = GetCrc(*target_zip);
   if (!crc) {
     out_error << "error: failed to get zip crc for target" << std::endl;
     return nullptr;
   }
   header->target_crc_ = *crc;
 
-  crc = overlay_zip->Crc("resources.arsc");
+  crc = GetCrc(*overlay_zip);
   if (!crc) {
     out_error << "error: failed to get zip crc for overlay" << std::endl;
     return nullptr;
diff --git a/cmds/idmap2/libidmap2/Result.cpp b/cmds/idmap2/libidmap2/Result.cpp
new file mode 100644
index 0000000..a5c9999
--- /dev/null
+++ b/cmds/idmap2/libidmap2/Result.cpp
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+#include <cstdarg>
+
+#include "android-base/stringprintf.h"
+
+#include "idmap2/Result.h"
+
+namespace android::idmap2 {
+
+v2::Error::Error(const char* fmt, ...) {
+  va_list ap;
+  va_start(ap, fmt);
+  base::StringAppendV(&msg_, fmt, ap);
+  va_end(ap);
+}
+
+v2::Error::Error(const Error& parent, const char* fmt, ...) : msg_(parent.msg_) {
+  msg_.append(" -> ");
+
+  va_list ap;
+  va_start(ap, fmt);
+  base::StringAppendV(&msg_, fmt, ap);
+  va_end(ap);
+}
+
+}  // namespace android::idmap2
diff --git a/cmds/idmap2/static-checks.sh b/cmds/idmap2/static-checks.sh
index ad9830b..41d3c69 100755
--- a/cmds/idmap2/static-checks.sh
+++ b/cmds/idmap2/static-checks.sh
@@ -59,7 +59,7 @@
 
 function _bpfmt()
 {
-    local output="$(bpfmt -s -d $bp_files)"
+    local output="$(bpfmt -d $bp_files)"
     if [[ "$output" ]]; then
         echo "$output"
         return 1
@@ -72,7 +72,9 @@
     local cpplint="${ANDROID_BUILD_TOP}/tools/repohooks/tools/cpplint.py"
     local output="$($cpplint --quiet $cpp_files 2>&1 >/dev/null | grep -v \
         -e 'Found C system header after C++ system header.' \
+        -e 'Unknown NOLINT error category: cert-dcl50-cpp' \
         -e 'Unknown NOLINT error category: misc-non-private-member-variables-in-classes' \
+        -e 'Unknown NOLINT error category: performance-unnecessary-copy-initialization' \
     )"
     if [[ "$output" ]]; then
         echo "$output"
@@ -115,7 +117,7 @@
     exit $errors
 elif [[ $opt_mode == "fix" ]]; then
     clang-format -style=file -i $cpp_files
-    bpfmt -s -w $bp_files
+    bpfmt -w $bp_files
     exit 0
 elif [[ $opt_mode == "help" ]]; then
     echo "Run static analysis tools such as clang-format and cpplint on the idmap2"
diff --git a/cmds/idmap2/tests/IdmapTests.cpp b/cmds/idmap2/tests/IdmapTests.cpp
index 9e27ccd..b40521f 100644
--- a/cmds/idmap2/tests/IdmapTests.cpp
+++ b/cmds/idmap2/tests/IdmapTests.cpp
@@ -191,8 +191,8 @@
   ASSERT_THAT(idmap->GetHeader(), NotNull());
   ASSERT_EQ(idmap->GetHeader()->GetMagic(), 0x504d4449U);
   ASSERT_EQ(idmap->GetHeader()->GetVersion(), 0x01U);
-  ASSERT_EQ(idmap->GetHeader()->GetTargetCrc(), 0xab7cf70d);
-  ASSERT_EQ(idmap->GetHeader()->GetOverlayCrc(), 0xd470336b);
+  ASSERT_EQ(idmap->GetHeader()->GetTargetCrc(), 0xdd53ca29);
+  ASSERT_EQ(idmap->GetHeader()->GetOverlayCrc(), 0xa71ccd77);
   ASSERT_EQ(idmap->GetHeader()->GetTargetPath().to_string(), target_apk_path);
   ASSERT_EQ(idmap->GetHeader()->GetOverlayPath(), overlay_apk_path);
   ASSERT_EQ(idmap->GetHeader()->GetOverlayPath(), overlay_apk_path);
diff --git a/cmds/idmap2/tests/RawPrintVisitorTests.cpp b/cmds/idmap2/tests/RawPrintVisitorTests.cpp
index b1ca125..a5588c3 100644
--- a/cmds/idmap2/tests/RawPrintVisitorTests.cpp
+++ b/cmds/idmap2/tests/RawPrintVisitorTests.cpp
@@ -52,8 +52,8 @@
 
   ASSERT_NE(stream.str().find("00000000: 504d4449  magic\n"), std::string::npos);
   ASSERT_NE(stream.str().find("00000004: 00000001  version\n"), std::string::npos);
-  ASSERT_NE(stream.str().find("00000008: ab7cf70d  target crc\n"), std::string::npos);
-  ASSERT_NE(stream.str().find("0000000c: d470336b  overlay crc\n"), std::string::npos);
+  ASSERT_NE(stream.str().find("00000008: dd53ca29  target crc\n"), std::string::npos);
+  ASSERT_NE(stream.str().find("0000000c: a71ccd77  overlay crc\n"), std::string::npos);
   ASSERT_NE(stream.str().find("0000021c: 00000000  0x7f010000 -> 0x7f010000 integer/int1\n"),
             std::string::npos);
 }
diff --git a/cmds/idmap2/tests/ResultTests.cpp b/cmds/idmap2/tests/ResultTests.cpp
new file mode 100644
index 0000000..d82f0c4
--- /dev/null
+++ b/cmds/idmap2/tests/ResultTests.cpp
@@ -0,0 +1,288 @@
+/*
+ * 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.
+ */
+
+#include <memory>
+#include <type_traits>
+#include <utility>
+
+#include "gmock/gmock.h"
+#include "gtest/gtest.h"
+
+#include "idmap2/Result.h"
+
+namespace android::idmap2 {
+
+struct Container {
+  uint32_t value;  // NOLINT(misc-non-private-member-variables-in-classes)
+};
+
+// Tests: Error
+
+TEST(ResultTests, ErrorTraits) {
+  ASSERT_TRUE(std::is_move_constructible<v2::Error>::value);
+  ASSERT_TRUE(std::is_move_assignable<v2::Error>::value);
+  ASSERT_TRUE(std::is_copy_constructible<v2::Error>::value);
+  ASSERT_TRUE(std::is_copy_assignable<v2::Error>::value);
+}
+
+TEST(ResultTests, ErrorCtorFormat) {
+  v2::Error e("%s=0x%08x", "resid", 0x7f010002);
+  ASSERT_EQ(e.GetMessage(), "resid=0x7f010002");
+}
+
+TEST(ResultTests, ErrorPropagateParent) {
+  v2::Error e1("foo");
+  ASSERT_EQ(e1.GetMessage(), "foo");
+
+  v2::Error e2(e1, "bar");
+  ASSERT_EQ(e2.GetMessage(), "foo -> bar");
+
+  v2::Error e3(e2);  // NOLINT(performance-unnecessary-copy-initialization)
+  ASSERT_EQ(e3.GetMessage(), "foo -> bar");
+
+  v2::Error e4(e3, "%02d", 1);
+  ASSERT_EQ(e4.GetMessage(), "foo -> bar -> 01");
+}
+
+// Tests: Result<T> member functions
+
+// Result(const Result&)
+TEST(ResultTests, CopyConstructor) {
+  v2::Result<uint32_t> r1(42U);
+
+  v2::Result<uint32_t> r2(r1);
+  ASSERT_TRUE(r2);
+  ASSERT_EQ(*r2, 42U);
+
+  v2::Result<uint32_t> r3 = r2;
+  ASSERT_TRUE(r3);
+  ASSERT_EQ(*r3, 42U);
+}
+
+// Result(const T&)
+TEST(ResultTests, Constructor) {
+  uint32_t v = 42U;
+  v2::Result<uint32_t> r1(v);
+  ASSERT_TRUE(r1);
+  ASSERT_EQ(*r1, 42U);
+
+  v2::Error e("foo");
+  v2::Result<uint32_t> r2(e);
+  ASSERT_FALSE(r2);
+  ASSERT_EQ(r2.GetErrorMessage(), "foo");
+}
+
+// Result(const T&&)
+TEST(ResultTests, MoveConstructor) {
+  v2::Result<uint32_t> r1(42U);
+  ASSERT_TRUE(r1);
+  ASSERT_EQ(*r1, 42U);
+
+  v2::Result<uint32_t> r2(v2::Error("foo"));
+  ASSERT_FALSE(r2);
+  ASSERT_EQ(r2.GetErrorMessage(), "foo");
+}
+
+// operator=
+TEST(ResultTests, CopyAssignmentOperator) {
+  // note: 'Result<...> r2 = r1;' calls the copy ctor
+  v2::Result<uint32_t> r1(42U);
+  v2::Result<uint32_t> r2(0U);
+  r2 = r1;
+  ASSERT_TRUE(r2);
+  ASSERT_EQ(*r2, 42U);
+
+  v2::Result<uint32_t> r3(v2::Error("foo"));
+  r2 = r3;
+  ASSERT_FALSE(r2);
+  ASSERT_EQ(r2.GetErrorMessage(), "foo");
+}
+
+TEST(ResultTests, MoveAssignmentOperator) {
+  v2::Result<uint32_t> r(0U);
+  r = v2::Result<uint32_t>(42U);
+  ASSERT_TRUE(r);
+  ASSERT_EQ(*r, 42U);
+
+  r = v2::Result<uint32_t>(v2::Error("foo"));
+  ASSERT_FALSE(r);
+  ASSERT_EQ(r.GetErrorMessage(), "foo");
+}
+
+// operator bool()
+TEST(ResultTests, BoolOperator) {
+  v2::Result<uint32_t> r1(42U);
+  ASSERT_TRUE(r1);
+  ASSERT_EQ(*r1, 42U);
+
+  v2::Result<uint32_t> r2(v2::Error("foo"));
+  ASSERT_FALSE(r2);
+  ASSERT_EQ(r2.GetErrorMessage(), "foo");
+}
+
+// operator*
+TEST(ResultTests, IndirectionOperator) {
+  const v2::Result<uint32_t> r1(42U);
+  ASSERT_TRUE(r1);
+  ASSERT_EQ(*r1, 42U);
+
+  const v2::Result<Container> r2(Container{42U});
+  ASSERT_TRUE(r2);
+  const Container& c = *r2;
+  ASSERT_EQ(c.value, 42U);
+
+  v2::Result<Container> r3(Container{42U});
+  ASSERT_TRUE(r3);
+  ASSERT_EQ((*r3).value, 42U);
+  (*r3).value = 0U;
+  ASSERT_EQ((*r3).value, 0U);
+}
+
+// operator->
+TEST(ResultTests, DereferenceOperator) {
+  const v2::Result<Container> r1(Container{42U});
+  ASSERT_TRUE(r1);
+  ASSERT_EQ(r1->value, 42U);
+
+  v2::Result<Container> r2(Container{42U});
+  ASSERT_TRUE(r2);
+  ASSERT_EQ(r2->value, 42U);
+  r2->value = 0U;
+  ASSERT_EQ(r2->value, 0U);
+}
+
+// Tests: intended use of Result<T>
+
+TEST(ResultTests, ResultTraits) {
+  ASSERT_TRUE(std::is_move_constructible<v2::Result<uint32_t>>::value);
+  ASSERT_TRUE(std::is_move_assignable<v2::Result<uint32_t>>::value);
+  ASSERT_TRUE(std::is_copy_constructible<v2::Result<uint32_t>>::value);
+  ASSERT_TRUE(std::is_copy_assignable<v2::Result<uint32_t>>::value);
+}
+
+TEST(ResultTests, UnitTypeResult) {
+  v2::Result<v2::Unit> r(v2::Unit{});
+  ASSERT_TRUE(r);
+}
+
+struct RefCountData {
+  int ctor;       // NOLINT(misc-non-private-member-variables-in-classes)
+  int copy_ctor;  // NOLINT(misc-non-private-member-variables-in-classes)
+  int dtor;       // NOLINT(misc-non-private-member-variables-in-classes)
+  int move;       // NOLINT(misc-non-private-member-variables-in-classes)
+};
+
+class RefCountContainer {
+ public:
+  explicit RefCountContainer(RefCountData& data) : data_(data) {
+    ++data_.ctor;
+  }
+
+  RefCountContainer(RefCountContainer const&) = delete;
+
+  RefCountContainer(RefCountContainer&& rhs) noexcept : data_(rhs.data_) {
+    ++data_.copy_ctor;
+  }
+
+  RefCountContainer& operator=(RefCountContainer const&) = delete;
+
+  RefCountContainer& operator=(RefCountContainer&& rhs) noexcept {
+    data_ = rhs.data_;
+    ++data_.move;
+    return *this;
+  }
+
+  ~RefCountContainer() {
+    ++data_.dtor;
+  }
+
+ private:
+  RefCountData& data_;
+};
+
+TEST(ResultTests, ReferenceCount) {
+  ASSERT_TRUE(std::is_move_constructible<RefCountContainer>::value);
+  ASSERT_TRUE(std::is_move_assignable<RefCountContainer>::value);
+  ASSERT_FALSE(std::is_copy_constructible<RefCountContainer>::value);
+  ASSERT_FALSE(std::is_copy_assignable<RefCountContainer>::value);
+
+  RefCountData rc{0, 0, 0, 0};
+  { v2::Result<RefCountContainer> r(RefCountContainer{rc}); }
+  ASSERT_EQ(rc.ctor, 1);
+  ASSERT_EQ(rc.copy_ctor, 1);
+  ASSERT_EQ(rc.move, 0);
+  ASSERT_EQ(rc.dtor, 2);
+}
+
+v2::Result<Container> CreateContainer(bool succeed) {
+  if (!succeed) {
+    return v2::Error("foo");
+  }
+  return Container{42U};
+}
+
+TEST(ResultTests, FunctionReturn) {
+  auto r1 = CreateContainer(true);
+  ASSERT_TRUE(r1);
+  ASSERT_EQ(r1->value, 42U);
+
+  auto r2 = CreateContainer(false);
+  ASSERT_FALSE(r2);
+  ASSERT_EQ(r2.GetErrorMessage(), "foo");
+  ASSERT_EQ(r2.GetError().GetMessage(), "foo");
+}
+
+v2::Result<Container> FailToCreateContainer() {
+  auto container = CreateContainer(false);
+  if (!container) {
+    return v2::Error(container.GetError(), "bar");
+  }
+  return container;
+}
+
+TEST(ResultTests, CascadeError) {
+  auto container = FailToCreateContainer();
+  ASSERT_FALSE(container);
+  ASSERT_EQ(container.GetErrorMessage(), "foo -> bar");
+}
+
+struct NoCopyContainer {
+  uint32_t value;  // NOLINT(misc-non-private-member-variables-in-classes)
+  DISALLOW_COPY_AND_ASSIGN(NoCopyContainer);
+};
+
+v2::Result<std::unique_ptr<NoCopyContainer>> CreateNoCopyContainer(bool succeed) {
+  if (!succeed) {
+    return v2::Error("foo");
+  }
+  std::unique_ptr<NoCopyContainer> p(new NoCopyContainer{0U});
+  p->value = 42U;
+  return std::move(p);
+}
+
+TEST(ResultTests, UniquePtr) {
+  auto r1 = CreateNoCopyContainer(true);
+  ASSERT_TRUE(r1);
+  ASSERT_EQ((*r1)->value, 42U);
+  (*r1)->value = 0U;
+  ASSERT_EQ((*r1)->value, 0U);
+
+  auto r2 = CreateNoCopyContainer(false);
+  ASSERT_FALSE(r2);
+  ASSERT_EQ(r2.GetErrorMessage(), "foo");
+}
+
+}  // namespace android::idmap2
diff --git a/cmds/incidentd/Android.bp b/cmds/incidentd/Android.bp
index 40da583..3dc1093 100644
--- a/cmds/incidentd/Android.bp
+++ b/cmds/incidentd/Android.bp
@@ -94,8 +94,10 @@
 
     data: ["testdata/**/*"],
 
-    static_libs: ["libgmock"],
-
+    static_libs: [
+        "libgmock",
+        "libplatformprotos",
+    ],
     shared_libs: [
         "libbase",
         "libbinder",
diff --git a/cmds/incidentd/tests/Reporter_test.cpp b/cmds/incidentd/tests/Reporter_test.cpp
index f54f738..b5e41d7 100644
--- a/cmds/incidentd/tests/Reporter_test.cpp
+++ b/cmds/incidentd/tests/Reporter_test.cpp
@@ -35,6 +35,16 @@
 using ::testing::StrEq;
 using ::testing::Test;
 
+namespace {
+void getHeaderData(const IncidentHeaderProto& headerProto, vector<uint8_t>* out) {
+    out->clear();
+    auto serialized = headerProto.SerializeAsString();
+    if (serialized.empty()) return;
+    out->resize(serialized.length());
+    std::copy(serialized.begin(), serialized.end(), out->begin());
+}
+}
+
 class TestListener : public IIncidentReportStatusListener {
 public:
     int startInvoked;
@@ -143,7 +153,10 @@
     args2.addSection(2);
     IncidentHeaderProto header;
     header.set_alert_id(12);
-    args2.addHeader(header);
+
+    vector<uint8_t> out;
+    getHeaderData(header, &out);
+    args2.addHeader(out);
     sp<ReportRequest> r1 = new ReportRequest(args1, l, tf.fd);
     sp<ReportRequest> r2 = new ReportRequest(args2, l, tf.fd);
 
@@ -169,8 +182,12 @@
     IncidentHeaderProto header1, header2;
     header1.set_alert_id(12);
     header2.set_reason("abcd");
-    args.addHeader(header1);
-    args.addHeader(header2);
+
+    vector<uint8_t> out;
+    getHeaderData(header1, &out);
+    args.addHeader(out);
+    getHeaderData(header2, &out);
+    args.addHeader(out);
     sp<ReportRequest> r = new ReportRequest(args, l, -1);
     reporter->batch.add(r);
 
diff --git a/cmds/incidentd/tests/Section_test.cpp b/cmds/incidentd/tests/Section_test.cpp
index 9b684a0..24454ed 100644
--- a/cmds/incidentd/tests/Section_test.cpp
+++ b/cmds/incidentd/tests/Section_test.cpp
@@ -82,6 +82,16 @@
     virtual IBinder* onAsBinder() override { return nullptr; };
 };
 
+namespace {
+void getHeaderData(const IncidentHeaderProto& headerProto, vector<uint8_t>* out) {
+    out->clear();
+    auto serialized = headerProto.SerializeAsString();
+    if (serialized.empty()) return;
+    out->resize(serialized.length());
+    std::copy(serialized.begin(), serialized.end(), out->begin());
+}
+}
+
 TEST_F(SectionTest, HeaderSection) {
     HeaderSection hs;
 
@@ -94,9 +104,15 @@
     head1.set_reason("axe");
     head2.set_reason("pup");
 
-    args1.addHeader(head1);
-    args1.addHeader(head2);
-    args2.addHeader(head2);
+    vector<uint8_t> out;
+    getHeaderData(head1, &out);
+    args1.addHeader(out);
+
+    getHeaderData(head2, &out);
+    args1.addHeader(out);
+
+    getHeaderData(head2, &out);
+    args2.addHeader(out);
 
     requests.add(new ReportRequest(args1, new SimpleListener(), -1));
     requests.add(new ReportRequest(args2, new SimpleListener(), tf.fd));
diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp
index 3d74f8b..c497667 100644
--- a/cmds/screencap/screencap.cpp
+++ b/cmds/screencap/screencap.cpp
@@ -46,23 +46,22 @@
 
 using namespace android;
 
-static uint32_t DEFAULT_DISPLAY_ID = ISurfaceComposer::eDisplayIdMain;
-
 #define COLORSPACE_UNKNOWN    0
 #define COLORSPACE_SRGB       1
 #define COLORSPACE_DISPLAY_P3 2
 
-static void usage(const char* pname)
+static void usage(const char* pname, PhysicalDisplayId displayId)
 {
     fprintf(stderr,
             "usage: %s [-hp] [-d display-id] [FILENAME]\n"
             "   -h: this message\n"
             "   -p: save the file as a png.\n"
-            "   -d: specify the display id to capture, default %d.\n"
+            "   -d: specify the physical display ID to capture (default: %"
+                    ANDROID_PHYSICAL_DISPLAY_ID_FORMAT ")\n"
+            "       see \"dumpsys SurfaceFlinger --display-id\" for valid display IDs.\n"
             "If FILENAME ends with .png it will be saved as a png.\n"
             "If FILENAME is not given, the results will be printed to stdout.\n",
-            pname, DEFAULT_DISPLAY_ID
-    );
+            pname, displayId);
 }
 
 static SkColorType flinger2skia(PixelFormat f)
@@ -127,9 +126,14 @@
 
 int main(int argc, char** argv)
 {
+    std::optional<PhysicalDisplayId> displayId = SurfaceComposerClient::getInternalDisplayId();
+    if (!displayId) {
+        fprintf(stderr, "Failed to get token for internal display\n");
+        return 1;
+    }
+
     const char* pname = argv[0];
     bool png = false;
-    int32_t displayId = DEFAULT_DISPLAY_ID;
     int c;
     while ((c = getopt(argc, argv, "phd:")) != -1) {
         switch (c) {
@@ -137,11 +141,11 @@
                 png = true;
                 break;
             case 'd':
-                displayId = atoi(optarg);
+                displayId = atoll(optarg);
                 break;
             case '?':
             case 'h':
-                usage(pname);
+                usage(pname, *displayId);
                 return 1;
         }
     }
@@ -166,7 +170,7 @@
     }
 
     if (fd == -1) {
-        usage(pname);
+        usage(pname, *displayId);
         return 1;
     }
 
@@ -192,9 +196,10 @@
     ProcessState::self()->setThreadPoolMaxThreadCount(0);
     ProcessState::self()->startThreadPool();
 
-    sp<IBinder> display = SurfaceComposerClient::getBuiltInDisplay(displayId);
-    if (display == NULL) {
-        fprintf(stderr, "Unable to get handle for display %d\n", displayId);
+    const sp<IBinder> display = SurfaceComposerClient::getPhysicalDisplayToken(*displayId);
+    if (display == nullptr) {
+        fprintf(stderr, "Failed to get token for invalid display %"
+                ANDROID_PHYSICAL_DISPLAY_ID_FORMAT "\n", *displayId);
         return 1;
     }
 
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index ca10482..d6f045e 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -50,6 +50,7 @@
 
     srcs: [
         ":statsd_aidl",
+        "src/active_config_list.proto",
         "src/statsd_config.proto",
         "src/FieldValue.cpp",
         "src/hash.cpp",
@@ -214,7 +215,7 @@
         "tests/anomaly/AnomalyTracker_test.cpp",
         "tests/ConfigManager_test.cpp",
         "tests/external/puller_util_test.cpp",
-	"tests/external/StatsPuller_test.cpp",
+        "tests/external/StatsPuller_test.cpp",
         "tests/indexed_priority_queue_test.cpp",
         "tests/LogEntryMatcher_test.cpp",
         "tests/LogEvent_test.cpp",
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index 69cb264..dd18bd4 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -14,18 +14,19 @@
  * limitations under the License.
  */
 
-#define DEBUG false // STOPSHIP if true
+#define DEBUG false  // STOPSHIP if true
 #include "Log.h"
 #include "statslog.h"
 
 #include <android-base/file.h>
 #include <dirent.h>
+#include <frameworks/base/cmds/statsd/src/active_config_list.pb.h>
 #include "StatsLogProcessor.h"
-#include "stats_log_util.h"
 #include "android-base/stringprintf.h"
+#include "external/StatsPullerManager.h"
 #include "guardrail/StatsdStats.h"
 #include "metrics/CountMetricProducer.h"
-#include "external/StatsPullerManager.h"
+#include "stats_log_util.h"
 #include "stats_util.h"
 #include "storage/StorageManager.h"
 
@@ -67,9 +68,17 @@
 const int FIELD_ID_DUMP_REPORT_REASON = 8;
 const int FIELD_ID_STRINGS = 9;
 
+const int FIELD_ID_ACTIVE_CONFIG_LIST = 1;
+const int FIELD_ID_CONFIG_ID = 1;
+const int FIELD_ID_CONFIG_UID = 2;
+const int FIELD_ID_ACTIVE_METRIC = 3;
+const int FIELD_ID_METRIC_ID = 1;
+const int FIELD_ID_TIME_TO_LIVE_NANOS = 2;
+
 #define NS_PER_HOUR 3600 * NS_PER_SEC
 
 #define STATS_DATA_DIR "/data/misc/stats-data"
+#define STATS_ACTIVE_METRIC_DIR "/data/misc/stats-active-metric"
 
 // Cool down period for writing data to disk to avoid overwriting files.
 #define WRITE_DATA_COOL_DOWN_SEC 5
@@ -507,6 +516,71 @@
     mOnDiskDataConfigs.insert(key);
 }
 
+void StatsLogProcessor::WriteMetricsActivationToDisk(int64_t currentTimeNs) {
+    std::lock_guard<std::mutex> lock(mMetricsMutex);
+    ProtoOutputStream proto;
+
+    for (const auto& pair : mMetricsManagers) {
+        uint64_t activeConfigListToken = proto.start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
+                                                     FIELD_ID_ACTIVE_CONFIG_LIST);
+        proto.write(FIELD_TYPE_INT64 | FIELD_ID_CONFIG_ID, (long long)pair.first.GetId());
+        proto.write(FIELD_TYPE_INT32 | FIELD_ID_CONFIG_UID, pair.first.GetUid());
+
+        vector<MetricProducer*> activeMetrics;
+        pair.second->prepForShutDown(currentTimeNs);
+        pair.second->getActiveMetrics(activeMetrics);
+        for (MetricProducer* metric : activeMetrics) {
+            if (metric->isActive()) {
+                uint64_t metricToken = proto.start(FIELD_TYPE_MESSAGE | FIELD_COUNT_REPEATED |
+                                                   FIELD_ID_ACTIVE_METRIC);
+                proto.write(FIELD_TYPE_INT64 | FIELD_ID_METRIC_ID,
+                            (long long)metric->getMetricId());
+                proto.write(FIELD_TYPE_INT64 | FIELD_ID_TIME_TO_LIVE_NANOS,
+                            (long long)metric->getRemainingTtlNs(currentTimeNs));
+                proto.end(metricToken);
+            }
+        }
+        proto.end(activeConfigListToken);
+    }
+
+    string file_name = StringPrintf("%s/active_metrics", STATS_ACTIVE_METRIC_DIR);
+    StorageManager::deleteFile(file_name.c_str());
+    android::base::unique_fd fd(
+            open(file_name.c_str(), O_WRONLY | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR));
+    if (fd == -1) {
+        ALOGE("Attempt to write %s but failed", file_name.c_str());
+        return;
+    }
+    proto.flush(fd.get());
+}
+
+void StatsLogProcessor::LoadMetricsActivationFromDisk() {
+    string file_name = StringPrintf("%s/active_metrics", STATS_ACTIVE_METRIC_DIR);
+    int fd = open(file_name.c_str(), O_RDONLY | O_CLOEXEC);
+    if (fd != -1) {
+        string content;
+        if (android::base::ReadFdToString(fd, &content)) {
+            ActiveConfigList activeConfigList;
+            if (activeConfigList.ParseFromString(content)) {
+                for (int i = 0; i < activeConfigList.active_config_size(); i++) {
+                    const auto& config = activeConfigList.active_config(i);
+                    ConfigKey key(config.uid(), config.config_id());
+                    auto it = mMetricsManagers.find(key);
+                    if (it == mMetricsManagers.end()) {
+                        ALOGE("No config found for config %s", key.ToString().c_str());
+                        continue;
+                    }
+                    VLOG("Setting active config %s", key.ToString().c_str());
+                    it->second->setActiveMetrics(config, mTimeBaseNs);
+                }
+            }
+            VLOG("Successfully loaded %d active configs.", activeConfigList.active_config_size());
+        }
+        close(fd);
+    }
+    StorageManager::deleteFile(file_name.c_str());
+}
+
 void StatsLogProcessor::WriteDataToDiskLocked(const DumpReportReason dumpReportReason) {
     const int64_t timeNs = getElapsedRealtimeNs();
     // Do not write to disk if we already have in the last few seconds.
diff --git a/cmds/statsd/src/StatsLogProcessor.h b/cmds/statsd/src/StatsLogProcessor.h
index a5ce9b6..caf1a71 100644
--- a/cmds/statsd/src/StatsLogProcessor.h
+++ b/cmds/statsd/src/StatsLogProcessor.h
@@ -80,6 +80,12 @@
     /* Flushes data to disk. Data on memory will be gone after written to disk. */
     void WriteDataToDisk(const DumpReportReason dumpReportReason);
 
+    /* Persist metric activation status onto disk. */
+    void WriteMetricsActivationToDisk(int64_t currentTimeNs);
+
+    /* Load metric activation status from disk. */
+    void LoadMetricsActivationFromDisk();
+
     // Reset all configs.
     void resetConfigs();
 
@@ -188,6 +194,9 @@
     FRIEND_TEST(StatsLogProcessorTest, TestRateLimitByteSize);
     FRIEND_TEST(StatsLogProcessorTest, TestRateLimitBroadcast);
     FRIEND_TEST(StatsLogProcessorTest, TestDropWhenByteSizeTooLarge);
+    FRIEND_TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead);
+    FRIEND_TEST(StatsLogProcessorTest, TestActivationOnBoot);
+
     FRIEND_TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration1);
     FRIEND_TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration2);
     FRIEND_TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensionsForSumDuration3);
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index b26c713..86bf3ec 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -161,7 +161,8 @@
     mConfigManager = new ConfigManager();
     mProcessor = new StatsLogProcessor(
             mUidMap, mPullerManager, mAnomalyAlarmMonitor, mPeriodicAlarmMonitor,
-            getElapsedRealtimeNs(), [this](const ConfigKey& key) {
+            getElapsedRealtimeNs(),
+            [this](const ConfigKey& key) {
                 sp<IStatsCompanionService> sc = getStatsCompanionService();
                 auto receiver = mConfigManager->GetConfigReceiver(key);
                 if (sc == nullptr) {
@@ -867,6 +868,7 @@
     ENFORCE_UID(AID_SYSTEM);
     VLOG("StatsService::informDeviceShutdown");
     mProcessor->WriteDataToDisk(DEVICE_SHUTDOWN);
+    mProcessor->WriteMetricsActivationToDisk(getElapsedRealtimeNs());
     return Status::ok();
 }
 
@@ -901,6 +903,7 @@
 
 void StatsService::Startup() {
     mConfigManager->Startup();
+    mProcessor->LoadMetricsActivationFromDisk();
 }
 
 void StatsService::Terminate() {
diff --git a/cmds/statsd/src/active_config_list.proto b/cmds/statsd/src/active_config_list.proto
new file mode 100644
index 0000000..0e9ee03
--- /dev/null
+++ b/cmds/statsd/src/active_config_list.proto
@@ -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.
+ */
+
+syntax = "proto2";
+
+package android.os.statsd;
+option java_package = "com.android.os";
+option java_multiple_files = true;
+option java_outer_classname = "ActiveConfigProto";
+
+message ActiveMetric {
+    // metric id
+    optional int64 metric_id = 1;
+    // Remaining time to live in nano seconds. -1 for infinity.
+    optional int64 time_to_live_nanos = 2;
+}
+
+message ActiveConfig {
+    // config id
+    optional int64 config_id = 1;
+    // config uid
+    optional int32 uid = 2;
+    // metrics
+    repeated ActiveMetric active_metric = 3;
+}
+
+// all configs and their metrics on device.
+message ActiveConfigList {
+    repeated ActiveConfig active_config = 1;
+}
\ No newline at end of file
diff --git a/cmds/statsd/src/anomaly/subscriber_util.cpp b/cmds/statsd/src/anomaly/subscriber_util.cpp
index ad5eae3..6b46b8b 100644
--- a/cmds/statsd/src/anomaly/subscriber_util.cpp
+++ b/cmds/statsd/src/anomaly/subscriber_util.cpp
@@ -23,7 +23,6 @@
 
 #include "external/Perfetto.h"
 #include "external/Perfprofd.h"
-#include "frameworks/base/libs/incident/proto/android/os/header.pb.h"
 #include "subscriber/IncidentdReporter.h"
 #include "subscriber/SubscriberReporter.h"
 
diff --git a/cmds/statsd/src/atom_field_options.proto b/cmds/statsd/src/atom_field_options.proto
index e33bd8c..2a3eee2 100644
--- a/cmds/statsd/src/atom_field_options.proto
+++ b/cmds/statsd/src/atom_field_options.proto
@@ -82,4 +82,6 @@
     optional bool is_uid = 50001 [default = false];
 
     optional LogMode log_mode = 50002 [default = MODE_AUTOMATIC];
+
+    optional bool allow_from_any_uid = 50003 [default = false];
 }
\ No newline at end of file
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index fc3aa91..7ddb783 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -41,12 +41,13 @@
 import "frameworks/base/core/proto/android/service/usb.proto";
 import "frameworks/base/core/proto/android/stats/enums.proto";
 import "frameworks/base/core/proto/android/stats/docsui/docsui_enums.proto";
+import "frameworks/base/core/proto/android/stats/devicepolicy/device_policy.proto";
+import "frameworks/base/core/proto/android/stats/devicepolicy/device_policy_enums.proto";
 import "frameworks/base/core/proto/android/stats/launcher/launcher.proto";
 import "frameworks/base/core/proto/android/telecomm/enums.proto";
 import "frameworks/base/core/proto/android/telephony/enums.proto";
 import "frameworks/base/core/proto/android/view/enums.proto";
-import "frameworks/base/core/proto/android/stats/devicepolicy/device_policy_enums.proto";
-import "frameworks/base/core/proto/android/stats/devicepolicy/device_policy.proto";
+import "frameworks/base/core/proto/android/wifi/enums.proto";
 
 /**
  * The master atom class. This message defines all of the available
@@ -110,7 +111,7 @@
         PacketWakeupOccurred packet_wakeup_occurred = 44;
         WallClockTimeShifted wall_clock_time_shifted = 45;
         AnomalyDetected anomaly_detected = 46;
-        AppBreadcrumbReported app_breadcrumb_reported = 47;
+        AppBreadcrumbReported app_breadcrumb_reported = 47 [(allow_from_any_uid) = true];
         AppStartOccurred app_start_occurred = 48;
         AppStartCanceled app_start_canceled = 49;
         AppStartFullyDrawn app_start_fully_drawn = 50;
@@ -121,7 +122,7 @@
         AppStartMemoryStateCaptured app_start_memory_state_captured = 55;
         ShutdownSequenceReported shutdown_sequence_reported = 56;
         BootSequenceReported boot_sequence_reported = 57;
-        DaveyOccurred davey_occurred = 58;
+        DaveyOccurred davey_occurred = 58 [(allow_from_any_uid) = true];
         OverlayStateChanged overlay_state_changed = 59;
         ForegroundServiceStateChanged foreground_service_state_changed = 60;
         CallStateChanged call_state_changed = 61;
@@ -214,7 +215,7 @@
         SpeechDspStatReported speech_dsp_stat_reported = 145;
         UsbContaminantReported usb_contaminant_reported = 146;
         WatchdogRollbackOccurred watchdog_rollback_occurred = 147;
-        BiometricHalDeathReported biometric_hal_death_reported = 148;
+        BiometricSystemHealthIssueDetected biometric_system_health_issue_detected = 148;
         BubbleUIChanged bubble_ui_changed = 149;
         ScheduledJobConstraintChanged scheduled_job_constraint_changed = 150;
         BluetoothActiveDeviceChanged bluetooth_active_device_changed = 151;
@@ -239,6 +240,7 @@
         PermissionGrantRequestResultReported permission_grant_request_result_reported = 170;
         BluetoothSocketConnectionStateChanged bluetooth_socket_connection_state_changed = 171;
         DeviceIdentifierAccessDenied device_identifier_access_denied = 172;
+        BubbleDeveloperErrorReported bubble_developer_error_reported = 173;
     }
 
     // Pulled events will start at field 10000.
@@ -993,6 +995,9 @@
         ON = 1;
     }
     optional State state = 2;
+
+    // WifiLock type, from frameworks/base/core/proto/android/wifi/enums.proto.
+    optional android.net.wifi.WifiModeEnum mode = 3;
 }
 
 /**
@@ -2081,9 +2086,9 @@
     // Salt: Randomly generated 256 bit value
     // Hash algorithm: HMAC-SHA256
     // Size: 32 byte
-    // Default: null or empty if the device identifier is not known
+    // Default: null or empty if this is a server listener socket
     optional bytes obfuscated_id = 1 [(android.os.statsd.log_mode) = MODE_BYTES];
-    // Port of this socket
+    // Temporary port of this socket for the current connection or session only
     // Default 0 when unknown or don't care
     optional int32 port = 2;
     // Socket type as mentioned in
@@ -2097,6 +2102,14 @@
     optional int64 tx_bytes = 5;
     // Number of bytes received from remote device during this connection
     optional int64 rx_bytes = 6;
+    // Socket owner's UID
+    optional int32 uid = 7 [(is_uid) = true];
+    // Server port of this socket, if any. When both |server_port| and |port| fields are populated,
+    // |port| must be spawned by |server_port|
+    // Default 0 when unknown or don't care
+    optional int32 server_port = 8;
+    // Whether this is a server listener socket
+    optional android.bluetooth.SocketRoleEnum is_server = 9;
 }
 
 /**
@@ -3045,13 +3058,15 @@
 }
 
 /**
- * Logs when a biometric HAL has crashed.
+ * Logs when a system health issue is detected.
  * Logged from:
  *   frameworks/base/services/core/java/com/android/server/biometrics
  */
-message BiometricHalDeathReported {
+message BiometricSystemHealthIssueDetected {
     // Biometric modality.
     optional android.hardware.biometrics.ModalityEnum modality = 1;
+    // Type of issue detected.
+    optional android.hardware.biometrics.IssueEnum issue = 2;
 }
 
 message Notification {
@@ -5344,6 +5359,27 @@
 }
 
 /**
+  * Logs System UI bubbles developer errors.
+  *
+  * Logged from:
+  *   frameworks/base/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+  */
+message BubbleDeveloperErrorReported {
+
+    // The app package that is posting the bubble.
+    optional string package_name = 1;
+
+    // Bubble developer error type enums.
+    enum Error {
+        UNKNOWN = 0;
+        ACTIVITY_INFO_MISSING = 1;
+        ACTIVITY_INFO_NOT_RESIZABLE = 2;
+        DOCUMENT_LAUNCH_NOT_ALWAYS = 3;
+    }
+    optional Error error = 2 [default = UNKNOWN];
+}
+
+/**
  * Logs that a constraint for a scheduled job has changed.
  *
  * Logged from:
diff --git a/cmds/statsd/src/external/PullDataReceiver.h b/cmds/statsd/src/external/PullDataReceiver.h
index 0d505cb..d2193f4 100644
--- a/cmds/statsd/src/external/PullDataReceiver.h
+++ b/cmds/statsd/src/external/PullDataReceiver.h
@@ -28,9 +28,16 @@
 class PullDataReceiver : virtual public RefBase{
  public:
   virtual ~PullDataReceiver() {}
-  virtual void onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& data) = 0;
+  /**
+   * @param data The pulled data.
+   * @param pullSuccess Whether the pull succeeded. If the pull does not succeed, the data for the
+   * bucket should be invalidated.
+   * @param originalPullTimeNs This is when all the pulls have been initiated (elapsed time).
+   */
+  virtual void onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& data, 
+                            bool pullSuccess, int64_t originalPullTimeNs) = 0;
 };
 
 }  // namespace statsd
 }  // namespace os
-}  // namespace android
\ No newline at end of file
+}  // namespace android
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index c69384c..ecdcd21 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -174,9 +174,12 @@
         // Size of specific categories of files. Eg. Music.
         {android::util::CATEGORY_SIZE,
          {.puller = new StatsCompanionServicePuller(android::util::CATEGORY_SIZE)}},
-        // Number of fingerprints registered to each user.
+        // Number of fingerprints enrolled for each user.
         {android::util::NUM_FINGERPRINTS_ENROLLED,
          {.puller = new StatsCompanionServicePuller(android::util::NUM_FINGERPRINTS_ENROLLED)}},
+        // Number of faces enrolled for each user.
+        {android::util::NUM_FACES_ENROLLED,
+         {.puller = new StatsCompanionServicePuller(android::util::NUM_FACES_ENROLLED)}},
         // ProcStats.
         {android::util::PROC_STATS,
          {.puller = new StatsCompanionServicePuller(android::util::PROC_STATS)}},
@@ -358,12 +361,13 @@
 
     for (const auto& pullInfo : needToPull) {
         vector<shared_ptr<LogEvent>> data;
-        if (!Pull(pullInfo.first, &data)) {
+        bool pullSuccess = Pull(pullInfo.first, &data);
+        if (pullSuccess) {
+            StatsdStats::getInstance().notePullDelay(
+                    pullInfo.first, getElapsedRealtimeNs() - elapsedTimeNs);
+        } else {
             VLOG("pull failed at %lld, will try again later", (long long)elapsedTimeNs);
-            continue;
         }
-        StatsdStats::getInstance().notePullDelay(pullInfo.first,
-                                                 getElapsedRealtimeNs() - elapsedTimeNs);
 
         // Convention is to mark pull atom timestamp at request time.
         // If we pull at t0, puller starts at t1, finishes at t2, and send back
@@ -380,8 +384,8 @@
         for (const auto& receiverInfo : pullInfo.second) {
             sp<PullDataReceiver> receiverPtr = receiverInfo->receiver.promote();
             if (receiverPtr != nullptr) {
-                receiverPtr->onDataPulled(data);
-                // we may have just come out of a coma, compute next pull time
+                receiverPtr->onDataPulled(data, pullSuccess, elapsedTimeNs);
+                // We may have just come out of a coma, compute next pull time.
                 int numBucketsAhead =
                         (elapsedTimeNs - receiverInfo->nextPullTimeNs) / receiverInfo->intervalNs;
                 receiverInfo->nextPullTimeNs += (numBucketsAhead + 1) * receiverInfo->intervalNs;
diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp
index 37ccad5..c4034ff 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.cpp
+++ b/cmds/statsd/src/guardrail/StatsdStats.cpp
@@ -423,31 +423,50 @@
     mPulledAtomStats[atomId].emptyData++;
 }
 
-void StatsdStats::noteHardDimensionLimitReached(int metricId) {
+void StatsdStats::noteHardDimensionLimitReached(int64_t metricId) {
     lock_guard<std::mutex> lock(mLock);
     getAtomMetricStats(metricId).hardDimensionLimitReached++;
 }
 
-void StatsdStats::noteLateLogEventSkipped(int metricId) {
+void StatsdStats::noteLateLogEventSkipped(int64_t metricId) {
     lock_guard<std::mutex> lock(mLock);
     getAtomMetricStats(metricId).lateLogEventSkipped++;
 }
 
-void StatsdStats::noteSkippedForwardBuckets(int metricId) {
+void StatsdStats::noteSkippedForwardBuckets(int64_t metricId) {
     lock_guard<std::mutex> lock(mLock);
     getAtomMetricStats(metricId).skippedForwardBuckets++;
 }
 
-void StatsdStats::noteBadValueType(int metricId) {
+void StatsdStats::noteBadValueType(int64_t metricId) {
     lock_guard<std::mutex> lock(mLock);
     getAtomMetricStats(metricId).badValueType++;
 }
 
-void StatsdStats::noteConditionChangeInNextBucket(int metricId) {
+void StatsdStats::noteBucketDropped(int64_t metricId) {
+    lock_guard<std::mutex> lock(mLock);
+    getAtomMetricStats(metricId).bucketDropped++;
+}
+
+void StatsdStats::noteConditionChangeInNextBucket(int64_t metricId) {
     lock_guard<std::mutex> lock(mLock);
     getAtomMetricStats(metricId).conditionChangeInNextBucket++;
 }
 
+void StatsdStats::noteInvalidatedBucket(int64_t metricId) {
+    lock_guard<std::mutex> lock(mLock);
+    getAtomMetricStats(metricId).invalidatedBucket++;
+}
+
+void StatsdStats::noteBucketBoundaryDelayNs(int64_t metricId, int64_t timeDelayNs) {
+    lock_guard<std::mutex> lock(mLock);
+    AtomMetricStats& pullStats = getAtomMetricStats(metricId);
+    pullStats.maxBucketBoundaryDelayNs =
+            std::max(pullStats.maxBucketBoundaryDelayNs, timeDelayNs);
+    pullStats.minBucketBoundaryDelayNs =
+            std::min(pullStats.minBucketBoundaryDelayNs, timeDelayNs);
+}
+
 StatsdStats::AtomMetricStats& StatsdStats::getAtomMetricStats(int metricId) {
     auto atomMetricStatsIter = mAtomMetricStats.find(metricId);
     if (atomMetricStatsIter != mAtomMetricStats.end()) {
diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h
index 01e9ca1..2999b64 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.h
+++ b/cmds/statsd/src/guardrail/StatsdStats.h
@@ -342,27 +342,43 @@
     /**
      * Hard limit was reached in the cardinality of an atom
      */
-    void noteHardDimensionLimitReached(int atomId);
+    void noteHardDimensionLimitReached(int64_t metricId);
 
     /**
      * A log event was too late, arrived in the wrong bucket and was skipped
      */
-    void noteLateLogEventSkipped(int atomId);
+    void noteLateLogEventSkipped(int64_t metricId);
 
     /**
      * Buckets were skipped as time elapsed without any data for them
      */
-    void noteSkippedForwardBuckets(int atomId);
+    void noteSkippedForwardBuckets(int64_t metricId);
 
     /**
      * An unsupported value type was received
      */
-    void noteBadValueType(int atomId);
+    void noteBadValueType(int64_t metricId);
+
+    /**
+     * Buckets were dropped due to reclaim memory.
+     */
+    void noteBucketDropped(int64_t metricId);
 
     /**
      * A condition change was too late, arrived in the wrong bucket and was skipped
      */
-    void noteConditionChangeInNextBucket(int atomId);
+    void noteConditionChangeInNextBucket(int64_t metricId);
+
+    /**
+     * A bucket has been tagged as invalid.
+     */
+    void noteInvalidatedBucket(int64_t metricId);
+
+    /**
+     * For pulls at bucket boundaries, it represents the misalignment between the real timestamp and
+     * the end of the bucket.
+     */
+    void noteBucketBoundaryDelayNs(int64_t metricId, int64_t timeDelayNs);
 
     /**
      * Reset the historical stats. Including all stats in icebox, and the tracked stats about
@@ -408,6 +424,10 @@
         long skippedForwardBuckets = 0;
         long badValueType = 0;
         long conditionChangeInNextBucket = 0;
+        long invalidatedBucket = 0;
+        long bucketDropped = 0;
+        int64_t minBucketBoundaryDelayNs = 0;
+        int64_t maxBucketBoundaryDelayNs = 0;
     } AtomMetricStats;
 
 private:
diff --git a/cmds/statsd/src/metrics/CountMetricProducer.cpp b/cmds/statsd/src/metrics/CountMetricProducer.cpp
index 7cc57c1..350745b 100644
--- a/cmds/statsd/src/metrics/CountMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/CountMetricProducer.cpp
@@ -243,6 +243,7 @@
 
 void CountMetricProducer::dropDataLocked(const int64_t dropTimeNs) {
     flushIfNeededLocked(dropTimeNs);
+    StatsdStats::getInstance().noteBucketDropped(mMetricId);
     mPastBuckets.clear();
 }
 
diff --git a/cmds/statsd/src/metrics/DurationMetricProducer.cpp b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
index 69bafc3..6c1c47b 100644
--- a/cmds/statsd/src/metrics/DurationMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/DurationMetricProducer.cpp
@@ -444,6 +444,7 @@
 
 void DurationMetricProducer::dropDataLocked(const int64_t dropTimeNs) {
     flushIfNeededLocked(dropTimeNs);
+    StatsdStats::getInstance().noteBucketDropped(mMetricId);
     mPastBuckets.clear();
 }
 
diff --git a/cmds/statsd/src/metrics/EventMetricProducer.cpp b/cmds/statsd/src/metrics/EventMetricProducer.cpp
index c53c4ce..7e695a6 100644
--- a/cmds/statsd/src/metrics/EventMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/EventMetricProducer.cpp
@@ -77,6 +77,7 @@
 
 void EventMetricProducer::dropDataLocked(const int64_t dropTimeNs) {
     mProto->clear();
+    StatsdStats::getInstance().noteBucketDropped(mMetricId);
 }
 
 void EventMetricProducer::onSlicedConditionMayChangeLocked(bool overallCondition,
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index c2878f0..d56a355 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -406,9 +406,10 @@
     return gaugeFields;
 }
 
-void GaugeMetricProducer::onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& allData) {
+void GaugeMetricProducer::onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& allData,
+                                       bool pullSuccess, int64_t originalPullTimeNs) {
     std::lock_guard<std::mutex> lock(mMutex);
-    if (allData.size() == 0) {
+    if (!pullSuccess || allData.size() == 0) {
         return;
     }
     for (const auto& data : allData) {
@@ -509,6 +510,7 @@
 
 void GaugeMetricProducer::dropDataLocked(const int64_t dropTimeNs) {
     flushIfNeededLocked(dropTimeNs);
+    StatsdStats::getInstance().noteBucketDropped(mMetricId);
     mPastBuckets.clear();
 }
 
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.h b/cmds/statsd/src/metrics/GaugeMetricProducer.h
index df08779..64a1833 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.h
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.h
@@ -67,7 +67,8 @@
     virtual ~GaugeMetricProducer();
 
     // Handles when the pulled data arrives.
-    void onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& data) override;
+    void onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& data,
+                      bool pullSuccess, int64_t originalPullTimeNs) override;
 
     // GaugeMetric needs to immediately trigger another pull when we create the partial bucket.
     void notifyAppUpgrade(const int64_t& eventTimeNs, const string& apk, const int uid,
diff --git a/cmds/statsd/src/metrics/MetricProducer.cpp b/cmds/statsd/src/metrics/MetricProducer.cpp
index f87849e..495138e 100644
--- a/cmds/statsd/src/metrics/MetricProducer.cpp
+++ b/cmds/statsd/src/metrics/MetricProducer.cpp
@@ -107,11 +107,57 @@
     if (it == mEventActivationMap.end()) {
         return;
     }
+    if (mActivationType == MetricActivation::ACTIVATE_ON_BOOT) {
+        it->second.state = ActivationState::kActiveOnBoot;
+        return;
+    }
     it->second.activation_ns = elapsedTimestampNs;
     it->second.state = ActivationState::kActive;
     mIsActive = true;
 }
 
+void MetricProducer::setActiveLocked(int64_t currentTimeNs, int64_t remainingTtlNs) {
+    if (mEventActivationMap.size() == 0) {
+        return;
+    }
+    for (auto& pair : mEventActivationMap) {
+        auto& activation = pair.second;
+        if (activation.ttl_ns >= remainingTtlNs) {
+            activation.activation_ns = currentTimeNs + remainingTtlNs - activation.ttl_ns;
+            activation.state = kActive;
+            mIsActive = true;
+            VLOG("setting new activation time to %lld, %lld, %lld",
+                 (long long)activation.activation_ns, (long long)currentTimeNs,
+                 (long long)remainingTtlNs);
+            return;
+        }
+    }
+    ALOGE("Required ttl is longer than all possible activations.");
+}
+
+int64_t MetricProducer::getRemainingTtlNsLocked(int64_t currentTimeNs) const {
+    int64_t maxTtl = 0;
+    for (const auto& activation : mEventActivationMap) {
+        if (activation.second.state == kActive) {
+            maxTtl = std::max(maxTtl, activation.second.ttl_ns + activation.second.activation_ns -
+                                              currentTimeNs);
+        }
+    }
+    return maxTtl;
+}
+
+void MetricProducer::prepActiveForBootIfNecessaryLocked(int64_t currentTimeNs) {
+    if (mActivationType != MetricActivation::ACTIVATE_ON_BOOT) {
+        return;
+    }
+    for (auto& activation : mEventActivationMap) {
+        if (activation.second.state == kActiveOnBoot) {
+            activation.second.state = kActive;
+            activation.second.activation_ns = currentTimeNs;
+            mIsActive = true;
+        }
+    }
+}
 
 }  // namespace statsd
 }  // namespace os
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index 09e2409..849cb76 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -37,12 +37,13 @@
 // If the metric has no activation requirement, it will be active once the metric producer is
 // created.
 // If the metric needs to be activated by atoms, the metric producer will start
-// with kNotActive state, turn to kActive when the activation event arrives, become kNotActive
-// when it reaches the duration limit (timebomb). If the activation event arrives again before
-// or after it expires, the event producer will be re-activated and ttl will be reset.
+// with kNotActive state, turn to kActive or kActiveOnBoot when the activation event arrives, become
+// kNotActive when it reaches the duration limit (timebomb). If the activation event arrives again
+// before or after it expires, the event producer will be re-activated and ttl will be reset.
 enum ActivationState {
     kNotActive = 0,
     kActive = 1,
+    kActiveOnBoot = 2,
 };
 
 // A MetricProducer is responsible for compute one single metrics, creating stats log report, and
@@ -179,10 +180,21 @@
         mBucketSizeNs = bucketSize;
     }
 
-    inline const int64_t& getMetricId() {
+    inline const int64_t& getMetricId() const {
         return mMetricId;
     }
 
+    int64_t getRemainingTtlNs(int64_t currentTimeNs) const {
+        std::lock_guard<std::mutex> lock(mMutex);
+        return getRemainingTtlNsLocked(currentTimeNs);
+    }
+
+    // Set metric to active for ttlNs.
+    void setActive(int64_t currentTimeNs, int64_t remainingTtlNs) {
+        std::lock_guard<std::mutex> lock(mMutex);
+        setActiveLocked(currentTimeNs, remainingTtlNs);
+    }
+
     // Let MetricProducer drop in-memory data to save memory.
     // We still need to keep future data valid and anomaly tracking work, which means we will
     // have to flush old data, informing anomaly trackers then safely drop old data.
@@ -202,8 +214,22 @@
         activateLocked(activationTrackerIndex, elapsedTimestampNs);
     }
 
+    bool isActive() const {
+        std::lock_guard<std::mutex> lock(mMutex);
+        return isActiveLocked();
+    }
+
+    void prepActiveForBootIfNecessary(int64_t currentTimeNs) {
+        std::lock_guard<std::mutex> lock(mMutex);
+        prepActiveForBootIfNecessaryLocked(currentTimeNs);
+    }
+
     void addActivation(int activationTrackerIndex, int64_t ttl_seconds);
 
+    inline void setActivationType(const MetricActivation::ActivationType& activationType) {
+        mActivationType = activationType;
+    }
+
     void flushIfExpire(int64_t elapsedTimestampNs);
 
 protected:
@@ -227,6 +253,12 @@
         return mIsActive;
     }
 
+    void prepActiveForBootIfNecessaryLocked(int64_t currentTimeNs);
+
+    int64_t getRemainingTtlNsLocked(int64_t currentTimeNs) const;
+
+    void setActiveLocked(int64_t currentTimeNs, int64_t remainingTtlNs);
+
     /**
      * Flushes the current bucket if the eventTime is after the current bucket's end time. This will
        also flush the current partial bucket in memory.
@@ -347,7 +379,12 @@
 
     bool mIsActive;
 
+    MetricActivation::ActivationType mActivationType;
+
     FRIEND_TEST(MetricActivationE2eTest, TestCountMetric);
+
+    FRIEND_TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead);
+    FRIEND_TEST(StatsLogProcessorTest, TestActivationOnBoot);
 };
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index dd969c0..6ed6ab50 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -122,6 +122,13 @@
     StatsdStats::getInstance().noteConfigReceived(
             key, mAllMetricProducers.size(), mAllConditionTrackers.size(), mAllAtomMatchers.size(),
             mAllAnomalyTrackers.size(), mAnnotations, mConfigValid);
+    // Check active
+    for (const auto& metric : mAllMetricProducers) {
+        if (metric->isActive()) {
+            mIsActive = true;
+            break;
+        }
+    }
 }
 
 MetricsManager::~MetricsManager() {
@@ -234,12 +241,22 @@
     VLOG("=========================Metric Reports End==========================");
 }
 
-// Consume the stats log if it's interesting to this metric.
-void MetricsManager::onLogEvent(const LogEvent& event) {
-    if (!mConfigValid) {
-        return;
-    }
 
+bool MetricsManager::checkLogCredentials(const LogEvent& event) {
+    if (android::util::AtomsInfo::kWhitelistedAtoms.find(event.GetTagId()) !=
+      android::util::AtomsInfo::kWhitelistedAtoms.end()) 
+    {
+        return true;
+    }
+    std::lock_guard<std::mutex> lock(mAllowedLogSourcesMutex);
+    if (mAllowedLogSources.find(event.GetUid()) == mAllowedLogSources.end()) {
+        VLOG("log source %d not on the whitelist", event.GetUid());
+        return false;
+    }
+    return true;
+}
+
+bool MetricsManager::eventSanityCheck(const LogEvent& event) {
     if (event.GetTagId() == android::util::APP_BREADCRUMB_REPORTED) {
         // Check that app breadcrumb reported fields are valid.
         status_t err = NO_ERROR;
@@ -249,23 +266,23 @@
         long appHookUid = event.GetLong(event.size()-2, &err);
         if (err != NO_ERROR ) {
             VLOG("APP_BREADCRUMB_REPORTED had error when parsing the uid");
-            return;
+            return false;
         }
         int32_t loggerUid = event.GetUid();
         if (loggerUid != appHookUid && loggerUid != AID_STATSD) {
             VLOG("APP_BREADCRUMB_REPORTED has invalid uid: claimed %ld but caller is %d",
                  appHookUid, loggerUid);
-            return;
+            return false;
         }
 
         // The state must be from 0,3. This part of code must be manually updated.
         long appHookState = event.GetLong(event.size(), &err);
         if (err != NO_ERROR ) {
             VLOG("APP_BREADCRUMB_REPORTED had error when parsing the state field");
-            return;
+            return false;
         } else if (appHookState < 0 || appHookState > 3) {
             VLOG("APP_BREADCRUMB_REPORTED does not have valid state %ld", appHookState);
-            return;
+            return false;
         }
     } else if (event.GetTagId() == android::util::DAVEY_OCCURRED) {
         // Daveys can be logged from any app since they are logged in libs/hwui/JankTracker.cpp.
@@ -276,36 +293,49 @@
         long jankUid = event.GetLong(1, &err);
         if (err != NO_ERROR ) {
             VLOG("Davey occurred had error when parsing the uid");
-            return;
+            return false;
         }
         int32_t loggerUid = event.GetUid();
         if (loggerUid != jankUid && loggerUid != AID_STATSD) {
             VLOG("DAVEY_OCCURRED has invalid uid: claimed %ld but caller is %d", jankUid,
                  loggerUid);
-            return;
+            return false;
         }
 
         long duration = event.GetLong(event.size(), &err);
         if (err != NO_ERROR ) {
             VLOG("Davey occurred had error when parsing the duration");
-            return;
+            return false;
         } else if (duration > 100000) {
             VLOG("Davey duration is unreasonably long: %ld", duration);
-            return;
+            return false;
         }
-    } else {
-        std::lock_guard<std::mutex> lock(mAllowedLogSourcesMutex);
-        if (mAllowedLogSources.find(event.GetUid()) == mAllowedLogSources.end()) {
-            VLOG("log source %d not on the whitelist", event.GetUid());
-            return;
-        }
+    }
+
+    return true;
+}
+
+// Consume the stats log if it's interesting to this metric.
+void MetricsManager::onLogEvent(const LogEvent& event) {
+    if (!mConfigValid) {
+        return;
+    }
+
+    if (!checkLogCredentials(event)) {
+        return;
+    }
+
+    if (!eventSanityCheck(event)) {
+        return;
     }
 
     int tagId = event.GetTagId();
     int64_t eventTimeNs = event.GetElapsedTimestampNs();
 
+    bool isActive = false;
     for (int metric : mMetricIndexesWithActivation) {
         mAllMetricProducers[metric]->flushIfExpire(eventTimeNs);
+        isActive |= mAllMetricProducers[metric]->isActive();
     }
 
     if (mTagIds.find(tagId) == mTagIds.end()) {
@@ -323,10 +353,13 @@
         if (matcherCache[it.first] == MatchingState::kMatched) {
             for (int metricIndex : it.second) {
                 mAllMetricProducers[metricIndex]->activate(it.first, eventTimeNs);
+                isActive |= mAllMetricProducers[metricIndex]->isActive();
             }
         }
     }
 
+    mIsActive = isActive;
+
     // A bitmap to see which ConditionTracker needs to be re-evaluated.
     vector<bool> conditionToBeEvaluated(mAllConditionTrackers.size(), false);
 
@@ -418,6 +451,25 @@
     return totalSize;
 }
 
+void MetricsManager::setActiveMetrics(ActiveConfig config, int64_t currentTimeNs) {
+    if (config.active_metric_size() == 0) {
+        ALOGW("No active metric for config %s", mConfigKey.ToString().c_str());
+        return;
+    }
+
+    for (int i = 0; i < config.active_metric_size(); i++) {
+        for (int metric : mMetricIndexesWithActivation) {
+            if (mAllMetricProducers[metric]->getMetricId() == config.active_metric(i).metric_id()) {
+                VLOG("Setting active metric: %lld",
+                     (long long)mAllMetricProducers[metric]->getMetricId());
+                mAllMetricProducers[metric]->setActive(
+                        currentTimeNs, config.active_metric(i).time_to_live_nanos());
+                mIsActive = true;
+            }
+        }
+    }
+}
+
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
diff --git a/cmds/statsd/src/metrics/MetricsManager.h b/cmds/statsd/src/metrics/MetricsManager.h
index a31efbd..cb1cefb 100644
--- a/cmds/statsd/src/metrics/MetricsManager.h
+++ b/cmds/statsd/src/metrics/MetricsManager.h
@@ -16,12 +16,13 @@
 
 #pragma once
 
-#include "external/StatsPullerManager.h"
+#include <frameworks/base/cmds/statsd/src/active_config_list.pb.h>
 #include "anomaly/AlarmMonitor.h"
 #include "anomaly/AlarmTracker.h"
 #include "anomaly/AnomalyTracker.h"
 #include "condition/ConditionTracker.h"
 #include "config/ConfigKey.h"
+#include "external/StatsPullerManager.h"
 #include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
 #include "logd/LogEvent.h"
 #include "matchers/LogMatchingTracker.h"
@@ -48,6 +49,10 @@
     // Return whether the configuration is valid.
     bool isConfigValid() const;
 
+    bool checkLogCredentials(const LogEvent& event);
+
+    bool eventSanityCheck(const LogEvent& event);
+
     void onLogEvent(const LogEvent& event);
 
     void onAnomalyAlarmFired(
@@ -123,6 +128,26 @@
     // Does not change the state.
     virtual size_t byteSize();
 
+    inline bool isActive() const {
+        return mIsActive;
+    }
+
+    inline void getActiveMetrics(std::vector<MetricProducer*>& metrics) const {
+        for (const auto& metric : mAllMetricProducers) {
+            if (metric->isActive()) {
+                metrics.push_back(metric.get());
+            }
+        }
+    }
+
+    inline void prepForShutDown(int64_t currentTimeNs) {
+        for (const auto& metric : mAllMetricProducers) {
+            metric->prepActiveForBootIfNecessary(currentTimeNs);
+        }
+    }
+
+    void setActiveMetrics(ActiveConfig config, int64_t currentTimeNs);
+
 private:
     // For test only.
     inline int64_t getTtlEndNs() const { return mTtlEndNs; }
@@ -216,6 +241,9 @@
     // The metrics that don't need to be uploaded or even reported.
     std::set<int64_t> mNoReportMetricIds;
 
+    // Any metric active means the config is active.
+    bool mIsActive;
+
     FRIEND_TEST(WakelockDurationE2eTest, TestAggregatedPredicateDimensions);
     FRIEND_TEST(MetricConditionLinkE2eTest, TestMultiplePredicatesAndLinks);
     FRIEND_TEST(AttributionE2eTest, TestAttributionMatchAndSliceByFirstUid);
@@ -247,6 +275,9 @@
     FRIEND_TEST(AlarmE2eTest, TestMultipleAlarms);
     FRIEND_TEST(ConfigTtlE2eTest, TestCountMetric);
     FRIEND_TEST(MetricActivationE2eTest, TestCountMetric);
+
+    FRIEND_TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead);
+    FRIEND_TEST(StatsLogProcessorTest, TestActivationOnBoot);
 };
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index 6aa8e84..ac6c27a 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -104,6 +104,7 @@
       mSkipZeroDiffOutput(metric.skip_zero_diff_output()),
       mUseZeroDefaultBase(metric.use_zero_default_base()),
       mHasGlobalBase(false),
+      mCurrentBucketIsInvalid(false),
       mMaxPullDelayNs(metric.max_pull_delay_sec() > 0 ? metric.max_pull_delay_sec() * NS_PER_SEC
                                                       : StatsdStats::kPullMaxDelayNs),
       mSplitBucketForAppUpgrade(metric.split_bucket_for_app_upgrade()) {
@@ -174,6 +175,7 @@
 
 void ValueMetricProducer::dropDataLocked(const int64_t dropTimeNs) {
     flushIfNeededLocked(dropTimeNs);
+    StatsdStats::getInstance().noteBucketDropped(mMetricId);
     mPastBuckets.clear();
 }
 
@@ -308,6 +310,15 @@
     }
 }
 
+void ValueMetricProducer::invalidateCurrentBucket() {
+    if (!mCurrentBucketIsInvalid) {
+        // Only report once per invalid bucket.
+        StatsdStats::getInstance().noteInvalidatedBucket(mMetricId);
+    }
+    mCurrentBucketIsInvalid = true;
+    resetBase();
+}
+
 void ValueMetricProducer::resetBase() {
     for (auto& slice : mCurrentSlicedBucket) {
         for (auto& interval : slice.second) {
@@ -323,6 +334,7 @@
         VLOG("Skip event due to late arrival: %lld vs %lld", (long long)eventTimeNs,
              (long long)mCurrentBucketStartTimeNs);
         StatsdStats::getInstance().noteConditionChangeInNextBucket(mMetricId);
+        invalidateCurrentBucket();
         return;
     }
 
@@ -346,50 +358,27 @@
     vector<std::shared_ptr<LogEvent>> allData;
     if (!mPullerManager->Pull(mPullTagId, &allData)) {
         ALOGE("Gauge Stats puller failed for tag: %d at %lld", mPullTagId, (long long)timestampNs);
-        resetBase();
+        invalidateCurrentBucket();
         return;
     }
-    const int64_t pullDelayNs = getElapsedRealtimeNs() - timestampNs;
-    if (pullDelayNs > mMaxPullDelayNs) {
-        ALOGE("Pull finish too late for atom %d, longer than %lld", mPullTagId,
-              (long long)mMaxPullDelayNs);
-        StatsdStats::getInstance().notePullExceedMaxDelay(mPullTagId);
-        StatsdStats::getInstance().notePullDelay(mPullTagId, pullDelayNs);
-        resetBase();
-        return;
-    }
-    StatsdStats::getInstance().notePullDelay(mPullTagId, pullDelayNs);
 
-    if (timestampNs < mCurrentBucketStartTimeNs) {
-        // The data will be skipped in onMatchedLogEventInternalLocked, but we don't want to report
-        // for every event, just the pull
-        StatsdStats::getInstance().noteLateLogEventSkipped(mMetricId);
-    }
-
-    for (const auto& data : allData) {
-        // make a copy before doing and changes
-        LogEvent localCopy = data->makeCopy();
-        localCopy.setElapsedTimestampNs(timestampNs);
-        if (mEventMatcherWizard->matchLogEvent(localCopy, mWhatMatcherIndex) ==
-            MatchingState::kMatched) {
-            onMatchedLogEventLocked(mWhatMatcherIndex, localCopy);
-        }
-    }
-    mHasGlobalBase = true;
+    accumulateEvents(allData, timestampNs, timestampNs);
 }
 
 int64_t ValueMetricProducer::calcPreviousBucketEndTime(const int64_t currentTimeNs) {
     return mTimeBaseNs + ((currentTimeNs - mTimeBaseNs) / mBucketSizeNs) * mBucketSizeNs;
 }
 
-void ValueMetricProducer::onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& allData) {
+void ValueMetricProducer::onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& allData,
+                                       bool pullSuccess, int64_t originalPullTimeNs) {
     std::lock_guard<std::mutex> lock(mMutex);
     if (mCondition) {
-        if (allData.size() == 0) {
-            VLOG("Data pulled is empty");
-            StatsdStats::getInstance().noteEmptyData(mPullTagId);
+        if (!pullSuccess) {
+            // If the pull failed, we won't be able to compute a diff.
+            invalidateCurrentBucket();
             return;
         }
+
         // For scheduled pulled data, the effective event time is snap to the nearest
         // bucket end. In the case of waking up from a deep sleep state, we will
         // attribute to the previous bucket end. If the sleep was long but not very long, we
@@ -397,28 +386,72 @@
         // we pull at a later time than real bucket end.
         // If the sleep was very long, we skip more than one bucket before sleep. In this case,
         // if the diff base will be cleared and this new data will serve as new diff base.
-        int64_t realEventTime = allData.at(0)->GetElapsedTimestampNs();
-        int64_t bucketEndTime = calcPreviousBucketEndTime(realEventTime) - 1;
-        if (bucketEndTime < mCurrentBucketStartTimeNs) {
-            VLOG("Skip bucket end pull due to late arrival: %lld vs %lld", (long long)bucketEndTime,
-                 (long long)mCurrentBucketStartTimeNs);
-            StatsdStats::getInstance().noteLateLogEventSkipped(mMetricId);
-            return;
-        }
-        for (const auto& data : allData) {
-            LogEvent localCopy = data->makeCopy();
-            if (mEventMatcherWizard->matchLogEvent(localCopy, mWhatMatcherIndex) ==
-                MatchingState::kMatched) {
-                localCopy.setElapsedTimestampNs(bucketEndTime);
-                onMatchedLogEventLocked(mWhatMatcherIndex, localCopy);
-            }
-        }
-        mHasGlobalBase = true;
+        int64_t bucketEndTime = calcPreviousBucketEndTime(originalPullTimeNs) - 1;
+        StatsdStats::getInstance().noteBucketBoundaryDelayNs(
+                mMetricId, originalPullTimeNs - bucketEndTime);
+        accumulateEvents(allData, originalPullTimeNs, bucketEndTime);
+
+        // We can probably flush the bucket. Since we used bucketEndTime when calling
+        // #onMatchedLogEventInternalLocked, the current bucket will not have been flushed.
+        flushIfNeededLocked(originalPullTimeNs);
+
     } else {
         VLOG("No need to commit data on condition false.");
     }
 }
 
+void ValueMetricProducer::accumulateEvents(const std::vector<std::shared_ptr<LogEvent>>& allData, 
+                                           int64_t originalPullTimeNs, int64_t eventElapsedTimeNs) {
+    bool isEventLate = eventElapsedTimeNs < mCurrentBucketStartTimeNs;
+    if (isEventLate) {
+        VLOG("Skip bucket end pull due to late arrival: %lld vs %lld",
+             (long long)eventElapsedTimeNs, (long long)mCurrentBucketStartTimeNs);
+        StatsdStats::getInstance().noteLateLogEventSkipped(mMetricId);
+        invalidateCurrentBucket();
+        return;
+    }
+
+    const int64_t pullDelayNs = getElapsedRealtimeNs() - originalPullTimeNs;
+    StatsdStats::getInstance().notePullDelay(mPullTagId, pullDelayNs);
+    if (pullDelayNs > mMaxPullDelayNs) {
+        ALOGE("Pull finish too late for atom %d, longer than %lld", mPullTagId,
+              (long long)mMaxPullDelayNs);
+        StatsdStats::getInstance().notePullExceedMaxDelay(mPullTagId);
+        // We are missing one pull from the bucket which means we will not have a complete view of
+        // what's going on.
+        invalidateCurrentBucket();
+        return;
+    }
+
+    if (allData.size() == 0) {
+        VLOG("Data pulled is empty");
+        StatsdStats::getInstance().noteEmptyData(mPullTagId);
+    }
+
+    mMatchedMetricDimensionKeys.clear();
+    for (const auto& data : allData) {
+        LogEvent localCopy = data->makeCopy();
+        if (mEventMatcherWizard->matchLogEvent(localCopy, mWhatMatcherIndex) ==
+            MatchingState::kMatched) {
+            localCopy.setElapsedTimestampNs(eventElapsedTimeNs);
+            onMatchedLogEventLocked(mWhatMatcherIndex, localCopy);
+        }
+    }
+    // If the new pulled data does not contains some keys we track in our intervals, we need to
+    // reset the base.
+    for (auto& slice : mCurrentSlicedBucket) {
+        bool presentInPulledData = mMatchedMetricDimensionKeys.find(slice.first) 
+                != mMatchedMetricDimensionKeys.end();
+        if (!presentInPulledData) {
+            for (auto& interval : slice.second) {
+                interval.hasBase = false;
+            }
+        }
+    }
+    mMatchedMetricDimensionKeys.clear();
+    mHasGlobalBase = true;
+}
+
 void ValueMetricProducer::dumpStatesLocked(FILE* out, bool verbose) const {
     if (mCurrentSlicedBucket.size() == 0) {
         return;
@@ -514,6 +547,7 @@
              (long long)mCurrentBucketStartTimeNs);
         return;
     }
+    mMatchedMetricDimensionKeys.insert(eventKey);
 
     flushIfNeededLocked(eventTimeNs);
 
@@ -679,31 +713,13 @@
     VLOG("finalizing bucket for %ld, dumping %d slices", (long)mCurrentBucketStartTimeNs,
          (int)mCurrentSlicedBucket.size());
     int64_t fullBucketEndTimeNs = getCurrentBucketEndTimeNs();
-
     int64_t bucketEndTime = eventTimeNs < fullBucketEndTimeNs ? eventTimeNs : fullBucketEndTimeNs;
 
-    if (bucketEndTime - mCurrentBucketStartTimeNs >= mMinBucketSizeNs) {
+    bool isBucketLargeEnough = bucketEndTime - mCurrentBucketStartTimeNs >= mMinBucketSizeNs;
+    if (isBucketLargeEnough && !mCurrentBucketIsInvalid) {
         // The current bucket is large enough to keep.
         for (const auto& slice : mCurrentSlicedBucket) {
-            ValueBucket bucket;
-            bucket.mBucketStartNs = mCurrentBucketStartTimeNs;
-            bucket.mBucketEndNs = bucketEndTime;
-            for (const auto& interval : slice.second) {
-                if (interval.hasValue) {
-                    // skip the output if the diff is zero
-                    if (mSkipZeroDiffOutput && mUseDiff && interval.value.isZero()) {
-                        continue;
-                    }
-                    bucket.valueIndex.push_back(interval.valueIndex);
-                    if (mAggregationType != ValueMetric::AVG) {
-                        bucket.values.push_back(interval.value);
-                    } else {
-                        double sum = interval.value.type == LONG ? (double)interval.value.long_value
-                                                                 : interval.value.double_value;
-                        bucket.values.push_back(Value((double)sum / interval.sampleSize));
-                    }
-                }
-            }
+            ValueBucket bucket = buildPartialBucket(bucketEndTime, slice.second);
             // it will auto create new vector of ValuebucketInfo if the key is not found.
             if (bucket.valueIndex.size() > 0) {
                 auto& bucketList = mPastBuckets[slice.first];
@@ -714,6 +730,58 @@
         mSkippedBuckets.emplace_back(mCurrentBucketStartTimeNs, bucketEndTime);
     }
 
+    if (!mCurrentBucketIsInvalid) {
+        appendToFullBucket(eventTimeNs, fullBucketEndTimeNs);
+    }
+    initCurrentSlicedBucket();
+    mCurrentBucketIsInvalid = false;
+}
+
+ValueBucket ValueMetricProducer::buildPartialBucket(int64_t bucketEndTime,
+                                                    const std::vector<Interval>& intervals) {
+    ValueBucket bucket;
+    bucket.mBucketStartNs = mCurrentBucketStartTimeNs;
+    bucket.mBucketEndNs = bucketEndTime;
+    for (const auto& interval : intervals) {
+        if (interval.hasValue) {
+            // skip the output if the diff is zero
+            if (mSkipZeroDiffOutput && mUseDiff && interval.value.isZero()) {
+                continue;
+            }
+            bucket.valueIndex.push_back(interval.valueIndex);
+            if (mAggregationType != ValueMetric::AVG) {
+                bucket.values.push_back(interval.value);
+            } else {
+                double sum = interval.value.type == LONG ? (double)interval.value.long_value
+                                                         : interval.value.double_value;
+                bucket.values.push_back(Value((double)sum / interval.sampleSize));
+            }
+        }
+    }
+    return bucket;
+}
+
+void ValueMetricProducer::initCurrentSlicedBucket() {
+    for (auto it = mCurrentSlicedBucket.begin(); it != mCurrentSlicedBucket.end();) {
+        bool obsolete = true;
+        for (auto& interval : it->second) {
+            interval.hasValue = false;
+            interval.sampleSize = 0;
+            if (interval.seenNewData) {
+                obsolete = false;
+            }
+            interval.seenNewData = false;
+        }
+
+        if (obsolete) {
+            it = mCurrentSlicedBucket.erase(it);
+        } else {
+            it++;
+        }
+    }
+}
+
+void ValueMetricProducer::appendToFullBucket(int64_t eventTimeNs, int64_t fullBucketEndTimeNs) {
     if (eventTimeNs > fullBucketEndTimeNs) {  // If full bucket, send to anomaly tracker.
         // Accumulate partial buckets with current value and then send to anomaly tracker.
         if (mCurrentFullBucket.size() > 0) {
@@ -751,24 +819,6 @@
             mCurrentFullBucket[slice.first] += slice.second[0].value.long_value;
         }
     }
-
-    for (auto it = mCurrentSlicedBucket.begin(); it != mCurrentSlicedBucket.end();) {
-        bool obsolete = true;
-        for (auto& interval : it->second) {
-            interval.hasValue = false;
-            interval.sampleSize = 0;
-            if (interval.seenNewData) {
-                obsolete = false;
-            }
-            interval.seenNewData = false;
-        }
-
-        if (obsolete) {
-            it = mCurrentSlicedBucket.erase(it);
-        } else {
-            it++;
-        }
-    }
 }
 
 size_t ValueMetricProducer::byteSizeLocked() const {
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index a8dfc5b..d1c2315 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -51,7 +51,8 @@
     virtual ~ValueMetricProducer();
 
     // Process data pulled on bucket boundary.
-    void onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& data) override;
+    void onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& data,
+                      bool pullSuccess, int64_t originalPullTimeNs) override;
 
     // ValueMetric needs special logic if it's a pulled atom.
     void notifyAppUpgrade(const int64_t& eventTimeNs, const string& apk, const int uid,
@@ -60,6 +61,7 @@
         if (!mSplitBucketForAppUpgrade) {
             return;
         }
+        flushIfNeededLocked(eventTimeNs - 1);
         if (mIsPulled && mCondition) {
             pullAndMatchEventsLocked(eventTimeNs - 1);
         }
@@ -102,6 +104,9 @@
     // Calculate previous bucket end time based on current time.
     int64_t calcPreviousBucketEndTime(const int64_t currentTimeNs);
 
+    // Mark the data as invalid.
+    void invalidateCurrentBucket();
+
     const int mWhatMatcherIndex;
 
     sp<EventMatcherWizard> mEventMatcherWizard;
@@ -111,6 +116,9 @@
     // Value fields for matching.
     std::vector<Matcher> mFieldMatchers;
 
+    // Value fields for matching.
+    std::set<MetricDimensionKey> mMatchedMetricDimensionKeys;
+
     // tagId for pulled data. -1 if this is not pulled
     const int mPullTagId;
 
@@ -155,6 +163,14 @@
 
     void pullAndMatchEventsLocked(const int64_t timestampNs);
 
+    void accumulateEvents(const std::vector<std::shared_ptr<LogEvent>>& allData, 
+                          int64_t originalPullTimeNs, int64_t eventElapsedTimeNs);
+
+    ValueBucket buildPartialBucket(int64_t bucketEndTime,
+                                   const std::vector<Interval>& intervals);
+    void initCurrentSlicedBucket();
+    void appendToFullBucket(int64_t eventTimeNs, int64_t fullBucketEndTimeNs);
+
     // Reset diff base and mHasGlobalBase
     void resetBase();
 
@@ -186,6 +202,12 @@
     // diff against.
     bool mHasGlobalBase;
 
+    // Invalid bucket. There was a problem in collecting data in the current bucket so we cannot
+    // trust any of the data in this bucket.
+    //
+    // For instance, one pull failed.
+    bool mCurrentBucketIsInvalid;
+
     const int64_t mMaxPullDelayNs;
 
     const bool mSplitBucketForAppUpgrade;
@@ -197,6 +219,7 @@
     FRIEND_TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition);
     FRIEND_TEST(ValueMetricProducerTest, TestPushedEventsWithUpgrade);
     FRIEND_TEST(ValueMetricProducerTest, TestPulledValueWithUpgrade);
+    FRIEND_TEST(ValueMetricProducerTest, TestPartialBucketCreated);
     FRIEND_TEST(ValueMetricProducerTest, TestPulledValueWithUpgradeWhileConditionFalse);
     FRIEND_TEST(ValueMetricProducerTest, TestPulledWithAppUpgradeDisabled);
     FRIEND_TEST(ValueMetricProducerTest, TestPushedEventsWithoutCondition);
@@ -216,8 +239,19 @@
     FRIEND_TEST(ValueMetricProducerTest, TestUseZeroDefaultBase);
     FRIEND_TEST(ValueMetricProducerTest, TestUseZeroDefaultBaseWithPullFailures);
     FRIEND_TEST(ValueMetricProducerTest, TestTrimUnusedDimensionKey);
-    FRIEND_TEST(ValueMetricProducerTest, TestResetBaseOnPullFail);
+    FRIEND_TEST(ValueMetricProducerTest, TestResetBaseOnPullFailBeforeConditionChange);
+    FRIEND_TEST(ValueMetricProducerTest, TestResetBaseOnPullFailAfterConditionChange);
+    FRIEND_TEST(ValueMetricProducerTest, TestResetBaseOnPullFailAfterConditionChange_EndOfBucket);
     FRIEND_TEST(ValueMetricProducerTest, TestResetBaseOnPullTooLate);
+    FRIEND_TEST(ValueMetricProducerTest, TestInvalidBucketWhenOneConditionFailed);
+    FRIEND_TEST(ValueMetricProducerTest, TestInvalidBucketWhenInitialPullFailed);
+    FRIEND_TEST(ValueMetricProducerTest, TestInvalidBucketWhenLastPullFailed);
+    FRIEND_TEST(ValueMetricProducerTest, TestResetBaseOnPullDelayExceeded);
+    FRIEND_TEST(ValueMetricProducerTest, TestBaseSetOnConditionChange);
+    FRIEND_TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onDataPulled);
+    FRIEND_TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onConditionChanged);
+    FRIEND_TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onBucketBoundary);
+    FRIEND_TEST(ValueMetricProducerTest, TestPartialResetOnBucketBoundaries);
 };
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp
index 180a1ae..463b5a0 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp
@@ -725,6 +725,8 @@
             ALOGE("Invalid metric tracker index.");
             return false;
         }
+        allMetricProducers[metricTrackerIndex]->setActivationType(
+                metric_activation.activation_type());
         metricsWithActivation.push_back(metricTrackerIndex);
         for (int j = 0; j < metric_activation.event_activation_size(); ++j) {
             const EventActivation& activation = metric_activation.event_activation(j);
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
index cca09ac..6a07a3f 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -417,6 +417,10 @@
       optional int64 skipped_forward_buckets = 4;
       optional int64 bad_value_type = 5;
       optional int64 condition_change_in_next_bucket = 6;
+      optional int64 invalidated_bucket = 7;
+      optional int64 bucket_dropped = 8;
+      optional int64 min_bucket_boundary_delay_ns = 9;
+      optional int64 max_bucket_boundary_delay_ns = 10;
     }
     repeated AtomMetricStats atom_metric_stats = 17;
 
diff --git a/cmds/statsd/src/stats_log_util.cpp b/cmds/statsd/src/stats_log_util.cpp
index 9c9985e..aa8cfc5 100644
--- a/cmds/statsd/src/stats_log_util.cpp
+++ b/cmds/statsd/src/stats_log_util.cpp
@@ -78,6 +78,10 @@
 const int FIELD_ID_SKIPPED_FORWARD_BUCKETS = 4;
 const int FIELD_ID_BAD_VALUE_TYPE = 5;
 const int FIELD_ID_CONDITION_CHANGE_IN_NEXT_BUCKET = 6;
+const int FIELD_ID_INVALIDATED_BUCKET = 7;
+const int FIELD_ID_BUCKET_DROPPED = 8;
+const int FIELD_ID_MIN_BUCKET_BOUNDARY_DELAY_NS = 9;
+const int FIELD_ID_MAX_BUCKET_BOUNDARY_DELAY_NS = 10;
 
 namespace {
 
@@ -494,6 +498,14 @@
                        (long long)pair.second.badValueType);
     protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_CONDITION_CHANGE_IN_NEXT_BUCKET,
                        (long long)pair.second.conditionChangeInNextBucket);
+    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_INVALIDATED_BUCKET,
+                       (long long)pair.second.invalidatedBucket);
+    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_BUCKET_DROPPED,
+                       (long long)pair.second.bucketDropped);
+    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_MIN_BUCKET_BOUNDARY_DELAY_NS,
+                       (long long)pair.second.minBucketBoundaryDelayNs);
+    protoOutput->write(FIELD_TYPE_INT64 | FIELD_ID_MAX_BUCKET_BOUNDARY_DELAY_NS,
+                       (long long)pair.second.maxBucketBoundaryDelayNs);
     protoOutput->end(token);
 }
 
diff --git a/cmds/statsd/src/statsd_config.proto b/cmds/statsd/src/statsd_config.proto
index 9d3a669..5c6d548 100644
--- a/cmds/statsd/src/statsd_config.proto
+++ b/cmds/statsd/src/statsd_config.proto
@@ -379,6 +379,13 @@
 message MetricActivation {
   optional int64 metric_id = 1;
 
+  enum ActivationType {
+      UNKNOWN = 0;
+      ACTIVATE_IMMEDIATELY = 1;
+      ACTIVATE_ON_BOOT = 2;
+  }
+  optional ActivationType activation_type = 3;
+
   repeated EventActivation event_activation = 2;
 }
 
diff --git a/cmds/statsd/src/subscriber/IncidentdReporter.cpp b/cmds/statsd/src/subscriber/IncidentdReporter.cpp
index 6e4b2c8..42cac0c 100644
--- a/cmds/statsd/src/subscriber/IncidentdReporter.cpp
+++ b/cmds/statsd/src/subscriber/IncidentdReporter.cpp
@@ -17,32 +17,67 @@
 #include "Log.h"
 
 #include "IncidentdReporter.h"
-#include "frameworks/base/libs/incident/proto/android/os/header.pb.h"
 
 #include <android/os/IIncidentManager.h>
 #include <android/os/IncidentReportArgs.h>
+#include <android/util/ProtoOutputStream.h>
 #include <binder/IBinder.h>
 #include <binder/IServiceManager.h>
 
+#include <vector>
+
 namespace android {
 namespace os {
 namespace statsd {
 
+using android::util::ProtoOutputStream;
+using std::vector;
+
+using util::FIELD_TYPE_MESSAGE;
+using util::FIELD_TYPE_INT32;
+using util::FIELD_TYPE_INT64;
+
+// field ids in IncidentHeaderProto
+const int FIELD_ID_ALERT_ID = 1;
+const int FIELD_ID_CONFIG_KEY = 3;
+const int FIELD_ID_CONFIG_KEY_UID = 1;
+const int FIELD_ID_CONFIG_KEY_ID = 2;
+
+namespace {
+void getProtoData(const int64_t& rule_id, const ConfigKey& configKey, vector<uint8_t>* protoData) {
+    ProtoOutputStream headerProto;
+    headerProto.write(FIELD_TYPE_INT64 | FIELD_ID_ALERT_ID, (long long)rule_id);
+    uint64_t token =
+            headerProto.start(FIELD_TYPE_MESSAGE | FIELD_ID_CONFIG_KEY);
+    headerProto.write(FIELD_TYPE_INT32 | FIELD_ID_CONFIG_KEY_UID, configKey.GetUid());
+    headerProto.write(FIELD_TYPE_INT64 | FIELD_ID_CONFIG_KEY_ID, (long long)configKey.GetId());
+    headerProto.end(token);
+
+    protoData->resize(headerProto.size());
+    size_t pos = 0;
+    auto iter = headerProto.data();
+    while (iter.readBuffer() != NULL) {
+        size_t toRead = iter.currentToRead();
+        std::memcpy(&((*protoData)[pos]), iter.readBuffer(), toRead);
+        pos += toRead;
+        iter.rp()->move(toRead);
+    }
+}
+}  // namespace
+
 bool GenerateIncidentReport(const IncidentdDetails& config, const int64_t& rule_id,
                             const ConfigKey& configKey) {
     if (config.section_size() == 0) {
         VLOG("The alert %lld contains zero section in config(%d,%lld)", (unsigned long long)rule_id,
-            configKey.GetUid(), (long long) configKey.GetId());
+             configKey.GetUid(), (long long)configKey.GetId());
         return false;
     }
 
     IncidentReportArgs incidentReport;
 
-    android::os::IncidentHeaderProto header;
-    header.set_alert_id(rule_id);
-    header.mutable_config_key()->set_uid(configKey.GetUid());
-    header.mutable_config_key()->set_id(configKey.GetId());
-    incidentReport.addHeader(header);
+    vector<uint8_t> protoData;
+    getProtoData(rule_id, configKey, &protoData);
+    incidentReport.addHeader(protoData);
 
     for (int i = 0; i < config.section_size(); i++) {
         incidentReport.addSection(config.section(i));
diff --git a/cmds/statsd/statsd.rc b/cmds/statsd/statsd.rc
index cbf2a8d..e0cbd5d 100644
--- a/cmds/statsd/statsd.rc
+++ b/cmds/statsd/statsd.rc
@@ -26,3 +26,4 @@
     # Create directory for statsd
     mkdir /data/misc/stats-data/ 0770 statsd system
     mkdir /data/misc/stats-service/ 0770 statsd system
+    mkdir /data/misc/stats-active-metric/ 0770 statsd system
diff --git a/cmds/statsd/tests/StatsLogProcessor_test.cpp b/cmds/statsd/tests/StatsLogProcessor_test.cpp
index d52be44..60df165 100644
--- a/cmds/statsd/tests/StatsLogProcessor_test.cpp
+++ b/cmds/statsd/tests/StatsLogProcessor_test.cpp
@@ -286,6 +286,415 @@
     EXPECT_TRUE(noData);
 }
 
+TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead) {
+    int uid = 1111;
+
+    // Setup a simple config, no activation
+    StatsdConfig config1;
+    config1.set_id(12341);
+    config1.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
+    auto wakelockAcquireMatcher = CreateAcquireWakelockAtomMatcher();
+    *config1.add_atom_matcher() = wakelockAcquireMatcher;
+
+    long metricId1 = 1234561;
+    long metricId2 = 1234562;
+    auto countMetric1 = config1.add_count_metric();
+    countMetric1->set_id(metricId1);
+    countMetric1->set_what(wakelockAcquireMatcher.id());
+    countMetric1->set_bucket(FIVE_MINUTES);
+
+    auto countMetric2 = config1.add_count_metric();
+    countMetric2->set_id(metricId2);
+    countMetric2->set_what(wakelockAcquireMatcher.id());
+    countMetric2->set_bucket(FIVE_MINUTES);
+
+    ConfigKey cfgKey1(uid, 12341);
+    long timeBase1 = 1;
+    sp<StatsLogProcessor> processor =
+            CreateStatsLogProcessor(timeBase1, timeBase1, config1, cfgKey1);
+
+    // Add another config, with two metrics, one with activation
+    StatsdConfig config2;
+    config2.set_id(12342);
+    config2.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
+    *config2.add_atom_matcher() = wakelockAcquireMatcher;
+
+    long metricId3 = 1234561;
+    long metricId4 = 1234562;
+
+    auto countMetric3 = config2.add_count_metric();
+    countMetric3->set_id(metricId3);
+    countMetric3->set_what(wakelockAcquireMatcher.id());
+    countMetric3->set_bucket(FIVE_MINUTES);
+
+    auto countMetric4 = config2.add_count_metric();
+    countMetric4->set_id(metricId4);
+    countMetric4->set_what(wakelockAcquireMatcher.id());
+    countMetric4->set_bucket(FIVE_MINUTES);
+
+    auto metric3Activation = config2.add_metric_activation();
+    metric3Activation->set_metric_id(metricId3);
+    auto metric3ActivationTrigger = metric3Activation->add_event_activation();
+    metric3ActivationTrigger->set_atom_matcher_id(wakelockAcquireMatcher.id());
+    metric3ActivationTrigger->set_ttl_seconds(100);
+
+    ConfigKey cfgKey2(uid, 12342);
+
+    // Add another config, with two metrics, both with activations
+    StatsdConfig config3;
+    config3.set_id(12342);
+    config3.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
+    *config3.add_atom_matcher() = wakelockAcquireMatcher;
+
+    long metricId5 = 1234565;
+    long metricId6 = 1234566;
+    auto countMetric5 = config3.add_count_metric();
+    countMetric5->set_id(metricId5);
+    countMetric5->set_what(wakelockAcquireMatcher.id());
+    countMetric5->set_bucket(FIVE_MINUTES);
+
+    auto countMetric6 = config3.add_count_metric();
+    countMetric6->set_id(metricId6);
+    countMetric6->set_what(wakelockAcquireMatcher.id());
+    countMetric6->set_bucket(FIVE_MINUTES);
+
+    auto metric5Activation = config3.add_metric_activation();
+    metric5Activation->set_metric_id(metricId5);
+    auto metric5ActivationTrigger = metric5Activation->add_event_activation();
+    metric5ActivationTrigger->set_atom_matcher_id(wakelockAcquireMatcher.id());
+    metric5ActivationTrigger->set_ttl_seconds(100);
+
+    auto metric6Activation = config3.add_metric_activation();
+    metric6Activation->set_metric_id(metricId6);
+    auto metric6ActivationTrigger = metric6Activation->add_event_activation();
+    metric6ActivationTrigger->set_atom_matcher_id(wakelockAcquireMatcher.id());
+    metric6ActivationTrigger->set_ttl_seconds(200);
+
+    ConfigKey cfgKey3(uid, 12343);
+
+    processor->OnConfigUpdated(2, cfgKey2, config2);
+    processor->OnConfigUpdated(3, cfgKey3, config3);
+
+    EXPECT_EQ(3, processor->mMetricsManagers.size());
+    auto it = processor->mMetricsManagers.find(cfgKey1);
+    EXPECT_TRUE(it != processor->mMetricsManagers.end());
+    auto& metricsManager1 = it->second;
+    EXPECT_TRUE(metricsManager1->isActive());
+
+    auto metricIt = metricsManager1->mAllMetricProducers.begin();
+    for (; metricIt != metricsManager1->mAllMetricProducers.end(); metricIt++) {
+        if ((*metricIt)->getMetricId() == metricId1) {
+            break;
+        }
+    }
+    EXPECT_TRUE(metricIt != metricsManager1->mAllMetricProducers.end());
+    auto& metricProducer1 = *metricIt;
+    EXPECT_TRUE(metricProducer1->isActive());
+
+    metricIt = metricsManager1->mAllMetricProducers.begin();
+    for (; metricIt != metricsManager1->mAllMetricProducers.end(); metricIt++) {
+        if ((*metricIt)->getMetricId() == metricId2) {
+            break;
+        }
+    }
+    EXPECT_TRUE(metricIt != metricsManager1->mAllMetricProducers.end());
+    auto& metricProducer2 = *metricIt;
+    EXPECT_TRUE(metricProducer2->isActive());
+
+    it = processor->mMetricsManagers.find(cfgKey2);
+    EXPECT_TRUE(it != processor->mMetricsManagers.end());
+    auto& metricsManager2 = it->second;
+    EXPECT_TRUE(metricsManager2->isActive());
+
+    metricIt = metricsManager2->mAllMetricProducers.begin();
+    for (; metricIt != metricsManager2->mAllMetricProducers.end(); metricIt++) {
+        if ((*metricIt)->getMetricId() == metricId3) {
+            break;
+        }
+    }
+    EXPECT_TRUE(metricIt != metricsManager2->mAllMetricProducers.end());
+    auto& metricProducer3 = *metricIt;
+    EXPECT_FALSE(metricProducer3->isActive());
+
+    metricIt = metricsManager2->mAllMetricProducers.begin();
+    for (; metricIt != metricsManager2->mAllMetricProducers.end(); metricIt++) {
+        if ((*metricIt)->getMetricId() == metricId4) {
+            break;
+        }
+    }
+    EXPECT_TRUE(metricIt != metricsManager2->mAllMetricProducers.end());
+    auto& metricProducer4 = *metricIt;
+    EXPECT_TRUE(metricProducer4->isActive());
+
+    it = processor->mMetricsManagers.find(cfgKey3);
+    EXPECT_TRUE(it != processor->mMetricsManagers.end());
+    auto& metricsManager3 = it->second;
+    EXPECT_FALSE(metricsManager3->isActive());
+
+    metricIt = metricsManager3->mAllMetricProducers.begin();
+    for (; metricIt != metricsManager2->mAllMetricProducers.end(); metricIt++) {
+        if ((*metricIt)->getMetricId() == metricId5) {
+            break;
+        }
+    }
+    EXPECT_TRUE(metricIt != metricsManager3->mAllMetricProducers.end());
+    auto& metricProducer5 = *metricIt;
+    EXPECT_FALSE(metricProducer5->isActive());
+
+    metricIt = metricsManager3->mAllMetricProducers.begin();
+    for (; metricIt != metricsManager3->mAllMetricProducers.end(); metricIt++) {
+        if ((*metricIt)->getMetricId() == metricId6) {
+            break;
+        }
+    }
+    EXPECT_TRUE(metricIt != metricsManager3->mAllMetricProducers.end());
+    auto& metricProducer6 = *metricIt;
+    EXPECT_FALSE(metricProducer6->isActive());
+
+    std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1")};
+    auto event = CreateAcquireWakelockEvent(attributions1, "wl1", 100 + timeBase1);
+    processor->OnLogEvent(event.get());
+
+    int64_t shutDownTime = timeBase1 + 100 * NS_PER_SEC;
+    EXPECT_TRUE(metricProducer3->isActive());
+    int64_t ttl3 = metricProducer3->getRemainingTtlNs(shutDownTime);
+    EXPECT_EQ(100, ttl3);
+    EXPECT_TRUE(metricProducer5->isActive());
+    int64_t ttl5 = metricProducer5->getRemainingTtlNs(shutDownTime);
+    EXPECT_EQ(100, ttl5);
+    EXPECT_TRUE(metricProducer6->isActive());
+    int64_t ttl6 = metricProducer6->getRemainingTtlNs(shutDownTime);
+    EXPECT_EQ(100 + 100 * NS_PER_SEC, ttl6);
+
+    processor->WriteMetricsActivationToDisk(timeBase1 + 100 * NS_PER_SEC);
+
+    long timeBase2 = 1000;
+    sp<StatsLogProcessor> processor2 =
+            CreateStatsLogProcessor(timeBase2, timeBase2, config1, cfgKey1);
+    processor2->OnConfigUpdated(timeBase2, cfgKey2, config2);
+    processor2->OnConfigUpdated(timeBase2, cfgKey3, config3);
+
+    EXPECT_EQ(3, processor2->mMetricsManagers.size());
+    it = processor2->mMetricsManagers.find(cfgKey1);
+    EXPECT_TRUE(it != processor2->mMetricsManagers.end());
+    auto& metricsManager1001 = it->second;
+    EXPECT_TRUE(metricsManager1001->isActive());
+
+    metricIt = metricsManager1001->mAllMetricProducers.begin();
+    for (; metricIt != metricsManager1001->mAllMetricProducers.end(); metricIt++) {
+        if ((*metricIt)->getMetricId() == metricId1) {
+            break;
+        }
+    }
+    EXPECT_TRUE(metricIt != metricsManager1001->mAllMetricProducers.end());
+    auto& metricProducer1001 = *metricIt;
+    EXPECT_TRUE(metricProducer1001->isActive());
+
+    metricIt = metricsManager1001->mAllMetricProducers.begin();
+    for (; metricIt != metricsManager1001->mAllMetricProducers.end(); metricIt++) {
+        if ((*metricIt)->getMetricId() == metricId2) {
+            break;
+        }
+    }
+    EXPECT_TRUE(metricIt != metricsManager1001->mAllMetricProducers.end());
+    auto& metricProducer1002 = *metricIt;
+    EXPECT_TRUE(metricProducer1002->isActive());
+
+    it = processor2->mMetricsManagers.find(cfgKey2);
+    EXPECT_TRUE(it != processor2->mMetricsManagers.end());
+    auto& metricsManager1002 = it->second;
+    EXPECT_TRUE(metricsManager1002->isActive());
+
+    metricIt = metricsManager1002->mAllMetricProducers.begin();
+    for (; metricIt != metricsManager1002->mAllMetricProducers.end(); metricIt++) {
+        if ((*metricIt)->getMetricId() == metricId3) {
+            break;
+        }
+    }
+    EXPECT_TRUE(metricIt != metricsManager1002->mAllMetricProducers.end());
+    auto& metricProducer1003 = *metricIt;
+    EXPECT_FALSE(metricProducer1003->isActive());
+
+    metricIt = metricsManager1002->mAllMetricProducers.begin();
+    for (; metricIt != metricsManager1002->mAllMetricProducers.end(); metricIt++) {
+        if ((*metricIt)->getMetricId() == metricId4) {
+            break;
+        }
+    }
+    EXPECT_TRUE(metricIt != metricsManager1002->mAllMetricProducers.end());
+    auto& metricProducer1004 = *metricIt;
+    EXPECT_TRUE(metricProducer1004->isActive());
+
+    it = processor2->mMetricsManagers.find(cfgKey3);
+    EXPECT_TRUE(it != processor2->mMetricsManagers.end());
+    auto& metricsManager1003 = it->second;
+    EXPECT_FALSE(metricsManager1003->isActive());
+    EXPECT_EQ(2, metricsManager1003->mAllMetricProducers.size());
+
+    metricIt = metricsManager1003->mAllMetricProducers.begin();
+    for (; metricIt != metricsManager1002->mAllMetricProducers.end(); metricIt++) {
+        if ((*metricIt)->getMetricId() == metricId5) {
+            break;
+        }
+    }
+    EXPECT_TRUE(metricIt != metricsManager1003->mAllMetricProducers.end());
+    auto& metricProducer1005 = *metricIt;
+    EXPECT_FALSE(metricProducer1005->isActive());
+
+    metricIt = metricsManager1003->mAllMetricProducers.begin();
+    for (; metricIt != metricsManager1003->mAllMetricProducers.end(); metricIt++) {
+        if ((*metricIt)->getMetricId() == metricId6) {
+            break;
+        }
+    }
+    EXPECT_TRUE(metricIt != metricsManager1003->mAllMetricProducers.end());
+    auto& metricProducer1006 = *metricIt;
+    EXPECT_FALSE(metricProducer1006->isActive());
+
+    EXPECT_FALSE(metricProducer1003->isActive());
+    const auto& activation1003 = metricProducer1003->mEventActivationMap.begin()->second;
+    EXPECT_EQ(100 * NS_PER_SEC, activation1003.ttl_ns);
+    EXPECT_EQ(0, activation1003.activation_ns);
+    EXPECT_FALSE(metricProducer1005->isActive());
+    const auto& activation1005 = metricProducer1005->mEventActivationMap.begin()->second;
+    EXPECT_EQ(100 * NS_PER_SEC, activation1005.ttl_ns);
+    EXPECT_EQ(0, activation1005.activation_ns);
+    EXPECT_FALSE(metricProducer1006->isActive());
+    const auto& activation1006 = metricProducer1006->mEventActivationMap.begin()->second;
+    EXPECT_EQ(200 * NS_PER_SEC, activation1006.ttl_ns);
+    EXPECT_EQ(0, activation1006.activation_ns);
+
+    processor2->LoadMetricsActivationFromDisk();
+
+    EXPECT_TRUE(metricProducer1003->isActive());
+    EXPECT_EQ(timeBase2 + ttl3 - activation1003.ttl_ns, activation1003.activation_ns);
+    EXPECT_TRUE(metricProducer1005->isActive());
+    EXPECT_EQ(timeBase2 + ttl5 - activation1005.ttl_ns, activation1005.activation_ns);
+    EXPECT_TRUE(metricProducer1006->isActive());
+    EXPECT_EQ(timeBase2 + ttl6 - activation1006.ttl_ns, activation1003.activation_ns);
+}
+
+TEST(StatsLogProcessorTest, TestActivationOnBoot) {
+    int uid = 1111;
+
+    // Setup a simple config, no activation
+    StatsdConfig config1;
+    config1.set_id(12341);
+    config1.add_allowed_log_source("AID_ROOT");  // LogEvent defaults to UID of root.
+    auto wakelockAcquireMatcher = CreateAcquireWakelockAtomMatcher();
+    *config1.add_atom_matcher() = wakelockAcquireMatcher;
+
+    long metricId1 = 1234561;
+    long metricId2 = 1234562;
+    auto countMetric1 = config1.add_count_metric();
+    countMetric1->set_id(metricId1);
+    countMetric1->set_what(wakelockAcquireMatcher.id());
+    countMetric1->set_bucket(FIVE_MINUTES);
+
+    auto countMetric2 = config1.add_count_metric();
+    countMetric2->set_id(metricId2);
+    countMetric2->set_what(wakelockAcquireMatcher.id());
+    countMetric2->set_bucket(FIVE_MINUTES);
+
+    auto metric1Activation = config1.add_metric_activation();
+    metric1Activation->set_metric_id(metricId1);
+    metric1Activation->set_activation_type(MetricActivation::ACTIVATE_ON_BOOT);
+    auto metric1ActivationTrigger = metric1Activation->add_event_activation();
+    metric1ActivationTrigger->set_atom_matcher_id(wakelockAcquireMatcher.id());
+    metric1ActivationTrigger->set_ttl_seconds(100);
+
+    ConfigKey cfgKey1(uid, 12341);
+    long timeBase1 = 1;
+    sp<StatsLogProcessor> processor =
+            CreateStatsLogProcessor(timeBase1, timeBase1, config1, cfgKey1);
+
+    EXPECT_EQ(1, processor->mMetricsManagers.size());
+    auto it = processor->mMetricsManagers.find(cfgKey1);
+    EXPECT_TRUE(it != processor->mMetricsManagers.end());
+    auto& metricsManager1 = it->second;
+    EXPECT_TRUE(metricsManager1->isActive());
+
+    auto metricIt = metricsManager1->mAllMetricProducers.begin();
+    for (; metricIt != metricsManager1->mAllMetricProducers.end(); metricIt++) {
+        if ((*metricIt)->getMetricId() == metricId1) {
+            break;
+        }
+    }
+    EXPECT_TRUE(metricIt != metricsManager1->mAllMetricProducers.end());
+    auto& metricProducer1 = *metricIt;
+    EXPECT_FALSE(metricProducer1->isActive());
+
+    metricIt = metricsManager1->mAllMetricProducers.begin();
+    for (; metricIt != metricsManager1->mAllMetricProducers.end(); metricIt++) {
+        if ((*metricIt)->getMetricId() == metricId2) {
+            break;
+        }
+    }
+    EXPECT_TRUE(metricIt != metricsManager1->mAllMetricProducers.end());
+    auto& metricProducer2 = *metricIt;
+    EXPECT_TRUE(metricProducer2->isActive());
+
+    const auto& activation1 = metricProducer1->mEventActivationMap.begin()->second;
+    EXPECT_EQ(100 * NS_PER_SEC, activation1.ttl_ns);
+    EXPECT_EQ(0, activation1.activation_ns);
+    EXPECT_EQ(kNotActive, activation1.state);
+
+    std::vector<AttributionNodeInternal> attributions1 = {CreateAttribution(111, "App1")};
+    auto event = CreateAcquireWakelockEvent(attributions1, "wl1", 100 + timeBase1);
+    processor->OnLogEvent(event.get());
+
+    EXPECT_FALSE(metricProducer1->isActive());
+    EXPECT_EQ(0, activation1.activation_ns);
+    EXPECT_EQ(kActiveOnBoot, activation1.state);
+
+    int64_t shutDownTime = timeBase1 + 100 * NS_PER_SEC;
+
+    processor->WriteMetricsActivationToDisk(shutDownTime);
+    EXPECT_TRUE(metricProducer1->isActive());
+    int64_t ttl1 = metricProducer1->getRemainingTtlNs(shutDownTime);
+    EXPECT_EQ(100 * NS_PER_SEC, ttl1);
+
+    long timeBase2 = 1000;
+    sp<StatsLogProcessor> processor2 =
+            CreateStatsLogProcessor(timeBase2, timeBase2, config1, cfgKey1);
+
+    EXPECT_EQ(1, processor2->mMetricsManagers.size());
+    it = processor2->mMetricsManagers.find(cfgKey1);
+    EXPECT_TRUE(it != processor2->mMetricsManagers.end());
+    auto& metricsManager1001 = it->second;
+    EXPECT_TRUE(metricsManager1001->isActive());
+
+    metricIt = metricsManager1001->mAllMetricProducers.begin();
+    for (; metricIt != metricsManager1001->mAllMetricProducers.end(); metricIt++) {
+        if ((*metricIt)->getMetricId() == metricId1) {
+            break;
+        }
+    }
+    EXPECT_TRUE(metricIt != metricsManager1001->mAllMetricProducers.end());
+    auto& metricProducer1001 = *metricIt;
+    EXPECT_FALSE(metricProducer1001->isActive());
+
+    metricIt = metricsManager1001->mAllMetricProducers.begin();
+    for (; metricIt != metricsManager1001->mAllMetricProducers.end(); metricIt++) {
+        if ((*metricIt)->getMetricId() == metricId2) {
+            break;
+        }
+    }
+    EXPECT_TRUE(metricIt != metricsManager1001->mAllMetricProducers.end());
+    auto& metricProducer1002 = *metricIt;
+    EXPECT_TRUE(metricProducer1002->isActive());
+
+    const auto& activation1001 = metricProducer1001->mEventActivationMap.begin()->second;
+    EXPECT_EQ(100 * NS_PER_SEC, activation1001.ttl_ns);
+    EXPECT_EQ(0, activation1001.activation_ns);
+    EXPECT_EQ(kNotActive, activation1001.state);
+
+    processor2->LoadMetricsActivationFromDisk();
+
+    EXPECT_TRUE(metricProducer1001->isActive());
+    EXPECT_EQ(timeBase2 + ttl1 - activation1001.ttl_ns, activation1001.activation_ns);
+}
+
 #else
 GTEST_LOG_(INFO) << "This test does nothing.\n";
 #endif
diff --git a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
index 0ffbb54..6286823 100644
--- a/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/GaugeMetricProducer_test.cpp
@@ -133,7 +133,7 @@
     event->init();
     allData.push_back(event);
 
-    gaugeProducer.onDataPulled(allData);
+    gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
     EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
     auto it = gaugeProducer.mCurrentSlicedBucket->begin()->second.front().mFields->begin();
     EXPECT_EQ(INT, it->mValue.getType());
@@ -151,7 +151,7 @@
     event2->write(25);
     event2->init();
     allData.push_back(event2);
-    gaugeProducer.onDataPulled(allData);
+    gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
     EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
     it = gaugeProducer.mCurrentSlicedBucket->begin()->second.front().mFields->begin();
     EXPECT_EQ(INT, it->mValue.getType());
@@ -305,7 +305,7 @@
     event->write(1);
     event->init();
     allData.push_back(event);
-    gaugeProducer.onDataPulled(allData);
+    gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs);
     EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
     EXPECT_EQ(1, gaugeProducer.mCurrentSlicedBucket->begin()
                          ->second.front()
@@ -328,7 +328,7 @@
     event->write(3);
     event->init();
     allData.push_back(event);
-    gaugeProducer.onDataPulled(allData);
+    gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs + bucketSizeNs);
     EXPECT_EQ(2UL, gaugeProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
     EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
     EXPECT_EQ(3, gaugeProducer.mCurrentSlicedBucket->begin()
@@ -371,7 +371,7 @@
     event->write(1);
     event->init();
     allData.push_back(event);
-    gaugeProducer.onDataPulled(allData);
+    gaugeProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs);
     EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
     EXPECT_EQ(1, gaugeProducer.mCurrentSlicedBucket->begin()
                          ->second.front()
@@ -440,7 +440,7 @@
     event->write(110);
     event->init();
     allData.push_back(event);
-    gaugeProducer.onDataPulled(allData);
+    gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
 
     EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
     EXPECT_EQ(110, gaugeProducer.mCurrentSlicedBucket->begin()
@@ -541,7 +541,7 @@
     event->write(110);
     event->init();
     allData.push_back(event);
-    gaugeProducer.onDataPulled(allData);
+    gaugeProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
 
     EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
     EXPECT_EQ(1UL, gaugeProducer.mPastBuckets.size());
@@ -590,7 +590,7 @@
     event1->write(13);
     event1->init();
 
-    gaugeProducer.onDataPulled({event1});
+    gaugeProducer.onDataPulled({event1}, /** succeed */ true, bucketStartTimeNs);
     EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
     EXPECT_EQ(13L, gaugeProducer.mCurrentSlicedBucket->begin()
                            ->second.front()
@@ -604,7 +604,7 @@
     event2->write(15);
     event2->init();
 
-    gaugeProducer.onDataPulled({event2});
+    gaugeProducer.onDataPulled({event2}, /** succeed */ true, bucketStartTimeNs + bucketSizeNs);
     EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
     EXPECT_EQ(15L, gaugeProducer.mCurrentSlicedBucket->begin()
                            ->second.front()
@@ -619,7 +619,7 @@
     event3->write(26);
     event3->init();
 
-    gaugeProducer.onDataPulled({event3});
+    gaugeProducer.onDataPulled({event3}, /** succeed */ true, bucket2StartTimeNs + 2 * bucketSizeNs);
     EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
     EXPECT_EQ(26L, gaugeProducer.mCurrentSlicedBucket->begin()
                            ->second.front()
@@ -633,7 +633,7 @@
             std::make_shared<LogEvent>(tagId, bucketStartTimeNs + 3 * bucketSizeNs + 10);
     event4->write("some value");
     event4->init();
-    gaugeProducer.onDataPulled({event4});
+    gaugeProducer.onDataPulled({event4}, /** succeed */ true, bucketStartTimeNs + 3 * bucketSizeNs);
     EXPECT_EQ(1UL, gaugeProducer.mCurrentSlicedBucket->size());
     EXPECT_TRUE(gaugeProducer.mCurrentSlicedBucket->begin()->second.front().mFields->empty());
 }
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index c0648ee..ae3cdbc 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -160,16 +160,17 @@
     event->init();
     allData.push_back(event);
 
-    valueProducer.onDataPulled(allData);
+    valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
     // has one slice
     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
     ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
 
     EXPECT_EQ(true, curInterval.hasBase);
     EXPECT_EQ(11, curInterval.base.long_value);
-    EXPECT_EQ(true, curInterval.hasValue);
+    EXPECT_EQ(false, curInterval.hasValue);
     EXPECT_EQ(8, curInterval.value.long_value);
-    EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
+    EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
+    EXPECT_EQ(8, valueProducer.mPastBuckets.begin()->second[0].values[0].long_value);
 
     allData.clear();
     event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 1);
@@ -177,18 +178,19 @@
     event->write(23);
     event->init();
     allData.push_back(event);
-    valueProducer.onDataPulled(allData);
+    valueProducer.onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
     // has one slice
     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
     curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
 
     EXPECT_EQ(true, curInterval.hasBase);
     EXPECT_EQ(23, curInterval.base.long_value);
-    EXPECT_EQ(true, curInterval.hasValue);
+    EXPECT_EQ(false, curInterval.hasValue);
     EXPECT_EQ(12, curInterval.value.long_value);
     EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
-    EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
-    EXPECT_EQ(8, valueProducer.mPastBuckets.begin()->second.back().values[0].long_value);
+    EXPECT_EQ(2UL, valueProducer.mPastBuckets.begin()->second.size());
+    EXPECT_EQ(8, valueProducer.mPastBuckets.begin()->second[0].values[0].long_value);
+    EXPECT_EQ(12, valueProducer.mPastBuckets.begin()->second.back().values[0].long_value);
 
     allData.clear();
     event = make_shared<LogEvent>(tagId, bucket4StartTimeNs + 1);
@@ -196,17 +198,86 @@
     event->write(36);
     event->init();
     allData.push_back(event);
-    valueProducer.onDataPulled(allData);
+    valueProducer.onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
     curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
 
     EXPECT_EQ(true, curInterval.hasBase);
     EXPECT_EQ(36, curInterval.base.long_value);
-    EXPECT_EQ(true, curInterval.hasValue);
+    EXPECT_EQ(false, curInterval.hasValue);
     EXPECT_EQ(13, curInterval.value.long_value);
     EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
-    EXPECT_EQ(2UL, valueProducer.mPastBuckets.begin()->second.size());
-    EXPECT_EQ(12, valueProducer.mPastBuckets.begin()->second.back().values[0].long_value);
+    EXPECT_EQ(3UL, valueProducer.mPastBuckets.begin()->second.size());
+    EXPECT_EQ(8, valueProducer.mPastBuckets.begin()->second[0].values[0].long_value);
+    EXPECT_EQ(12, valueProducer.mPastBuckets.begin()->second[1].values[0].long_value);
+    EXPECT_EQ(13, valueProducer.mPastBuckets.begin()->second[2].values[0].long_value);
+}
+
+TEST(ValueMetricProducerTest, TestPartialBucketCreated) {
+    ValueMetric metric;
+    metric.set_id(metricId);
+    metric.set_bucket(ONE_MINUTE);
+    metric.mutable_value_field()->set_field(tagId);
+    metric.mutable_value_field()->add_child()->set_field(2);
+    metric.set_max_pull_delay_sec(INT_MAX);
+
+    UidMap uidMap;
+    SimpleAtomMatcher atomMatcher;
+    atomMatcher.set_atom_id(tagId);
+    sp<EventMatcherWizard> eventMatcherWizard =
+            new EventMatcherWizard({new SimpleLogMatchingTracker(
+                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
+    EXPECT_CALL(*pullerManager, Pull(tagId, _))
+            // Initialize bucket.
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 1);
+                event->write(tagId);
+                event->write(1);
+                event->init();
+                data->push_back(event);
+                return true;
+            }))
+            // Partial bucket.
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 10);
+                event->write(tagId);
+                event->write(5);
+                event->init();
+                data->push_back(event);
+                return true;
+            }));
+
+    ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+                                      logEventMatcherIndex, eventMatcherWizard, tagId,
+                                      bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+
+    // First bucket ends.
+    vector<shared_ptr<LogEvent>> allData;
+    allData.clear();
+    shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 10);
+    event->write(tagId);
+    event->write(2);
+    event->init();
+    allData.push_back(event);
+    valueProducer.onDataPulled(allData, /** success */ true, bucket2StartTimeNs);
+
+    // Partial buckets created in 2nd bucket.
+    valueProducer.notifyAppUpgrade(bucket2StartTimeNs + 2, "com.foo", 10000, 1);
+
+    // One full bucket and one partial bucket.
+    EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
+    vector<ValueBucket> buckets = valueProducer.mPastBuckets.begin()->second;
+    EXPECT_EQ(2UL, buckets.size());
+    // Full bucket (2 - 1)
+    EXPECT_EQ(1, buckets[0].values[0].long_value);
+    // Full bucket (5 - 3)
+    EXPECT_EQ(3, buckets[1].values[0].long_value);
 }
 
 /*
@@ -256,7 +327,7 @@
     event->init();
     allData.push_back(event);
 
-    valueProducer.onDataPulled(allData);
+    valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
     // has one slice
     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
     ValueMetricProducer::Interval curInterval =
@@ -264,9 +335,10 @@
 
     EXPECT_EQ(true, curInterval.hasBase);
     EXPECT_EQ(11, curInterval.base.long_value);
-    EXPECT_EQ(true, curInterval.hasValue);
+    EXPECT_EQ(false, curInterval.hasValue);
     EXPECT_EQ(8, curInterval.value.long_value);
-    EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
+    EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
+    EXPECT_EQ(8, valueProducer.mPastBuckets.begin()->second[0].values[0].long_value);
 
     allData.clear();
     event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 1);
@@ -274,17 +346,16 @@
     event->write(23);
     event->init();
     allData.push_back(event);
-    valueProducer.onDataPulled(allData);
-    // has one slice
-    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    valueProducer.onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
+    // No new data seen, so data has been cleared.
+    EXPECT_EQ(0UL, valueProducer.mCurrentSlicedBucket.size());
 
     EXPECT_EQ(true, curInterval.hasBase);
     EXPECT_EQ(11, curInterval.base.long_value);
-    // no events caused flush of bucket
-    EXPECT_EQ(true, curInterval.hasValue);
+    EXPECT_EQ(false, curInterval.hasValue);
     EXPECT_EQ(8, curInterval.value.long_value);
-    EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
+    EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
+    EXPECT_EQ(8, valueProducer.mPastBuckets.begin()->second[0].values[0].long_value);
 
     allData.clear();
     event = make_shared<LogEvent>(tagId, bucket4StartTimeNs + 1);
@@ -292,7 +363,7 @@
     event->write(36);
     event->init();
     allData.push_back(event);
-    valueProducer.onDataPulled(allData);
+    valueProducer.onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
     curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
 
@@ -341,7 +412,7 @@
     event->init();
     allData.push_back(event);
 
-    valueProducer.onDataPulled(allData);
+    valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
     // has one slice
     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
     ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
@@ -357,15 +428,16 @@
     event->write(10);
     event->init();
     allData.push_back(event);
-    valueProducer.onDataPulled(allData);
+    valueProducer.onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
     // has one slice
     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
     curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
     EXPECT_EQ(true, curInterval.hasBase);
     EXPECT_EQ(10, curInterval.base.long_value);
-    EXPECT_EQ(true, curInterval.hasValue);
+    EXPECT_EQ(false, curInterval.hasValue);
     EXPECT_EQ(10, curInterval.value.long_value);
-    EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
+    EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
+    EXPECT_EQ(10, valueProducer.mPastBuckets.begin()->second.back().values[0].long_value);
 
     allData.clear();
     event = make_shared<LogEvent>(tagId, bucket4StartTimeNs + 1);
@@ -373,16 +445,17 @@
     event->write(36);
     event->init();
     allData.push_back(event);
-    valueProducer.onDataPulled(allData);
+    valueProducer.onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
     curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
     EXPECT_EQ(true, curInterval.hasBase);
     EXPECT_EQ(36, curInterval.base.long_value);
-    EXPECT_EQ(true, curInterval.hasValue);
+    EXPECT_EQ(false, curInterval.hasValue);
     EXPECT_EQ(26, curInterval.value.long_value);
     EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
-    EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
-    EXPECT_EQ(10, valueProducer.mPastBuckets.begin()->second.back().values[0].long_value);
+    EXPECT_EQ(2UL, valueProducer.mPastBuckets.begin()->second.size());
+    EXPECT_EQ(10, valueProducer.mPastBuckets.begin()->second[0].values[0].long_value);
+    EXPECT_EQ(26, valueProducer.mPastBuckets.begin()->second[1].values[0].long_value);
 }
 
 /*
@@ -420,7 +493,7 @@
     event->init();
     allData.push_back(event);
 
-    valueProducer.onDataPulled(allData);
+    valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
     // has one slice
     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
     ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
@@ -436,7 +509,7 @@
     event->write(10);
     event->init();
     allData.push_back(event);
-    valueProducer.onDataPulled(allData);
+    valueProducer.onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
     // has one slice
     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
     curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
@@ -451,14 +524,15 @@
     event->write(36);
     event->init();
     allData.push_back(event);
-    valueProducer.onDataPulled(allData);
+    valueProducer.onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
     curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
     EXPECT_EQ(true, curInterval.hasBase);
     EXPECT_EQ(36, curInterval.base.long_value);
-    EXPECT_EQ(true, curInterval.hasValue);
+    EXPECT_EQ(false, curInterval.hasValue);
     EXPECT_EQ(26, curInterval.value.long_value);
-    EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
+    EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
+    EXPECT_EQ(26, valueProducer.mPastBuckets.begin()->second[0].values[0].long_value);
 }
 
 /*
@@ -525,16 +599,17 @@
     event->write(110);
     event->init();
     allData.push_back(event);
-    valueProducer.onDataPulled(allData);
+    valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
 
     // has one slice
     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
     curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
     EXPECT_EQ(true, curInterval.hasBase);
     EXPECT_EQ(110, curInterval.base.long_value);
-    EXPECT_EQ(true, curInterval.hasValue);
+    EXPECT_EQ(false, curInterval.hasValue);
     EXPECT_EQ(10, curInterval.value.long_value);
-    EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
+    EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
+    EXPECT_EQ(10, valueProducer.mPastBuckets.begin()->second[0].values[0].long_value);
 
     valueProducer.onConditionChanged(false, bucket2StartTimeNs + 1);
 
@@ -635,7 +710,7 @@
     event->init();
     allData.push_back(event);
 
-    valueProducer.onDataPulled(allData);
+    valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
 
     valueProducer.notifyAppUpgrade(bucket2StartTimeNs + 150, "ANY.APP", 1, 1);
@@ -650,9 +725,9 @@
     event->write(150);
     event->init();
     allData.push_back(event);
-    valueProducer.onDataPulled(allData);
-    EXPECT_EQ(1UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-    EXPECT_EQ(bucket2StartTimeNs + 150, valueProducer.mCurrentBucketStartTimeNs);
+    valueProducer.onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
+    EXPECT_EQ(2UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+    EXPECT_EQ(bucket3StartTimeNs, valueProducer.mCurrentBucketStartTimeNs);
     EXPECT_EQ(20L,
               valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].values[0].long_value);
 }
@@ -689,12 +764,12 @@
     event->init();
     allData.push_back(event);
 
-    valueProducer.onDataPulled(allData);
+    valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
 
     valueProducer.notifyAppUpgrade(bucket2StartTimeNs + 150, "ANY.APP", 1, 1);
     EXPECT_EQ(0UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-    EXPECT_EQ(bucketStartTimeNs, valueProducer.mCurrentBucketStartTimeNs);
+    EXPECT_EQ(bucket2StartTimeNs, valueProducer.mCurrentBucketStartTimeNs);
 }
 
 TEST(ValueMetricProducerTest, TestPulledValueWithUpgradeWhileConditionFalse) {
@@ -993,7 +1068,7 @@
     event->init();
     allData.push_back(event);
 
-    valueProducer.onDataPulled(allData);
+    valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
     // has one slice
     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
     ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
@@ -1011,16 +1086,16 @@
     event->write(23);
     event->init();
     allData.push_back(event);
-    valueProducer.onDataPulled(allData);
+    valueProducer.onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
     // has one slice
     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
     curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
     // tartUpdated:false sum:12
     EXPECT_EQ(true, curInterval.hasBase);
     EXPECT_EQ(23, curInterval.base.long_value);
-    EXPECT_EQ(true, curInterval.hasValue);
-    EXPECT_EQ(12, curInterval.value.long_value);
-    EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
+    EXPECT_EQ(false, curInterval.hasValue);
+    EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
+    EXPECT_EQ(12, valueProducer.mPastBuckets.begin()->second.back().values[0].long_value);
 
     // pull 3 come late.
     // The previous bucket gets closed with error. (Has start value 23, no ending)
@@ -1032,7 +1107,7 @@
     event->write(36);
     event->init();
     allData.push_back(event);
-    valueProducer.onDataPulled(allData);
+    valueProducer.onDataPulled(allData, /** succeed */ true, bucket6StartTimeNs);
     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
     curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
     // startUpdated:false sum:12
@@ -1120,7 +1195,7 @@
     event->write(110);
     event->init();
     allData.push_back(event);
-    valueProducer.onDataPulled(allData);
+    valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
 
     curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
     EXPECT_EQ(false, curInterval.hasBase);
@@ -1216,7 +1291,7 @@
     EXPECT_EQ(20, curInterval.value.long_value);
     EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
 
-    // Now the alarm is delivered, but it is considered late, it has no effect
+    // Now the alarm is delivered, but it is considered late, the bucket is invalidated.
     vector<shared_ptr<LogEvent>> allData;
     allData.clear();
     shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 50);
@@ -1224,10 +1299,10 @@
     event->write(110);
     event->init();
     allData.push_back(event);
-    valueProducer.onDataPulled(allData);
+    valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
 
     curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
-    EXPECT_EQ(true, curInterval.hasBase);
+    EXPECT_EQ(false, curInterval.hasBase);
     EXPECT_EQ(130, curInterval.base.long_value);
     EXPECT_EQ(true, curInterval.hasValue);
     EXPECT_EQ(20, curInterval.value.long_value);
@@ -1677,11 +1752,11 @@
     allData.push_back(event1);
     allData.push_back(event2);
 
-    valueProducer.onDataPulled(allData);
+    valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
     EXPECT_EQ(2UL, valueProducer.mCurrentSlicedBucket.size());
     EXPECT_EQ(true, interval1.hasBase);
     EXPECT_EQ(11, interval1.base.long_value);
-    EXPECT_EQ(true, interval1.hasValue);
+    EXPECT_EQ(false, interval1.hasValue);
     EXPECT_EQ(8, interval1.value.long_value);
 
     auto it = valueProducer.mCurrentSlicedBucket.begin();
@@ -1695,9 +1770,14 @@
     EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
     EXPECT_EQ(true, interval2.hasBase);
     EXPECT_EQ(4, interval2.base.long_value);
-    EXPECT_EQ(true, interval2.hasValue);
+    EXPECT_EQ(false, interval2.hasValue);
     EXPECT_EQ(4, interval2.value.long_value);
-    EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
+
+    EXPECT_EQ(2UL, valueProducer.mPastBuckets.size());
+    auto iterator = valueProducer.mPastBuckets.begin();
+    EXPECT_EQ(8, iterator->second[0].values[0].long_value);
+    iterator++;
+    EXPECT_EQ(4, iterator->second[0].values[0].long_value);
 }
 
 /*
@@ -1762,11 +1842,11 @@
     allData.push_back(event1);
     allData.push_back(event2);
 
-    valueProducer.onDataPulled(allData);
+    valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
     EXPECT_EQ(2UL, valueProducer.mCurrentSlicedBucket.size());
     EXPECT_EQ(true, interval1.hasBase);
     EXPECT_EQ(11, interval1.base.long_value);
-    EXPECT_EQ(true, interval1.hasValue);
+    EXPECT_EQ(false, interval1.hasValue);
     EXPECT_EQ(8, interval1.value.long_value);
 
     auto it = valueProducer.mCurrentSlicedBucket.begin();
@@ -1780,9 +1860,9 @@
     EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
     EXPECT_EQ(true, interval2.hasBase);
     EXPECT_EQ(4, interval2.base.long_value);
-    EXPECT_EQ(true, interval2.hasValue);
+    EXPECT_EQ(false, interval2.hasValue);
     EXPECT_EQ(4, interval2.value.long_value);
-    EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
+    EXPECT_EQ(2UL, valueProducer.mPastBuckets.size());
 
     // next pull somehow did not happen, skip to end of bucket 3
     allData.clear();
@@ -1791,13 +1871,13 @@
     event1->write(5);
     event1->init();
     allData.push_back(event1);
-    valueProducer.onDataPulled(allData);
+    valueProducer.onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
 
-    EXPECT_EQ(2UL, valueProducer.mCurrentSlicedBucket.size());
+    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
     EXPECT_EQ(true, interval2.hasBase);
-    EXPECT_EQ(5, interval2.base.long_value);
+    EXPECT_EQ(4, interval2.base.long_value);
     EXPECT_EQ(false, interval2.hasValue);
-    EXPECT_EQ(false, interval1.hasBase);
+    EXPECT_EQ(true, interval1.hasBase);
     EXPECT_EQ(false, interval1.hasValue);
     EXPECT_EQ(true, valueProducer.mHasGlobalBase);
     EXPECT_EQ(2UL, valueProducer.mPastBuckets.size());
@@ -1813,17 +1893,17 @@
     event2->write(5);
     event2->init();
     allData.push_back(event2);
-    valueProducer.onDataPulled(allData);
+    valueProducer.onDataPulled(allData, /** succeed */ true, bucket5StartTimeNs);
 
     EXPECT_EQ(2UL, valueProducer.mCurrentSlicedBucket.size());
     EXPECT_EQ(true, interval2.hasBase);
-    EXPECT_EQ(13, interval2.base.long_value);
-    EXPECT_EQ(true, interval2.hasValue);
-    EXPECT_EQ(8, interval2.value.long_value);
+    EXPECT_EQ(5, interval2.base.long_value);
+    EXPECT_EQ(false, interval2.hasValue);
+    EXPECT_EQ(5, interval2.value.long_value);
     EXPECT_EQ(true, interval1.hasBase);
-    EXPECT_EQ(5, interval1.base.long_value);
-    EXPECT_EQ(true, interval1.hasValue);
-    EXPECT_EQ(5, interval1.value.long_value);
+    EXPECT_EQ(13, interval1.base.long_value);
+    EXPECT_EQ(false, interval1.hasValue);
+    EXPECT_EQ(8, interval1.value.long_value);
     EXPECT_EQ(true, valueProducer.mHasGlobalBase);
     EXPECT_EQ(2UL, valueProducer.mPastBuckets.size());
 }
@@ -1888,13 +1968,15 @@
     allData.push_back(event1);
     allData.push_back(event2);
 
-    valueProducer.onDataPulled(allData);
+    valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
     EXPECT_EQ(2UL, valueProducer.mCurrentSlicedBucket.size());
     EXPECT_EQ(true, interval1.hasBase);
     EXPECT_EQ(11, interval1.base.long_value);
-    EXPECT_EQ(true, interval1.hasValue);
+    EXPECT_EQ(false, interval1.hasValue);
     EXPECT_EQ(8, interval1.value.long_value);
-    EXPECT_TRUE(interval1.seenNewData);
+    EXPECT_FALSE(interval1.seenNewData);
+    EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
+    EXPECT_EQ(8, valueProducer.mPastBuckets.begin()->second[0].values[0].long_value);
 
     auto it = valueProducer.mCurrentSlicedBucket.begin();
     for (; it != valueProducer.mCurrentSlicedBucket.end(); it++) {
@@ -1908,8 +1990,8 @@
     EXPECT_EQ(true, interval2.hasBase);
     EXPECT_EQ(4, interval2.base.long_value);
     EXPECT_EQ(false, interval2.hasValue);
-    EXPECT_TRUE(interval2.seenNewData);
-    EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
+    EXPECT_FALSE(interval2.seenNewData);
+    EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
 
     // next pull somehow did not happen, skip to end of bucket 3
     allData.clear();
@@ -1918,40 +2000,92 @@
     event1->write(5);
     event1->init();
     allData.push_back(event1);
-    valueProducer.onDataPulled(allData);
+    valueProducer.onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
 
-    EXPECT_EQ(2UL, valueProducer.mCurrentSlicedBucket.size());
-
-    EXPECT_EQ(false, interval1.hasBase);
-    EXPECT_EQ(false, interval1.hasValue);
-    EXPECT_EQ(8, interval1.value.long_value);
-    // on probation now
-    EXPECT_FALSE(interval1.seenNewData);
-
+	// Only one interval left. One was trimmed.
+    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    interval2 = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
     EXPECT_EQ(true, interval2.hasBase);
     EXPECT_EQ(5, interval2.base.long_value);
     EXPECT_EQ(false, interval2.hasValue);
-    // back to good status
-    EXPECT_TRUE(interval2.seenNewData);
+    EXPECT_FALSE(interval2.seenNewData);
     EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
 
     allData.clear();
     event1 = make_shared<LogEvent>(tagId, bucket5StartTimeNs + 1);
     event1->write(2);
-    event1->write(13);
+    event1->write(14);
     event1->init();
     allData.push_back(event1);
-    valueProducer.onDataPulled(allData);
+    valueProducer.onDataPulled(allData, /** succeed */ true, bucket5StartTimeNs);
 
-    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    interval2 = valueProducer.mCurrentSlicedBucket.begin()->second[0];
     EXPECT_EQ(true, interval2.hasBase);
-    EXPECT_EQ(13, interval2.base.long_value);
-    EXPECT_EQ(true, interval2.hasValue);
-    EXPECT_EQ(8, interval2.value.long_value);
-    EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
+    EXPECT_EQ(14, interval2.base.long_value);
+    EXPECT_EQ(false, interval2.hasValue);
+    EXPECT_FALSE(interval2.seenNewData);
+    EXPECT_EQ(2UL, valueProducer.mPastBuckets.size());
+    auto iterator = valueProducer.mPastBuckets.begin();
+    EXPECT_EQ(9, iterator->second[0].values[0].long_value);
+    iterator++;
+    EXPECT_EQ(8, iterator->second[0].values[0].long_value);
 }
 
-TEST(ValueMetricProducerTest, TestResetBaseOnPullFail) {
+TEST(ValueMetricProducerTest, TestResetBaseOnPullFailAfterConditionChange_EndOfBucket) {
+    ValueMetric metric;
+    metric.set_id(metricId);
+    metric.set_bucket(ONE_MINUTE);
+    metric.mutable_value_field()->set_field(tagId);
+    metric.mutable_value_field()->add_child()->set_field(2);
+    metric.set_condition(StringToId("SCREEN_ON"));
+    metric.set_max_pull_delay_sec(INT_MAX);
+
+    UidMap uidMap;
+    SimpleAtomMatcher atomMatcher;
+    atomMatcher.set_atom_id(tagId);
+    sp<EventMatcherWizard> eventMatcherWizard =
+            new EventMatcherWizard({new SimpleLogMatchingTracker(
+                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
+
+    // Used by onConditionChanged.
+    EXPECT_CALL(*pullerManager, Pull(tagId, _))
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 8);
+                event->write(tagId);
+                event->write(100);
+                event->init();
+                data->push_back(event);
+                return true;
+            }));
+
+    ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
+                                      eventMatcherWizard, tagId, bucketStartTimeNs,
+                                      bucketStartTimeNs, pullerManager);
+
+    valueProducer.onConditionChanged(true, bucketStartTimeNs + 8);
+    // has one slice
+    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    ValueMetricProducer::Interval& curInterval =
+            valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    EXPECT_EQ(true, curInterval.hasBase);
+    EXPECT_EQ(100, curInterval.base.long_value);
+    EXPECT_EQ(false, curInterval.hasValue);
+
+    vector<shared_ptr<LogEvent>> allData;
+    valueProducer.onDataPulled(allData, /** succeed */ false, bucket2StartTimeNs);
+    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    EXPECT_EQ(false, curInterval.hasBase);
+    EXPECT_EQ(false, curInterval.hasValue);
+    EXPECT_EQ(false, valueProducer.mHasGlobalBase);
+}
+
+TEST(ValueMetricProducerTest, TestResetBaseOnPullFailAfterConditionChange) {
     ValueMetric metric;
     metric.set_id(metricId);
     metric.set_bucket(ONE_MINUTE);
@@ -2007,7 +2141,57 @@
     EXPECT_EQ(false, valueProducer.mHasGlobalBase);
 }
 
-TEST(ValueMetricProducerTest, TestResetBaseOnPullTooLate) {
+TEST(ValueMetricProducerTest, TestResetBaseOnPullFailBeforeConditionChange) {
+    ValueMetric metric;
+    metric.set_id(metricId);
+    metric.set_bucket(ONE_MINUTE);
+    metric.mutable_value_field()->set_field(tagId);
+    metric.mutable_value_field()->add_child()->set_field(2);
+    metric.set_condition(StringToId("SCREEN_ON"));
+    metric.set_max_pull_delay_sec(INT_MAX);
+
+    UidMap uidMap;
+    SimpleAtomMatcher atomMatcher;
+    atomMatcher.set_atom_id(tagId);
+    sp<EventMatcherWizard> eventMatcherWizard =
+            new EventMatcherWizard({new SimpleLogMatchingTracker(
+                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
+
+    EXPECT_CALL(*pullerManager, Pull(tagId, _))
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 8);
+                event->write(tagId);
+                event->write(100);
+                event->init();
+                data->push_back(event);
+                return true;
+            }));
+
+    ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
+                                      eventMatcherWizard, tagId, bucketStartTimeNs,
+                                      bucketStartTimeNs, pullerManager);
+
+    valueProducer.mCondition = true;
+
+    vector<shared_ptr<LogEvent>> allData;
+    valueProducer.onDataPulled(allData, /** succeed */ false, bucketStartTimeNs);
+    EXPECT_EQ(0UL, valueProducer.mCurrentSlicedBucket.size());
+
+    valueProducer.onConditionChanged(false, bucketStartTimeNs + 1);
+    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    ValueMetricProducer::Interval& curInterval =
+            valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    EXPECT_EQ(false, curInterval.hasBase);
+    EXPECT_EQ(false, curInterval.hasValue);
+    EXPECT_EQ(false, valueProducer.mHasGlobalBase);
+}
+
+TEST(ValueMetricProducerTest, TestResetBaseOnPullDelayExceeded) {
     ValueMetric metric;
     metric.set_id(metricId);
     metric.set_bucket(ONE_MINUTE);
@@ -2030,7 +2214,7 @@
     EXPECT_CALL(*pullerManager, Pull(tagId, _))
             .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
                 data->clear();
-                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
+                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 1);
                 event->write(tagId);
                 event->write(120);
                 event->init();
@@ -2042,37 +2226,599 @@
                                       eventMatcherWizard, tagId, bucketStartTimeNs,
                                       bucketStartTimeNs, pullerManager);
 
-    valueProducer.mCondition = true;
+    valueProducer.mCondition = false;
+
+    // Max delay is set to 0 so pull will exceed max delay.
+    valueProducer.onConditionChanged(true, bucketStartTimeNs + 1);
+    EXPECT_EQ(0UL, valueProducer.mCurrentSlicedBucket.size());
+}
+
+TEST(ValueMetricProducerTest, TestResetBaseOnPullTooLate) {
+    ValueMetric metric;
+    metric.set_id(metricId);
+    metric.set_bucket(ONE_MINUTE);
+    metric.mutable_value_field()->set_field(tagId);
+    metric.mutable_value_field()->add_child()->set_field(2);
+    metric.set_condition(StringToId("SCREEN_ON"));
+    metric.set_max_pull_delay_sec(INT_MAX);
+
+    UidMap uidMap;
+    SimpleAtomMatcher atomMatcher;
+    atomMatcher.set_atom_id(tagId);
+    sp<EventMatcherWizard> eventMatcherWizard =
+            new EventMatcherWizard({new SimpleLogMatchingTracker(
+                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
+
+    ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
+                                      eventMatcherWizard, tagId, bucket2StartTimeNs,
+                                      bucket2StartTimeNs, pullerManager);
+
+    valueProducer.mCondition = false;
+
+    // Event should be skipped since it is from previous bucket.
+    // Pull should not be called.
+    valueProducer.onConditionChanged(true, bucketStartTimeNs);
+    EXPECT_EQ(0UL, valueProducer.mCurrentSlicedBucket.size());
+}
+
+TEST(ValueMetricProducerTest, TestBaseSetOnConditionChange) {
+    ValueMetric metric;
+    metric.set_id(metricId);
+    metric.set_bucket(ONE_MINUTE);
+    metric.mutable_value_field()->set_field(tagId);
+    metric.mutable_value_field()->add_child()->set_field(2);
+    metric.set_condition(StringToId("SCREEN_ON"));
+    metric.set_max_pull_delay_sec(INT_MAX);
+
+    UidMap uidMap;
+    SimpleAtomMatcher atomMatcher;
+    atomMatcher.set_atom_id(tagId);
+    sp<EventMatcherWizard> eventMatcherWizard =
+            new EventMatcherWizard({new SimpleLogMatchingTracker(
+                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
+    EXPECT_CALL(*pullerManager, Pull(tagId, _))
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 1);
+                event->write(tagId);
+                event->write(100);
+                event->init();
+                data->push_back(event);
+                return true;
+            }));
+
+    ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
+                                      eventMatcherWizard, tagId, bucketStartTimeNs,
+                                      bucketStartTimeNs, pullerManager);
+
+    valueProducer.mCondition = false;
+    valueProducer.mHasGlobalBase = false;
+
+    valueProducer.onConditionChanged(true, bucketStartTimeNs + 1);
     valueProducer.mHasGlobalBase = true;
-
-    vector<shared_ptr<LogEvent>> allData;
-    allData.clear();
-    shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
-    event->write(1);
-    event->write(110);
-    event->init();
-    allData.push_back(event);
-    valueProducer.onDataPulled(allData);
-
-    // has one slice
     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
     ValueMetricProducer::Interval& curInterval =
             valueProducer.mCurrentSlicedBucket.begin()->second[0];
     EXPECT_EQ(true, curInterval.hasBase);
-    EXPECT_EQ(110, curInterval.base.long_value);
+    EXPECT_EQ(100, curInterval.base.long_value);
     EXPECT_EQ(false, curInterval.hasValue);
+    EXPECT_EQ(true, valueProducer.mHasGlobalBase);
+}
+
+TEST(ValueMetricProducerTest, TestInvalidBucketWhenOneConditionFailed) {
+    ValueMetric metric;
+    metric.set_id(metricId);
+    metric.set_bucket(ONE_MINUTE);
+    metric.mutable_value_field()->set_field(tagId);
+    metric.mutable_value_field()->add_child()->set_field(2);
+    metric.set_condition(StringToId("SCREEN_ON"));
+    metric.set_max_pull_delay_sec(INT_MAX);
+
+    UidMap uidMap;
+    SimpleAtomMatcher atomMatcher;
+    atomMatcher.set_atom_id(tagId);
+    sp<EventMatcherWizard> eventMatcherWizard =
+            new EventMatcherWizard({new SimpleLogMatchingTracker(
+                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
+
+    EXPECT_CALL(*pullerManager, Pull(tagId, _))
+            // First onConditionChanged
+            .WillOnce(Return(false))
+            // Second onConditionChanged
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 8);
+                event->write(tagId);
+                event->write(130);
+                event->init();
+                data->push_back(event);
+                return true;
+            }));
+
+    ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
+                                      eventMatcherWizard, tagId, bucketStartTimeNs,
+                                      bucketStartTimeNs, pullerManager);
+
+    valueProducer.mCondition = true;
+
+    // Bucket start.
+    vector<shared_ptr<LogEvent>> allData;
+    allData.clear();
+    shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 1);
+    event->write(1);
+    event->write(110);
+    event->init();
+    allData.push_back(event);
+    valueProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs);
+
+    // This will fail and should invalidate the whole bucket since we do not have all the data
+    // needed to compute the metric value when the screen was on.
+    valueProducer.onConditionChanged(false, bucketStartTimeNs + 2);
+    valueProducer.onConditionChanged(true, bucketStartTimeNs + 3);
+
+    // Bucket end.
+    allData.clear();
+    shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
+    event2->write(1);
+    event2->write(140);
+    event2->init();
+    allData.push_back(event2);
+    valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+
+    valueProducer.flushIfNeededLocked(bucket2StartTimeNs + 1);
+    
     EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
+    // Contains base from last pull which was successful.
+    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    ValueMetricProducer::Interval& curInterval =
+            valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    EXPECT_EQ(true, curInterval.hasBase);
+    EXPECT_EQ(140, curInterval.base.long_value);
+    EXPECT_EQ(false, curInterval.hasValue);
+    EXPECT_EQ(true, valueProducer.mHasGlobalBase);
+}
+
+TEST(ValueMetricProducerTest, TestInvalidBucketWhenInitialPullFailed) {
+    ValueMetric metric;
+    metric.set_id(metricId);
+    metric.set_bucket(ONE_MINUTE);
+    metric.mutable_value_field()->set_field(tagId);
+    metric.mutable_value_field()->add_child()->set_field(2);
+    metric.set_condition(StringToId("SCREEN_ON"));
+    metric.set_max_pull_delay_sec(INT_MAX);
+
+    UidMap uidMap;
+    SimpleAtomMatcher atomMatcher;
+    atomMatcher.set_atom_id(tagId);
+    sp<EventMatcherWizard> eventMatcherWizard =
+            new EventMatcherWizard({new SimpleLogMatchingTracker(
+                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
+
+    EXPECT_CALL(*pullerManager, Pull(tagId, _))
+            // First onConditionChanged
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 8);
+                event->write(tagId);
+                event->write(120);
+                event->init();
+                data->push_back(event);
+                return true;
+            }))
+            // Second onConditionChanged
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 8);
+                event->write(tagId);
+                event->write(130);
+                event->init();
+                data->push_back(event);
+                return true;
+            }));
+
+    ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
+                                      eventMatcherWizard, tagId, bucketStartTimeNs,
+                                      bucketStartTimeNs, pullerManager);
+
+    valueProducer.mCondition = true;
+
+    // Bucket start.
+    vector<shared_ptr<LogEvent>> allData;
+    allData.clear();
+    shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 1);
+    event->write(1);
+    event->write(110);
+    event->init();
+    allData.push_back(event);
+    valueProducer.onDataPulled(allData, /** succeed */ false, bucketStartTimeNs);
+
+    valueProducer.onConditionChanged(false, bucketStartTimeNs + 2);
+    valueProducer.onConditionChanged(true, bucketStartTimeNs + 3);
+
+    // Bucket end.
+    allData.clear();
+    shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
+    event2->write(1);
+    event2->write(140);
+    event2->init();
+    allData.push_back(event2);
+    valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+
+    valueProducer.flushIfNeededLocked(bucket2StartTimeNs + 1);
+    
+    EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
+    // Contains base from last pull which was successful.
+    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    ValueMetricProducer::Interval& curInterval =
+            valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    EXPECT_EQ(true, curInterval.hasBase);
+    EXPECT_EQ(140, curInterval.base.long_value);
+    EXPECT_EQ(false, curInterval.hasValue);
+    EXPECT_EQ(true, valueProducer.mHasGlobalBase);
+}
+
+TEST(ValueMetricProducerTest, TestInvalidBucketWhenLastPullFailed) {
+    ValueMetric metric;
+    metric.set_id(metricId);
+    metric.set_bucket(ONE_MINUTE);
+    metric.mutable_value_field()->set_field(tagId);
+    metric.mutable_value_field()->add_child()->set_field(2);
+    metric.set_condition(StringToId("SCREEN_ON"));
+    metric.set_max_pull_delay_sec(INT_MAX);
+
+    UidMap uidMap;
+    SimpleAtomMatcher atomMatcher;
+    atomMatcher.set_atom_id(tagId);
+    sp<EventMatcherWizard> eventMatcherWizard =
+            new EventMatcherWizard({new SimpleLogMatchingTracker(
+                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
+
+    EXPECT_CALL(*pullerManager, Pull(tagId, _))
+            // First onConditionChanged
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 8);
+                event->write(tagId);
+                event->write(120);
+                event->init();
+                data->push_back(event);
+                return true;
+            }))
+            // Second onConditionChanged
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 8);
+                event->write(tagId);
+                event->write(130);
+                event->init();
+                data->push_back(event);
+                return true;
+            }));
+
+    ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
+                                      eventMatcherWizard, tagId, bucketStartTimeNs,
+                                      bucketStartTimeNs, pullerManager);
+
+    valueProducer.mCondition = true;
+
+    // Bucket start.
+    vector<shared_ptr<LogEvent>> allData;
+    allData.clear();
+    shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs + 1);
+    event->write(1);
+    event->write(110);
+    event->init();
+    allData.push_back(event);
+    valueProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs);
+
+    // This will fail and should invalidate the whole bucket since we do not have all the data
+    // needed to compute the metric value when the screen was on.
+    valueProducer.onConditionChanged(false, bucketStartTimeNs + 2);
+    valueProducer.onConditionChanged(true, bucketStartTimeNs + 3);
+
+    // Bucket end.
+    allData.clear();
+    shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
+    event2->write(1);
+    event2->write(140);
+    event2->init();
+    allData.push_back(event2);
+    valueProducer.onDataPulled(allData, /** succeed */ false, bucket2StartTimeNs);
+
+    valueProducer.flushIfNeededLocked(bucket2StartTimeNs + 1);
+    
+    EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
+    // Last pull failed so based has been reset.
+    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    ValueMetricProducer::Interval& curInterval =
+            valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    EXPECT_EQ(false, curInterval.hasBase);
+    EXPECT_EQ(false, curInterval.hasValue);
+    EXPECT_EQ(false, valueProducer.mHasGlobalBase);
+}
+
+TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onDataPulled) {
+    ValueMetric metric;
+    metric.set_id(metricId);
+    metric.set_bucket(ONE_MINUTE);
+    metric.mutable_value_field()->set_field(tagId);
+    metric.mutable_value_field()->add_child()->set_field(2);
+    metric.set_max_pull_delay_sec(INT_MAX);
+
+    UidMap uidMap;
+    SimpleAtomMatcher atomMatcher;
+    atomMatcher.set_atom_id(tagId);
+    sp<EventMatcherWizard> eventMatcherWizard =
+            new EventMatcherWizard({new SimpleLogMatchingTracker(
+                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
+
+    EXPECT_CALL(*pullerManager, Pull(tagId, _))
+            // Start bucket.
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs);
+                event->write(tagId);
+                event->write(3);
+                event->init();
+                data->push_back(event);
+                return true;
+            }));
+
+    ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+                                      logEventMatcherIndex, eventMatcherWizard, tagId,
+                                      bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+
+    // Bucket 2 start.
+    vector<shared_ptr<LogEvent>> allData;
+    allData.clear();
+    shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
+    event->write(tagId);
+    event->write(110);
+    event->init();
+    allData.push_back(event);
+    valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
+
+    // Bucket 3 empty.
+    allData.clear();
+    shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 1);
+    event2->init();
+    allData.push_back(event2);
+    valueProducer.onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
+    // Data has been trimmed.
+    EXPECT_EQ(0UL, valueProducer.mCurrentSlicedBucket.size());
+    EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
+}
+
+TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onConditionChanged) {
+    ValueMetric metric;
+    metric.set_id(metricId);
+    metric.set_bucket(ONE_MINUTE);
+    metric.mutable_value_field()->set_field(tagId);
+    metric.mutable_value_field()->add_child()->set_field(2);
+    metric.set_condition(StringToId("SCREEN_ON"));
+    metric.set_max_pull_delay_sec(INT_MAX);
+
+    UidMap uidMap;
+    SimpleAtomMatcher atomMatcher;
+    atomMatcher.set_atom_id(tagId);
+    sp<EventMatcherWizard> eventMatcherWizard =
+            new EventMatcherWizard({new SimpleLogMatchingTracker(
+                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
+
+    EXPECT_CALL(*pullerManager, Pull(tagId, _))
+            // First onConditionChanged
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs);
+                event->write(tagId);
+                event->write(3);
+                event->init();
+                data->push_back(event);
+                return true;
+            }))
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                return true;
+            }));
+
+    ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
+                                      eventMatcherWizard, tagId, bucketStartTimeNs,
+                                      bucketStartTimeNs, pullerManager);
+
+    valueProducer.onConditionChanged(true, bucketStartTimeNs + 10);
+    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    ValueMetricProducer::Interval& curInterval =
+            valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    EXPECT_EQ(true, curInterval.hasBase);
+    EXPECT_EQ(false, curInterval.hasValue);
     EXPECT_EQ(true, valueProducer.mHasGlobalBase);
 
-    valueProducer.onConditionChanged(false, bucket2StartTimeNs + 1);
-
-    // has one slice
+    // Empty pull.
+    valueProducer.onConditionChanged(false, bucketStartTimeNs + 10);
     EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-    EXPECT_EQ(false, curInterval.hasValue);
+    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
     EXPECT_EQ(false, curInterval.hasBase);
+    EXPECT_EQ(false, curInterval.hasValue);
     EXPECT_EQ(false, valueProducer.mHasGlobalBase);
 }
 
+TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onBucketBoundary) {
+    ValueMetric metric;
+    metric.set_id(metricId);
+    metric.set_bucket(ONE_MINUTE);
+    metric.mutable_value_field()->set_field(tagId);
+    metric.mutable_value_field()->add_child()->set_field(2);
+    metric.set_condition(StringToId("SCREEN_ON"));
+    metric.set_max_pull_delay_sec(INT_MAX);
+
+    UidMap uidMap;
+    SimpleAtomMatcher atomMatcher;
+    atomMatcher.set_atom_id(tagId);
+    sp<EventMatcherWizard> eventMatcherWizard =
+            new EventMatcherWizard({new SimpleLogMatchingTracker(
+                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
+
+    EXPECT_CALL(*pullerManager, Pull(tagId, _))
+            // First onConditionChanged
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs);
+                event->write(tagId);
+                event->write(1);
+                event->init();
+                data->push_back(event);
+                return true;
+            }))
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs);
+                event->write(tagId);
+                event->write(2);
+                event->init();
+                data->push_back(event);
+                return true;
+            }))
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs);
+                event->write(tagId);
+                event->write(5);
+                event->init();
+                data->push_back(event);
+                return true;
+            }));
+
+    ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
+                                      eventMatcherWizard, tagId, bucketStartTimeNs,
+                                      bucketStartTimeNs, pullerManager);
+
+    valueProducer.onConditionChanged(true, bucketStartTimeNs + 10);
+    valueProducer.onConditionChanged(false, bucketStartTimeNs + 11);
+    valueProducer.onConditionChanged(true, bucketStartTimeNs + 12);
+    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    ValueMetricProducer::Interval& curInterval =
+            valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    EXPECT_EQ(true, curInterval.hasBase);
+    EXPECT_EQ(true, curInterval.hasValue);
+    EXPECT_EQ(true, valueProducer.mHasGlobalBase);
+
+    // End of bucket
+    vector<shared_ptr<LogEvent>> allData;
+    allData.clear();
+    valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    // Data is empty, base should be reset.
+    EXPECT_EQ(false, curInterval.hasBase);
+    EXPECT_EQ(5, curInterval.base.long_value);
+    EXPECT_EQ(false, curInterval.hasValue);
+    EXPECT_EQ(true, valueProducer.mHasGlobalBase);
+
+    EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
+    EXPECT_EQ(1, valueProducer.mPastBuckets.begin()->second[0].values[0].long_value);
+}
+
+
+TEST(ValueMetricProducerTest, TestPartialResetOnBucketBoundaries) {
+    ValueMetric metric;
+    metric.set_id(metricId);
+    metric.set_bucket(ONE_MINUTE);
+    metric.mutable_value_field()->set_field(tagId);
+    metric.mutable_value_field()->add_child()->set_field(2);
+    metric.mutable_dimensions_in_what()->set_field(tagId);
+    metric.mutable_dimensions_in_what()->add_child()->set_field(1);
+    metric.set_condition(StringToId("SCREEN_ON"));
+    metric.set_max_pull_delay_sec(INT_MAX);
+
+    UidMap uidMap;
+    SimpleAtomMatcher atomMatcher;
+    atomMatcher.set_atom_id(tagId);
+    sp<EventMatcherWizard> eventMatcherWizard =
+            new EventMatcherWizard({new SimpleLogMatchingTracker(
+                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
+    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
+
+    EXPECT_CALL(*pullerManager, Pull(tagId, _))
+            // First onConditionChanged
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs);
+                event->write(tagId);
+                event->write(1);
+                event->write(1);
+                event->init();
+                data->push_back(event);
+                return true;
+            }));
+
+    ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
+                                      eventMatcherWizard, tagId, bucketStartTimeNs,
+                                      bucketStartTimeNs, pullerManager);
+
+    valueProducer.onConditionChanged(true, bucketStartTimeNs + 10);
+    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+
+    // End of bucket
+    vector<shared_ptr<LogEvent>> allData;
+    allData.clear();
+    shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
+    event->write(2);
+    event->write(2);
+    event->init();
+    allData.push_back(event);
+    valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+
+    // Key 1 should be reset since in not present in the most pull.
+    EXPECT_EQ(2UL, valueProducer.mCurrentSlicedBucket.size());
+    auto iterator = valueProducer.mCurrentSlicedBucket.begin();
+    EXPECT_EQ(true, iterator->second[0].hasBase);
+    EXPECT_EQ(2, iterator->second[0].base.long_value);
+    EXPECT_EQ(false, iterator->second[0].hasValue);
+    iterator++;
+    EXPECT_EQ(false, iterator->second[0].hasBase);
+    EXPECT_EQ(1, iterator->second[0].base.long_value);
+    EXPECT_EQ(false, iterator->second[0].hasValue);
+
+    EXPECT_EQ(true, valueProducer.mHasGlobalBase);
+}
+
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
diff --git a/cmds/svc/src/com/android/commands/svc/PowerCommand.java b/cmds/svc/src/com/android/commands/svc/PowerCommand.java
index 920a52d..d29e68e 100644
--- a/cmds/svc/src/com/android/commands/svc/PowerCommand.java
+++ b/cmds/svc/src/com/android/commands/svc/PowerCommand.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.os.BatteryManager;
 import android.os.IPowerManager;
+import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
@@ -71,7 +72,8 @@
                         if (val != 0) {
                             // if the request is not to set it to false, wake up the screen so that
                             // it can stay on as requested
-                            pm.wakeUp(SystemClock.uptimeMillis(), "PowerCommand", null);
+                            pm.wakeUp(SystemClock.uptimeMillis(),
+                                    PowerManager.WAKE_REASON_UNKNOWN, "PowerCommand", null);
                         }
                         pm.setStayOnSetting(val);
                     }
diff --git a/config/boot-image-profile.txt b/config/boot-image-profile.txt
index 6061b66..7edd128 100644
--- a/config/boot-image-profile.txt
+++ b/config/boot-image-profile.txt
@@ -33456,7 +33456,6 @@
 HSPLandroid/view/SurfaceControl;->finalize()V
 HSPLandroid/view/SurfaceControl;->getActiveColorMode(Landroid/os/IBinder;)I
 HSPLandroid/view/SurfaceControl;->getActiveConfig(Landroid/os/IBinder;)I
-HSPLandroid/view/SurfaceControl;->getBuiltInDisplay(I)Landroid/os/IBinder;
 HSPLandroid/view/SurfaceControl;->getDisplayColorModes(Landroid/os/IBinder;)[I
 HSPLandroid/view/SurfaceControl;->getDisplayConfigs(Landroid/os/IBinder;)[Landroid/view/SurfaceControl$PhysicalDisplayInfo;
 HSPLandroid/view/SurfaceControl;->getHandle()Landroid/os/IBinder;
diff --git a/config/hiddenapi-greylist-max-p.txt b/config/hiddenapi-greylist-max-p.txt
index 7840b18..4c643e1 100644
--- a/config/hiddenapi-greylist-max-p.txt
+++ b/config/hiddenapi-greylist-max-p.txt
@@ -48,6 +48,8 @@
 Landroid/service/carrier/ICarrierMessagingCallback$Stub;-><init>()V
 Landroid/service/carrier/ICarrierMessagingService;->filterSms(Landroid/service/carrier/MessagePdu;Ljava/lang/String;IILandroid/service/carrier/ICarrierMessagingCallback;)V
 Landroid/telephony/CarrierMessagingServiceManager;-><init>()V
+Landroid/view/IGraphicsStats$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
+Landroid/view/IGraphicsStats$Stub;->asInterface(Landroid/os/IBinder;)Landroid/view/IGraphicsStats;
 Landroid/view/IWindowManager;->setInTouchMode(Z)V
 Landroid/view/IWindowManager;->showStrictModeViolation(Z)V
 Lcom/android/internal/R$styleable;->AndroidManifestActivityAlias:[I
diff --git a/config/hiddenapi-greylist.txt b/config/hiddenapi-greylist.txt
index 11bb38b..010e447 100644
--- a/config/hiddenapi-greylist.txt
+++ b/config/hiddenapi-greylist.txt
@@ -328,17 +328,12 @@
 Landroid/content/om/IOverlayManager;->getOverlayInfo(Ljava/lang/String;I)Landroid/content/om/OverlayInfo;
 Landroid/content/pm/IPackageDataObserver$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Landroid/content/pm/IPackageDataObserver$Stub$Proxy;->mRemote:Landroid/os/IBinder;
-Landroid/content/pm/IPackageDataObserver$Stub$Proxy;->onRemoveCompleted(Ljava/lang/String;Z)V
 Landroid/content/pm/IPackageDataObserver$Stub;-><init>()V
 Landroid/content/pm/IPackageDataObserver$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/pm/IPackageDataObserver;
-Landroid/content/pm/IPackageDataObserver$Stub;->DESCRIPTOR:Ljava/lang/String;
-Landroid/content/pm/IPackageDataObserver$Stub;->TRANSACTION_onRemoveCompleted:I
 Landroid/content/pm/IPackageDataObserver;->onRemoveCompleted(Ljava/lang/String;Z)V
 Landroid/content/pm/IPackageDeleteObserver$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Landroid/content/pm/IPackageDeleteObserver$Stub;-><init>()V
 Landroid/content/pm/IPackageDeleteObserver$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/pm/IPackageDeleteObserver;
-Landroid/content/pm/IPackageDeleteObserver$Stub;->DESCRIPTOR:Ljava/lang/String;
-Landroid/content/pm/IPackageDeleteObserver$Stub;->TRANSACTION_packageDeleted:I
 Landroid/content/pm/IPackageDeleteObserver2$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Landroid/content/pm/IPackageDeleteObserver2$Stub$Proxy;->mRemote:Landroid/os/IBinder;
 Landroid/content/pm/IPackageDeleteObserver2$Stub;-><init>()V
@@ -437,8 +432,6 @@
 Landroid/content/pm/IPackageStatsObserver$Stub$Proxy;->mRemote:Landroid/os/IBinder;
 Landroid/content/pm/IPackageStatsObserver$Stub;-><init>()V
 Landroid/content/pm/IPackageStatsObserver$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/pm/IPackageStatsObserver;
-Landroid/content/pm/IPackageStatsObserver$Stub;->DESCRIPTOR:Ljava/lang/String;
-Landroid/content/pm/IPackageStatsObserver$Stub;->TRANSACTION_onGetStatsCompleted:I
 Landroid/content/pm/IPackageStatsObserver;->onGetStatsCompleted(Landroid/content/pm/PackageStats;Z)V
 Landroid/content/pm/IShortcutService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Landroid/content/pm/IShortcutService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/pm/IShortcutService;
@@ -835,7 +828,6 @@
 Landroid/os/IPowerManager;->reboot(ZLjava/lang/String;Z)V
 Landroid/os/IPowerManager;->releaseWakeLock(Landroid/os/IBinder;I)V
 Landroid/os/IPowerManager;->userActivity(JII)V
-Landroid/os/IPowerManager;->wakeUp(JLjava/lang/String;Ljava/lang/String;)V
 Landroid/os/IRecoverySystem$Stub;->asInterface(Landroid/os/IBinder;)Landroid/os/IRecoverySystem;
 Landroid/os/IRemoteCallback$Stub;-><init>()V
 Landroid/os/IRemoteCallback;->sendResult(Landroid/os/Bundle;)V
@@ -1482,8 +1474,6 @@
 Landroid/view/autofill/IAutoFillManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/view/autofill/IAutoFillManager;
 Landroid/view/IAppTransitionAnimationSpecsFuture$Stub;-><init>()V
 Landroid/view/IDockedStackListener$Stub;-><init>()V
-Landroid/view/IGraphicsStats$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
-Landroid/view/IGraphicsStats$Stub;->asInterface(Landroid/os/IBinder;)Landroid/view/IGraphicsStats;
 Landroid/view/IRecentsAnimationController;->finish(Z)V
 Landroid/view/IRecentsAnimationController;->screenshotTask(I)Landroid/app/ActivityManager$TaskSnapshot;
 Landroid/view/IRecentsAnimationController;->setAnimationTargetsBehindSystemBars(Z)V
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index a0464df..ebb03e7 100644
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -20,6 +20,7 @@
 import android.annotation.IntDef;
 import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
+import android.os.Build;
 import android.os.Looper;
 import android.os.Trace;
 import android.util.AndroidRuntimeException;
@@ -76,7 +77,13 @@
     /**
      * Internal constants
      */
-    @UnsupportedAppUsage
+
+    /**
+     * System-wide animation scale.
+     *
+     * <p>To check whether animations are enabled system-wise use {@link #areAnimatorsEnabled()}.
+     */
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     private static float sDurationScale = 1.0f;
 
     /**
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 21d66e5..cc419b8 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -4565,16 +4565,25 @@
     }
 
     private void onCoreSettingsChange() {
-        boolean debugViewAttributes =
-                mCoreSettings.getInt(Settings.Global.DEBUG_VIEW_ATTRIBUTES, 0) != 0;
-        if (debugViewAttributes != View.mDebugViewAttributes) {
-            View.mDebugViewAttributes = debugViewAttributes;
-
+        if (updateDebugViewAttributeState()) {
             // request all activities to relaunch for the changes to take place
             relaunchAllActivities();
         }
     }
 
+    private boolean updateDebugViewAttributeState() {
+        boolean previousState = View.sDebugViewAttributes;
+
+        View.sDebugViewAttributesApplicationPackage = mCoreSettings.getString(
+                Settings.Global.DEBUG_VIEW_ATTRIBUTES_APPLICATION_PACKAGE, "");
+        String currentPackage = (mBoundApplication != null && mBoundApplication.appInfo != null)
+                ? mBoundApplication.appInfo.packageName : "";
+        View.sDebugViewAttributes =
+                mCoreSettings.getInt(Settings.Global.DEBUG_VIEW_ATTRIBUTES, 0) != 0
+                        || View.sDebugViewAttributesApplicationPackage.equals(currentPackage);
+        return previousState != View.sDebugViewAttributes;
+    }
+
     private void relaunchAllActivities() {
         for (Map.Entry<IBinder, ActivityClientRecord> entry : mActivities.entrySet()) {
             final Activity activity = entry.getValue().activity;
@@ -5950,8 +5959,7 @@
         // true : use 24 hour format.
         DateFormat.set24HourTimePref(is24Hr);
 
-        View.mDebugViewAttributes =
-                mCoreSettings.getInt(Settings.Global.DEBUG_VIEW_ATTRIBUTES, 0) != 0;
+        updateDebugViewAttributeState();
 
         StrictMode.initThreadDefaults(data.appInfo);
         StrictMode.initVmDefaults(data.appInfo);
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index 5814e69..ce71998 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -26,6 +26,7 @@
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.graphics.Insets;
 import android.hardware.display.DisplayManager;
 import android.hardware.display.VirtualDisplay;
 import android.os.RemoteException;
@@ -84,6 +85,8 @@
     /** The ActivityView is only allowed to contain one task. */
     private final boolean mSingleTaskInstance;
 
+    private Insets mForwardedInsets;
+
     @UnsupportedAppUsage
     public ActivityView(Context context) {
         this(context, null /* attrs */);
@@ -369,11 +372,13 @@
                 .build();
 
         try {
+            // TODO: Find a way to consolidate these calls to the server.
             wm.reparentDisplayContent(displayId, mRootSurfaceControl);
             wm.dontOverrideDisplayInfo(displayId);
             if (mSingleTaskInstance) {
                 mActivityTaskManager.setDisplayToSingleTaskInstance(displayId);
             }
+            wm.setForwardedInsets(displayId, mForwardedInsets);
         } catch (RemoteException e) {
             e.rethrowAsRuntimeException();
         }
@@ -454,6 +459,24 @@
     }
 
     /**
+     * Set forwarded insets on the virtual display.
+     *
+     * @see IWindowManager#setForwardedInsets
+     */
+    public void setForwardedInsets(Insets insets) {
+        mForwardedInsets = insets;
+        if (mVirtualDisplay == null) {
+            return;
+        }
+        try {
+            final IWindowManager wm = WindowManagerGlobal.getWindowManagerService();
+            wm.setForwardedInsets(mVirtualDisplay.getDisplay().getDisplayId(), mForwardedInsets);
+        } catch (RemoteException e) {
+            e.rethrowAsRuntimeException();
+        }
+    }
+
+    /**
      * A task change listener that detects background color change of the topmost stack on our
      * virtual display and updates the background of the surface view. This background will be shown
      * when surface view is resized, but the app hasn't drawn its content in new size yet.
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index ea145f0..64b94a9 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -189,9 +189,19 @@
 
     /**
      * Special mode that means "allow only when app is in foreground."  This is <b>not</b>
-     * returned from {@link #checkOp}, {@link #noteOp}, {@link #startOp}; rather, when this
-     * mode is set, these functions will return {@link #MODE_ALLOWED} when the app being
-     * checked is currently in the foreground, otherwise {@link #MODE_IGNORED}.
+     * returned from {@link #unsafeCheckOp}, {@link #noteOp}, {@link #startOp}.  Rather,
+     * {@link #unsafeCheckOp} will always return {@link #MODE_ALLOWED} (because it is always
+     * possible for it to be ultimately allowed, depending on the app's background state),
+     * and {@link #noteOp} and {@link #startOp} will return {@link #MODE_ALLOWED} when the app
+     * being checked is currently in the foreground, otherwise {@link #MODE_IGNORED}.
+     *
+     * <p>The only place you will this normally see this value is through
+     * {@link #unsafeCheckOpRaw}, which returns the actual raw mode of the op.  Note that because
+     * you can't know the current state of the app being checked (and it can change at any
+     * point), you can only treat the result here as an indication that it will vary between
+     * {@link #MODE_ALLOWED} and {@link #MODE_IGNORED} depending on changes in the background
+     * state of the app.  You thus must always use {@link #noteOp} or {@link #startOp} to do
+     * the actual check for access to the op.</p>
      */
     public static final int MODE_FOREGROUND = 4;
 
diff --git a/core/java/android/app/KeyguardManager.java b/core/java/android/app/KeyguardManager.java
index f522d71..17f645d 100644
--- a/core/java/android/app/KeyguardManager.java
+++ b/core/java/android/app/KeyguardManager.java
@@ -125,7 +125,7 @@
     public static final int RESULT_ALTERNATE = 1;
 
     /**
-     * @deprecated see {@link BiometricPrompt.Builder#setEnableFallback(boolean)}
+     * @deprecated see {@link BiometricPrompt.Builder#setAllowDeviceCredential(boolean)}
      *
      * Get an intent to prompt the user to confirm credentials (pin, pattern, password or biometrics
      * if enrolled) for the current user of the device. The caller is expected to launch this
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 028e3ef..dc4f343 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -8243,6 +8243,7 @@
 
         private void buildIntoRemoteViewContent(RemoteViews remoteViews,
                 RemoteViews customContent, TemplateBindResult result) {
+            int childIndex = -1;
             if (customContent != null) {
                 // Need to clone customContent before adding, because otherwise it can no longer be
                 // parceled independently of remoteViews.
@@ -8250,7 +8251,11 @@
                 remoteViews.removeAllViewsExceptId(R.id.notification_main_column, R.id.progress);
                 remoteViews.addView(R.id.notification_main_column, customContent, 0 /* index */);
                 remoteViews.addFlags(RemoteViews.FLAG_REAPPLY_DISALLOWED);
+                childIndex = 0;
             }
+            remoteViews.setIntTag(R.id.notification_main_column,
+                    com.android.internal.R.id.notification_custom_view_index_tag,
+                    childIndex);
             // also update the end margin if there is an image
             Resources resources = mBuilder.mContext.getResources();
             int endMargin = resources.getDimensionPixelSize(
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index e95d62f..cfe27c7 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -85,7 +85,7 @@
     private static final String ATT_FG_SERVICE_SHOWN = "fgservice";
     private static final String ATT_GROUP = "group";
     private static final String ATT_BLOCKABLE_SYSTEM = "blockable_system";
-    private static final String ATT_ALLOW_BUBBLE = "allow_bubble";
+    private static final String ATT_ALLOW_BUBBLE = "can_bubble";
     private static final String DELIMITER = ",";
 
     /**
@@ -611,14 +611,6 @@
      * shade, in a floating window on top of other apps.
      */
     public boolean canBubble() {
-        return isBubbleAllowed() && getImportance() >= IMPORTANCE_HIGH;
-    }
-
-    /**
-     * Like {@link #canBubble()}, but only checks the permission, not the importance.
-     * @hide
-     */
-    public boolean isBubbleAllowed() {
         return mAllowBubbles;
     }
 
diff --git a/core/java/android/app/TEST_MAPPING b/core/java/android/app/TEST_MAPPING
index 78ec8a1..65859c7 100644
--- a/core/java/android/app/TEST_MAPPING
+++ b/core/java/android/app/TEST_MAPPING
@@ -6,5 +6,13 @@
     {
       "path": "frameworks/base/services/core/java/com/android/server/wm"
     }
+  ],
+  "presubmit": [
+      {
+        "name": "CtsFragmentTestCases"
+      },
+      {
+        "name": "CtsFragmentTestCasesSdk26"
+      }
   ]
 }
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 428c9b0..8861151 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -4618,6 +4618,10 @@
      * <p>If the installer must have access to the credentials, call
      * {@link #installKeyPair(ComponentName, PrivateKey, Certificate[], String, boolean)} instead.
      *
+     * <p>Note: If the provided {@code alias} is of an existing alias, all former grants that apps
+     * have been given to access the key and certificates associated with this alias will be
+     * revoked.
+     *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
      *            {@code null} if calling from a delegated certificate installer.
      * @param privKey The private key to install.
@@ -4645,6 +4649,10 @@
      * immediately, without user approval. It is a best practice not to request this unless strictly
      * necessary since it opens up additional security vulnerabilities.
      *
+     * <p>Note: If the provided {@code alias} is of an existing alias, all former grants that apps
+     * have been given to access the key and certificates associated with this alias will be
+     * revoked.
+     *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
      *        {@code null} if calling from a delegated certificate installer.
      * @param privKey The private key to install.
@@ -4685,6 +4693,10 @@
      * <p>Include {@link #INSTALLKEY_SET_USER_SELECTABLE} in the {@code flags} argument to allow
      * the user to select the key from a dialog.
      *
+     * <p>Note: If the provided {@code alias} is of an existing alias, all former grants that apps
+     * have been given to access the key and certificates associated with this alias will be
+     * revoked.
+     *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
      *        {@code null} if calling from a delegated certificate installer.
      * @param privKey The private key to install.
@@ -4761,6 +4773,10 @@
      * <p>Because this method might take several seconds to complete, it should only be called from
      * a worker thread. This method returns {@code null} when called from the main thread.
      *
+     * <p>Note: If the provided {@code alias} is of an existing alias, all former grants that apps
+     * have been given to access the key and certificates associated with this alias will be
+     * revoked.
+     *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
      *            {@code null} if calling from a delegated certificate installer.
      * @param algorithm The key generation algorithm, see {@link java.security.KeyPairGenerator}.
@@ -6408,11 +6424,9 @@
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param packageName The name of the package to set as the default SMS application.
      * @throws SecurityException if {@code admin} is not a device owner.
-     *
-     * @hide
      */
-    @UnsupportedAppUsage
-    public void setDefaultSmsApplication(@NonNull ComponentName admin, String packageName) {
+    public void setDefaultSmsApplication(@NonNull ComponentName admin,
+            @NonNull String packageName) {
         throwIfParentInstance("setDefaultSmsApplication");
         if (mService != null) {
             try {
@@ -9630,7 +9644,7 @@
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param enabled {@code true} to enable the backup service, {@code false} to disable it.
-     * @throws SecurityException if {@code admin} is not a device owner.
+     * @throws SecurityException if {@code admin} is not a device owner or a profile owner.
      */
     public void setBackupServiceEnabled(@NonNull ComponentName admin, boolean enabled) {
         throwIfParentInstance("setBackupServiceEnabled");
diff --git a/core/java/android/app/backup/BackupManager.java b/core/java/android/app/backup/BackupManager.java
index a6f6d06..868fbfe 100644
--- a/core/java/android/app/backup/BackupManager.java
+++ b/core/java/android/app/backup/BackupManager.java
@@ -751,6 +751,47 @@
     }
 
     /**
+     * Returns a {@link UserHandle} for the user that has {@code ancestralSerialNumber} as the
+     * serial number of the its ancestral work profile or {@code null} if there is none.
+     *
+     * <p> The ancestral serial number will have a corresponding {@link UserHandle} if the device
+     * has a work profile that was restored from another work profile with serial number
+     * {@code ancestralSerialNumber}.
+     *
+     * @see UserManager#getSerialNumberForUser(UserHandle)
+     */
+    @Nullable
+    public UserHandle getUserForAncestralSerialNumber(long ancestralSerialNumber) {
+        if (sService != null) {
+            try {
+                return sService.getUserForAncestralSerialNumber(ancestralSerialNumber);
+            } catch (RemoteException e) {
+                Log.e(TAG, "getUserForAncestralSerialNumber() couldn't connect");
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Sets the ancestral work profile for the calling user.
+     *
+     * <p> The ancestral work profile corresponds to the profile that was used to restore to the
+     * callers profile.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.BACKUP)
+    public void setAncestralSerialNumber(long ancestralSerialNumber) {
+        if (sService != null) {
+            try {
+                sService.setAncestralSerialNumber(ancestralSerialNumber);
+            } catch (RemoteException e) {
+                Log.e(TAG, "setAncestralSerialNumber() couldn't connect");
+            }
+        }
+    }
+
+    /**
      * Returns an {@link Intent} for the specified transport's configuration UI.
      * This value is set by {@link #updateTransportAttributes(ComponentName, String, Intent, String,
      * Intent, String)}.
diff --git a/core/java/android/app/backup/IBackupManager.aidl b/core/java/android/app/backup/IBackupManager.aidl
index eda8981..8386c72 100644
--- a/core/java/android/app/backup/IBackupManager.aidl
+++ b/core/java/android/app/backup/IBackupManager.aidl
@@ -22,6 +22,7 @@
 import android.app.backup.IRestoreSession;
 import android.app.backup.ISelectBackupTransportCallback;
 import android.os.ParcelFileDescriptor;
+import android.os.UserHandle;
 import android.content.Intent;
 import android.content.ComponentName;
 
@@ -685,4 +686,24 @@
      * {@link android.app.backup.IBackupManager.cancelBackups} for the calling user id.
      */
     void cancelBackups();
+
+    /**
+     * Returns a {@link UserHandle} for the user that has {@code ancestralSerialNumber} as the serial
+     * number of the it's ancestral work profile.
+     *
+     * <p> The ancestral work profile is set by {@link #setAncestralSerialNumber(long)}
+     * and it corresponds to the profile that was used to restore to the callers profile.
+     */
+    UserHandle getUserForAncestralSerialNumber(in long ancestralSerialNumber);
+
+    /**
+     * Sets the ancestral work profile for the calling user.
+     *
+     * <p> The ancestral work profile corresponds to the profile that was used to restore to the
+     * callers profile.
+     *
+     * <p>Callers must hold the android.permission.BACKUP permission to use this method.
+     */
+    void setAncestralSerialNumber(in long ancestralSerialNumber);
+
 }
diff --git a/core/java/android/app/role/IRoleManager.aidl b/core/java/android/app/role/IRoleManager.aidl
index cf62e8d..76dbf7e 100644
--- a/core/java/android/app/role/IRoleManager.aidl
+++ b/core/java/android/app/role/IRoleManager.aidl
@@ -32,13 +32,14 @@
 
     List<String> getRoleHoldersAsUser(in String roleName, int userId);
 
-    void addRoleHolderAsUser(in String roleName, in String packageName, int userId,
+    void addRoleHolderAsUser(in String roleName, in String packageName, int flags, int userId,
             in IRoleManagerCallback callback);
 
-    void removeRoleHolderAsUser(in String roleName, in String packageName, int userId,
+    void removeRoleHolderAsUser(in String roleName, in String packageName, int flags, int userId,
             in IRoleManagerCallback callback);
 
-    void clearRoleHoldersAsUser(in String roleName, int userId, in IRoleManagerCallback callback);
+    void clearRoleHoldersAsUser(in String roleName, int flags, int userId,
+            in IRoleManagerCallback callback);
 
     void addOnRoleHoldersChangedListenerAsUser(IOnRoleHoldersChangedListener listener, int userId);
 
diff --git a/core/java/android/app/role/RoleManager.java b/core/java/android/app/role/RoleManager.java
index ddd5313..edd3ef98 100644
--- a/core/java/android/app/role/RoleManager.java
+++ b/core/java/android/app/role/RoleManager.java
@@ -18,6 +18,7 @@
 
 import android.Manifest;
 import android.annotation.CallbackExecutor;
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
@@ -68,6 +69,22 @@
     private static final String LOG_TAG = RoleManager.class.getSimpleName();
 
     /**
+     * The name of the assistant app role.
+     *
+     * @hide
+     */
+    @SystemApi
+    @TestApi
+    public static final String ROLE_ASSISTANT = "android.app.role.ASSISTANT";
+
+    /**
+     * The name of the browser role.
+     *
+     * @see Intent#CATEGORY_APP_BROWSER
+     */
+    public static final String ROLE_BROWSER = "android.app.role.BROWSER";
+
+    /**
      * The name of the dialer role.
      *
      * @see Intent#ACTION_DIAL
@@ -82,25 +99,11 @@
     public static final String ROLE_SMS = "android.app.role.SMS";
 
     /**
-     * The name of the browser role.
+     * The name of the emergency role
      *
-     * @see Intent#CATEGORY_APP_BROWSER
+     * @see android.telephony.TelephonyManager#ACTION_EMERGENCY_ASSISTANCE
      */
-    public static final String ROLE_BROWSER = "android.app.role.BROWSER";
-
-    /**
-     * The name of the gallery role.
-     *
-     * @see Intent#CATEGORY_APP_GALLERY
-     */
-    public static final String ROLE_GALLERY = "android.app.role.GALLERY";
-
-    /**
-     * The name of the music player role.
-     *
-     * @see Intent#CATEGORY_APP_MUSIC
-     */
-    public static final String ROLE_MUSIC = "android.app.role.MUSIC";
+    public static final String ROLE_EMERGENCY = "android.app.role.EMERGENCY";
 
     /**
      * The name of the home role.
@@ -110,11 +113,18 @@
     public static final String ROLE_HOME = "android.app.role.HOME";
 
     /**
-     * The name of the emergency role
+     * The name of the music player role.
      *
-     * @see android.telephony.TelephonyManager#ACTION_EMERGENCY_ASSISTANCE
+     * @see Intent#CATEGORY_APP_MUSIC
      */
-    public static final String ROLE_EMERGENCY = "android.app.role.EMERGENCY";
+    public static final String ROLE_MUSIC = "android.app.role.MUSIC";
+
+    /**
+     * The name of the gallery role.
+     *
+     * @see Intent#CATEGORY_APP_GALLERY
+     */
+    public static final String ROLE_GALLERY = "android.app.role.GALLERY";
 
     /**
      * The name of the car mode dialer app role.
@@ -130,20 +140,20 @@
      * TODO: STOPSHIP: Make name of required roles public API
      * @hide
      */
-    public static final String ROLE_CAR_MODE_DIALER_APP = "android.app.role.CAR_MODE_DIALER_APP";
+    public static final String ROLE_CAR_MODE_DIALER = "android.app.role.CAR_MODE_DIALER";
 
     /**
-     * The name of the proxy calling role.
+     * The name of the call redirection role.
      * <p>
-     * A proxy calling app provides a means to re-write the phone number for an outgoing call to
-     * place the call through a proxy calling service.
+     * A call redirection app provides a means to re-write the phone number for an outgoing call to
+     * place the call through a call redirection service.
      *
      * @see android.telecom.CallRedirectionService
      *
      * TODO: STOPSHIP: Make name of required roles public API
      * @hide
      */
-    public static final String ROLE_PROXY_CALLING_APP = "android.app.role.PROXY_CALLING_APP";
+    public static final String ROLE_CALL_REDIRECTION = "android.app.role.CALL_REDIRECTION";
 
     /**
      * The name of the call screening and caller id role.
@@ -153,7 +163,7 @@
      * TODO: STOPSHIP: Make name of required roles public API
      * @hide
      */
-    public static final String ROLE_CALL_SCREENING_APP = "android.app.role.CALL_SCREENING_APP";
+    public static final String ROLE_CALL_SCREENING = "android.app.role.CALL_SCREENING";
 
     /**
      * The name of the call companion app role.
@@ -169,16 +179,23 @@
      * TODO: STOPSHIP: Make name of required roles public API
      * @hide
      */
-    public static final String ROLE_CALL_COMPANION_APP = "android.app.role.CALL_COMPANION_APP";
+    public static final String ROLE_CALL_COMPANION = "android.app.role.CALL_COMPANION";
 
     /**
-     * The name of the assistant app role.
+     * @hide
+     */
+    @IntDef(flag = true, value = { MANAGE_HOLDERS_FLAG_DONT_KILL_APP })
+    public @interface ManageHoldersFlags {}
+
+    /**
+     * Flag parameter for {@link #addRoleHolderAsUser}, {@link #removeRoleHolderAsUser} and
+     * {@link #clearRoleHoldersAsUser} to indicate that apps should not be killed when changing
+     * their role holder status.
      *
      * @hide
      */
     @SystemApi
-    @TestApi
-    public static final String ROLE_ASSISTANT = "android.app.role.ASSISTANT";
+    public static final int MANAGE_HOLDERS_FLAG_DONT_KILL_APP = 1;
 
     /**
      * The action used to request user approval of a role for an application.
@@ -305,9 +322,9 @@
      *
      * @return a list of package names of the role holders, or an empty list if none.
      *
-     * @see #addRoleHolderAsUser(String, String, UserHandle, Executor, RoleManagerCallback)
-     * @see #removeRoleHolderAsUser(String, String, UserHandle, Executor, RoleManagerCallback)
-     * @see #clearRoleHoldersAsUser(String, UserHandle, Executor, RoleManagerCallback)
+     * @see #addRoleHolderAsUser(String, String, int, UserHandle, Executor, RoleManagerCallback)
+     * @see #removeRoleHolderAsUser(String, String, int, UserHandle, Executor, RoleManagerCallback)
+     * @see #clearRoleHoldersAsUser(String, int, UserHandle, Executor, RoleManagerCallback)
      *
      * @hide
      */
@@ -335,13 +352,14 @@
      *
      * @param roleName the name of the role to add the role holder for
      * @param packageName the package name of the application to add to the role holders
+     * @param flags optional behavior flags
      * @param user the user to add the role holder for
      * @param executor the {@code Executor} to run the callback on.
      * @param callback the callback for whether this call is successful
      *
      * @see #getRoleHoldersAsUser(String, UserHandle)
-     * @see #removeRoleHolderAsUser(String, String, UserHandle, Executor, RoleManagerCallback)
-     * @see #clearRoleHoldersAsUser(String, UserHandle, Executor, RoleManagerCallback)
+     * @see #removeRoleHolderAsUser(String, String, int, UserHandle, Executor, RoleManagerCallback)
+     * @see #clearRoleHoldersAsUser(String, int, UserHandle, Executor, RoleManagerCallback)
      *
      * @hide
      */
@@ -349,15 +367,15 @@
     @SystemApi
     @TestApi
     public void addRoleHolderAsUser(@NonNull String roleName, @NonNull String packageName,
-            @NonNull UserHandle user, @CallbackExecutor @NonNull Executor executor,
-            @NonNull RoleManagerCallback callback) {
+            @ManageHoldersFlags int flags, @NonNull UserHandle user,
+            @CallbackExecutor @NonNull Executor executor, @NonNull RoleManagerCallback callback) {
         Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
         Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
         Preconditions.checkNotNull(user, "user cannot be null");
         Preconditions.checkNotNull(executor, "executor cannot be null");
         Preconditions.checkNotNull(callback, "callback cannot be null");
         try {
-            mService.addRoleHolderAsUser(roleName, packageName, user.getIdentifier(),
+            mService.addRoleHolderAsUser(roleName, packageName, flags, user.getIdentifier(),
                     new RoleManagerCallbackDelegate(executor, callback));
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
@@ -373,13 +391,14 @@
      *
      * @param roleName the name of the role to remove the role holder for
      * @param packageName the package name of the application to remove from the role holders
+     * @param flags optional behavior flags
      * @param user the user to remove the role holder for
      * @param executor the {@code Executor} to run the callback on.
      * @param callback the callback for whether this call is successful
      *
      * @see #getRoleHoldersAsUser(String, UserHandle)
-     * @see #addRoleHolderAsUser(String, String, UserHandle, Executor, RoleManagerCallback)
-     * @see #clearRoleHoldersAsUser(String, UserHandle, Executor, RoleManagerCallback)
+     * @see #addRoleHolderAsUser(String, String, int, UserHandle, Executor, RoleManagerCallback)
+     * @see #clearRoleHoldersAsUser(String, int, UserHandle, Executor, RoleManagerCallback)
      *
      * @hide
      */
@@ -387,15 +406,15 @@
     @SystemApi
     @TestApi
     public void removeRoleHolderAsUser(@NonNull String roleName, @NonNull String packageName,
-            @NonNull UserHandle user, @CallbackExecutor @NonNull Executor executor,
-            @NonNull RoleManagerCallback callback) {
+            @ManageHoldersFlags int flags, @NonNull UserHandle user,
+            @CallbackExecutor @NonNull Executor executor, @NonNull RoleManagerCallback callback) {
         Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
         Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
         Preconditions.checkNotNull(user, "user cannot be null");
         Preconditions.checkNotNull(executor, "executor cannot be null");
         Preconditions.checkNotNull(callback, "callback cannot be null");
         try {
-            mService.removeRoleHolderAsUser(roleName, packageName, user.getIdentifier(),
+            mService.removeRoleHolderAsUser(roleName, packageName, flags, user.getIdentifier(),
                     new RoleManagerCallbackDelegate(executor, callback));
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
@@ -410,27 +429,29 @@
      * {@code android.permission.INTERACT_ACROSS_USERS_FULL}.
      *
      * @param roleName the name of the role to remove role holders for
+     * @param flags optional behavior flags
      * @param user the user to remove role holders for
      * @param executor the {@code Executor} to run the callback on.
      * @param callback the callback for whether this call is successful
      *
      * @see #getRoleHoldersAsUser(String, UserHandle)
-     * @see #addRoleHolderAsUser(String, String, UserHandle, Executor, RoleManagerCallback)
-     * @see #removeRoleHolderAsUser(String, String, UserHandle, Executor, RoleManagerCallback)
+     * @see #addRoleHolderAsUser(String, String, int, UserHandle, Executor, RoleManagerCallback)
+     * @see #removeRoleHolderAsUser(String, String, int, UserHandle, Executor, RoleManagerCallback)
      *
      * @hide
      */
     @RequiresPermission(Manifest.permission.MANAGE_ROLE_HOLDERS)
     @SystemApi
     @TestApi
-    public void clearRoleHoldersAsUser(@NonNull String roleName, @NonNull UserHandle user,
-            @CallbackExecutor @NonNull Executor executor, @NonNull RoleManagerCallback callback) {
+    public void clearRoleHoldersAsUser(@NonNull String roleName, @ManageHoldersFlags int flags,
+            @NonNull UserHandle user, @CallbackExecutor @NonNull Executor executor,
+            @NonNull RoleManagerCallback callback) {
         Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
         Preconditions.checkNotNull(user, "user cannot be null");
         Preconditions.checkNotNull(executor, "executor cannot be null");
         Preconditions.checkNotNull(callback, "callback cannot be null");
         try {
-            mService.clearRoleHoldersAsUser(roleName, user.getIdentifier(),
+            mService.clearRoleHoldersAsUser(roleName, flags, user.getIdentifier(),
                     new RoleManagerCallbackDelegate(executor, callback));
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 47a4a2d..f1bfe86 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -2748,6 +2748,19 @@
     }
 
     /**
+     * @see #setIsSyncable(Account, String, int)
+     * @hide
+     */
+    public static void setIsSyncableAsUser(Account account, String authority, int syncable,
+            int userId) {
+        try {
+            getContentService().setIsSyncableAsUser(account, authority, syncable, userId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Gets the master auto-sync setting that applies to all the providers and accounts.
      * If this is false then the per-provider auto-sync setting is ignored.
      * <p>This method requires the caller to hold the permission
diff --git a/core/java/android/content/IContentService.aidl b/core/java/android/content/IContentService.aidl
index 1d02375..9f6e236 100644
--- a/core/java/android/content/IContentService.aidl
+++ b/core/java/android/content/IContentService.aidl
@@ -126,6 +126,7 @@
      * @param syncable, >0 denotes syncable, 0 means not syncable, <0 means unknown
      */
     void setIsSyncable(in Account account, String providerName, int syncable);
+    void setIsSyncableAsUser(in Account account, String providerName, int syncable, int userId);
 
     void setMasterSyncAutomatically(boolean flag);
     void setMasterSyncAutomaticallyAsUser(boolean flag, int userId);
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index a3021f3..d781a96 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -817,28 +817,6 @@
             = "android.intent.action.SHOW_APP_INFO";
 
     /**
-     * Activity Action: Start an activity to show the app's detailed usage information for
-     * permission protected data.
-     *
-     * The Intent contains an extra {@link #EXTRA_PERMISSION_USAGE_PERMISSIONS} that is of
-     * type {@code String[]} and contains the specific permissions to show information for.
-     *
-     * Apps should handle this intent if they want to provide more information about permission
-     * usage to users beyond the information provided in the manifest.
-     */
-    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
-    public static final String ACTION_PERMISSION_USAGE_DETAILS =
-            "android.intent.action.PERMISSION_USAGE_DETAILS";
-
-    /**
-     * The name of the extra used to contain the permissions in
-     * {@link #ACTION_PERMISSION_USAGE_DETAILS}.
-     * @see #ACTION_PERMISSION_USAGE_DETAILS
-     */
-    public static final String EXTRA_PERMISSION_USAGE_PERMISSIONS =
-            "android.intent.extra.PERMISSION_USAGE_PERMISSIONS";
-
-    /**
      * Represents a shortcut/live folder icon resource.
      *
      * @see Intent#ACTION_CREATE_SHORTCUT
diff --git a/core/java/android/content/pm/PackageInfo.java b/core/java/android/content/pm/PackageInfo.java
index 6d22277..27a5b39 100644
--- a/core/java/android/content/pm/PackageInfo.java
+++ b/core/java/android/content/pm/PackageInfo.java
@@ -204,10 +204,7 @@
      * {@link PackageManager#GET_PERMISSIONS} was set.  This list includes
      * all permissions requested, even those that were not granted or known
      * by the system at install time.
-     *
-     * @deprecated Use {@link #usesPermissions}
      */
-    @Deprecated
     public String[] requestedPermissions;
 
     /**
@@ -217,23 +214,10 @@
      * {@link PackageManager#GET_PERMISSIONS} was set.  Each value matches
      * the corresponding entry in {@link #requestedPermissions}, and will have
      * the flag {@link #REQUESTED_PERMISSION_GRANTED} set as appropriate.
-     *
-     * @deprecated Use {@link #usesPermissions}
      */
-    @Deprecated
     public int[] requestedPermissionsFlags;
 
     /**
-     * Array of all {@link android.R.styleable#AndroidManifestUsesPermission
-     * &lt;uses-permission&gt;} tags included under &lt;manifest&gt;,
-     * or null if there were none.  This is only filled in if the flag
-     * {@link PackageManager#GET_PERMISSIONS} was set.  This list includes
-     * all permissions requested, even those that were not granted or known
-     * by the system at install time.
-     */
-    public UsesPermissionInfo[] usesPermissions;
-
-    /**
      * Flag for {@link #requestedPermissionsFlags}: the requested permission
      * is required for the application to run; the user can not optionally
      * disable it.  Currently all permissions are required.
@@ -480,7 +464,6 @@
         dest.writeTypedArray(permissions, parcelableFlags);
         dest.writeStringArray(requestedPermissions);
         dest.writeIntArray(requestedPermissionsFlags);
-        dest.writeTypedArray(usesPermissions, parcelableFlags);
         dest.writeTypedArray(signatures, parcelableFlags);
         dest.writeTypedArray(configPreferences, parcelableFlags);
         dest.writeTypedArray(reqFeatures, parcelableFlags);
@@ -545,7 +528,6 @@
         permissions = source.createTypedArray(PermissionInfo.CREATOR);
         requestedPermissions = source.createStringArray();
         requestedPermissionsFlags = source.createIntArray();
-        usesPermissions = source.createTypedArray(UsesPermissionInfo.CREATOR);
         signatures = source.createTypedArray(Signature.CREATOR);
         configPreferences = source.createTypedArray(ConfigurationInfo.CREATOR);
         reqFeatures = source.createTypedArray(FeatureInfo.CREATOR);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 6e52b33..eaf6c5a 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -715,7 +715,6 @@
             INSTALL_FORCE_PERMISSION_PROMPT,
             INSTALL_INSTANT_APP,
             INSTALL_DONT_KILL_APP,
-            INSTALL_FORCE_SDK,
             INSTALL_FULL_APP,
             INSTALL_ALLOCATE_AGGRESSIVE,
             INSTALL_VIRTUAL_PRELOAD,
@@ -816,15 +815,6 @@
     public static final int INSTALL_DONT_KILL_APP = 0x00001000;
 
     /**
-     * Flag parameter for {@link #installPackage} to indicate that this package is an
-     * upgrade to a package that refers to the SDK via release letter or is targeting an SDK via
-     * release letter that the current build does not support.
-     *
-     * @hide
-     */
-    public static final int INSTALL_FORCE_SDK = 0x00002000;
-
-    /**
      * Flag parameter for {@link #installPackage} to indicate that this package is
      * to be installed as a heavy weight app. This is fundamentally the opposite of
      * {@link #INSTALL_INSTANT_APP}.
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 6044914..96b6eb52 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -791,23 +791,18 @@
                     pi.permissions[i] = generatePermissionInfo(p.permissions.get(i), flags);
                 }
             }
-            N = p.usesPermissionInfos.size();
+            N = p.requestedPermissions.size();
             if (N > 0) {
                 pi.requestedPermissions = new String[N];
                 pi.requestedPermissionsFlags = new int[N];
-                pi.usesPermissions = new UsesPermissionInfo[N];
                 for (int i=0; i<N; i++) {
-                    UsesPermissionInfo info = p.usesPermissionInfos.get(i);
-                    final String perm = info.getPermission();
+                    final String perm = p.requestedPermissions.get(i);
                     pi.requestedPermissions[i] = perm;
-                    int permissionFlags = 0;
                     // The notion of required permissions is deprecated but for compatibility.
-                    permissionFlags |= PackageInfo.REQUESTED_PERMISSION_REQUIRED;
+                    pi.requestedPermissionsFlags[i] |= PackageInfo.REQUESTED_PERMISSION_REQUIRED;
                     if (grantedPermissions != null && grantedPermissions.contains(perm)) {
-                        permissionFlags |= PackageInfo.REQUESTED_PERMISSION_GRANTED;
+                        pi.requestedPermissionsFlags[i] |= PackageInfo.REQUESTED_PERMISSION_GRANTED;
                     }
-                    pi.requestedPermissionsFlags[i] = permissionFlags;
-                    pi.usesPermissions[i] = new UsesPermissionInfo(info, permissionFlags);
                 }
             }
         }
@@ -844,7 +839,6 @@
     public static final int PARSE_IS_SYSTEM_DIR = 1 << 4;
     public static final int PARSE_COLLECT_CERTIFICATES = 1 << 5;
     public static final int PARSE_ENFORCE_CODE = 1 << 6;
-    public static final int PARSE_FORCE_SDK = 1 << 7;
     public static final int PARSE_CHATTY = 1 << 31;
 
     @IntDef(flag = true, prefix = { "PARSE_" }, value = {
@@ -852,7 +846,6 @@
             PARSE_COLLECT_CERTIFICATES,
             PARSE_ENFORCE_CODE,
             PARSE_EXTERNAL_STORAGE,
-            PARSE_FORCE_SDK,
             PARSE_IGNORE_PROCESSES,
             PARSE_IS_SYSTEM_DIR,
             PARSE_MUST_BE_APK,
@@ -2175,12 +2168,12 @@
                     return null;
                 }
             } else if (tagName.equals(TAG_USES_PERMISSION)) {
-                if (!parseUsesPermission(pkg, res, parser, outError)) {
+                if (!parseUsesPermission(pkg, res, parser)) {
                     return null;
                 }
             } else if (tagName.equals(TAG_USES_PERMISSION_SDK_M)
                     || tagName.equals(TAG_USES_PERMISSION_SDK_23)) {
-                if (!parseUsesPermission(pkg, res, parser, outError)) {
+                if (!parseUsesPermission(pkg, res, parser)) {
                     return null;
                 }
             } else if (tagName.equals(TAG_USES_CONFIGURATION)) {
@@ -2498,7 +2491,7 @@
                     newPermsMsg.append(' ');
                 }
                 newPermsMsg.append(npi.name);
-                addRequestedPermission(pkg, npi.name);
+                pkg.requestedPermissions.add(npi.name);
                 pkg.implicitPermissions.add(npi.name);
             }
         }
@@ -2519,7 +2512,7 @@
             for (int in = 0; in < newPerms.size(); in++) {
                 final String perm = newPerms.get(in);
                 if (!pkg.requestedPermissions.contains(perm)) {
-                    addRequestedPermission(pkg, perm);
+                    pkg.requestedPermissions.add(perm);
                     pkg.implicitPermissions.add(perm);
                 }
             }
@@ -2599,13 +2592,13 @@
             }
         } else {
             if (FORCE_AUDIO_PACKAGES.contains(pkg.packageName)) {
-                addRequestedPermission(pkg, android.Manifest.permission.READ_MEDIA_AUDIO);
+                pkg.requestedPermissions.add(android.Manifest.permission.READ_MEDIA_AUDIO);
             }
             if (FORCE_VIDEO_PACKAGES.contains(pkg.packageName)) {
-                addRequestedPermission(pkg, android.Manifest.permission.READ_MEDIA_VIDEO);
+                pkg.requestedPermissions.add(android.Manifest.permission.READ_MEDIA_VIDEO);
             }
             if (FORCE_IMAGES_PACKAGES.contains(pkg.packageName)) {
-                addRequestedPermission(pkg, android.Manifest.permission.READ_MEDIA_IMAGES);
+                pkg.requestedPermissions.add(android.Manifest.permission.READ_MEDIA_IMAGES);
             }
         }
 
@@ -2645,12 +2638,6 @@
     }
 
     /**
-     * Helper method for adding a requested permission to a package outside of a uses-permission.
-     */
-    private void addRequestedPermission(Package pkg, String permission) {
-        pkg.requestedPermissions.add(permission);
-        pkg.usesPermissionInfos.add(new UsesPermissionInfo(permission));
-    }
 
     /**
      * Matches a given {@code targetCode} against a set of release codeNames. Target codes can
@@ -2695,8 +2682,6 @@
      * @param platformSdkCodenames array of allowed pre-release SDK codenames
      *                             for this platform
      * @param outError output array to populate with error, if applicable
-     * @param forceCurrentDev if development target code is not available, use the current
-     *                        development version by default.
      * @return the targetSdkVersion to use at runtime, or -1 if the package is
      *         not compatible with this platform
      * @hide Exposed for unit testing only.
@@ -2704,7 +2689,7 @@
     @TestApi
     public static int computeTargetSdkVersion(@IntRange(from = 0) int targetVers,
             @Nullable String targetCode, @NonNull String[] platformSdkCodenames,
-            @NonNull String[] outError, boolean forceCurrentDev) {
+            @NonNull String[] outError) {
         // If it's a release SDK, return the version number unmodified.
         if (targetCode == null) {
             return targetVers;
@@ -2712,7 +2697,7 @@
 
         // If it's a pre-release SDK and the codename matches this platform, it
         // definitely targets this SDK.
-        if (matchTargetCode(platformSdkCodenames, targetCode) || forceCurrentDev) {
+        if (matchTargetCode(platformSdkCodenames, targetCode)) {
             return Build.VERSION_CODES.CUR_DEVELOPMENT;
         }
 
@@ -2779,9 +2764,8 @@
             return null;
         }
 
-        boolean defaultToCurrentDevBranch = (flags & PARSE_FORCE_SDK) != 0;
         final int targetSdkVersion = computeTargetSdkVersion(targetVers,
-                targetCode, SDK_CODENAMES, outError, defaultToCurrentDevBranch);
+                targetCode, SDK_CODENAMES, outError);
         if (targetSdkVersion < 0) {
             return null;
         }
@@ -2987,8 +2971,8 @@
         return certSha256Digests;
     }
 
-    private boolean parseUsesPermission(Package pkg, Resources res, XmlResourceParser parser,
-            String[] outError) throws XmlPullParserException, IOException {
+    private boolean parseUsesPermission(Package pkg, Resources res, XmlResourceParser parser)
+            throws XmlPullParserException, IOException {
         TypedArray sa = res.obtainAttributes(parser,
                 com.android.internal.R.styleable.AndroidManifestUsesPermission);
 
@@ -3012,44 +2996,6 @@
         final String requiredNotfeature = sa.getNonConfigurationString(
                 com.android.internal.R.styleable.AndroidManifestUsesPermission_requiredNotFeature, 0);
 
-        int dataSentOffDevice = sa.getInt(
-                com.android.internal.R.styleable.AndroidManifestUsesPermission_dataSentOffDevice, 0);
-
-        int dataSharedWithThirdParty = sa.getInt(
-                com.android.internal.R.styleable.AndroidManifestUsesPermission_dataSharedWithThirdParty, 0);
-
-        int dataUsedForMonetization = sa.getInt(
-                com.android.internal.R.styleable.AndroidManifestUsesPermission_dataUsedForMonetization, 0);
-
-        int retentionWeeks = -1;
-        int retention;
-
-        String rawRetention = sa.getString(
-                com.android.internal.R.styleable.AndroidManifestUsesPermission_dataRetentionTime);
-
-        if (rawRetention == null) {
-            retention = UsesPermissionInfo.RETENTION_UNDEFINED;
-        } else if ("notRetained".equals(rawRetention)) {
-            retention = UsesPermissionInfo.RETENTION_NOT_RETAINED;
-        } else if ("userSelected".equals(rawRetention)) {
-            retention = UsesPermissionInfo.RETENTION_USER_SELECTED;
-        } else if ("unlimited".equals(rawRetention)) {
-            retention = UsesPermissionInfo.RETENTION_UNLIMITED;
-        } else {
-            // A number of weeks was specified
-            retention = UsesPermissionInfo.RETENTION_SPECIFIED;
-            retentionWeeks = sa.getInt(
-                com.android.internal.R.styleable.AndroidManifestUsesPermission_dataRetentionTime,
-                -1);
-
-            if (retentionWeeks < 0) {
-                outError[0] = "Bad value provided for dataRetentionTime.";
-                mParseError = PackageManager.INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
-                XmlUtils.skipCurrentTag(parser);
-                sa.recycle();
-                return false;
-            }
-        }
         sa.recycle();
 
         XmlUtils.skipCurrentTag(parser);
@@ -3082,10 +3028,6 @@
                     + parser.getPositionDescription());
         }
 
-        UsesPermissionInfo info = new UsesPermissionInfo(name, dataSentOffDevice,
-                dataSharedWithThirdParty, dataUsedForMonetization, retention, retentionWeeks);
-        pkg.usesPermissionInfos.add(info);
-
         return true;
     }
 
@@ -3420,10 +3362,6 @@
         perm.info.flags = sa.getInt(
                 com.android.internal.R.styleable.AndroidManifestPermission_permissionFlags, 0);
 
-        perm.info.usageInfoRequired = sa.getInt(
-                com.android.internal.R.styleable.AndroidManifestPermission_usageInfoRequired, 0)
-                != 0;
-
         sa.recycle();
 
         if (perm.info.protectionLevel == -1) {
@@ -5260,6 +5198,10 @@
                 com.android.internal.R.styleable.AndroidManifestProvider_grantUriPermissions,
                 false);
 
+        p.info.forceUriPermissions = sa.getBoolean(
+                com.android.internal.R.styleable.AndroidManifestProvider_forceUriPermissions,
+                false);
+
         p.info.multiprocess = sa.getBoolean(
                 com.android.internal.R.styleable.AndroidManifestProvider_multiprocess,
                 false);
@@ -6621,9 +6563,6 @@
         @UnsupportedAppUsage
         public final ArrayList<String> requestedPermissions = new ArrayList<String>();
 
-        public final ArrayList<UsesPermissionInfo> usesPermissionInfos =
-                new ArrayList<>();
-
         /** Permissions requested but not in the manifest. */
         public final ArrayList<String> implicitPermissions = new ArrayList<>();
 
@@ -7155,7 +7094,6 @@
 
             dest.readStringList(requestedPermissions);
             internStringArrayList(requestedPermissions);
-            dest.readParcelableList(usesPermissionInfos, boot);
             dest.readStringList(implicitPermissions);
             internStringArrayList(implicitPermissions);
             protectedBroadcasts = dest.createStringArrayList();
@@ -7323,7 +7261,6 @@
             dest.writeParcelableList(instrumentation, flags);
 
             dest.writeStringList(requestedPermissions);
-            dest.writeParcelableList(usesPermissionInfos, flags);
             dest.writeStringList(implicitPermissions);
             dest.writeStringList(protectedBroadcasts);
 
diff --git a/core/java/android/content/pm/PermissionInfo.java b/core/java/android/content/pm/PermissionInfo.java
index fb63e0d..e245234 100644
--- a/core/java/android/content/pm/PermissionInfo.java
+++ b/core/java/android/content/pm/PermissionInfo.java
@@ -20,7 +20,6 @@
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
-import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.TextUtils;
@@ -368,12 +367,6 @@
      */
     public CharSequence nonLocalizedDescription;
 
-    /**
-     * If {@code true} an application targeting {@link Build.VERSION_CODES#Q} <em>must</em>
-     * include permission data usage information in order to be able to be granted this permission.
-     */
-    public boolean usageInfoRequired;
-
     /** @hide */
     public static int fixProtectionLevel(int level) {
         if (level == PROTECTION_SIGNATURE_OR_SYSTEM) {
@@ -475,7 +468,6 @@
         descriptionRes = orig.descriptionRes;
         requestRes = orig.requestRes;
         nonLocalizedDescription = orig.nonLocalizedDescription;
-        usageInfoRequired = orig.usageInfoRequired;
     }
 
     /**
@@ -540,7 +532,6 @@
         dest.writeInt(descriptionRes);
         dest.writeInt(requestRes);
         TextUtils.writeToParcel(nonLocalizedDescription, dest, parcelableFlags);
-        dest.writeInt(usageInfoRequired ? 1 : 0);
     }
 
     /** @hide */
@@ -581,6 +572,5 @@
         descriptionRes = source.readInt();
         requestRes = source.readInt();
         nonLocalizedDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source);
-        usageInfoRequired = source.readInt() != 0;
     }
 }
diff --git a/core/java/android/content/pm/ProviderInfo.java b/core/java/android/content/pm/ProviderInfo.java
index 379b783..f06a628 100644
--- a/core/java/android/content/pm/ProviderInfo.java
+++ b/core/java/android/content/pm/ProviderInfo.java
@@ -47,7 +47,13 @@
      * grantUriPermissions} attribute.
      */
     public boolean grantUriPermissions = false;
-    
+
+    /** If true, always apply URI permission grants, as per the
+     * {@link android.R.styleable#AndroidManifestProvider_forceUriPermissions
+     * forceUriPermissions} attribute.
+     */
+    public boolean forceUriPermissions = false;
+
     /**
      * If non-null, these are the patterns that are allowed for granting URI
      * permissions.  Any URI that does not match one of these patterns will not
@@ -112,6 +118,7 @@
         readPermission = orig.readPermission;
         writePermission = orig.writePermission;
         grantUriPermissions = orig.grantUriPermissions;
+        forceUriPermissions = orig.forceUriPermissions;
         uriPermissionPatterns = orig.uriPermissionPatterns;
         pathPermissions = orig.pathPermissions;
         multiprocess = orig.multiprocess;
@@ -142,6 +149,7 @@
         out.writeString(readPermission);
         out.writeString(writePermission);
         out.writeInt(grantUriPermissions ? 1 : 0);
+        out.writeInt(forceUriPermissions ? 1 : 0);
         out.writeTypedArray(uriPermissionPatterns, parcelableFlags);
         out.writeTypedArray(pathPermissions, parcelableFlags);
         out.writeInt(multiprocess ? 1 : 0);
@@ -171,6 +179,7 @@
         readPermission = in.readString();
         writePermission = in.readString();
         grantUriPermissions = in.readInt() != 0;
+        forceUriPermissions = in.readInt() != 0;
         uriPermissionPatterns = in.createTypedArray(PatternMatcher.CREATOR);
         pathPermissions = in.createTypedArray(PathPermission.CREATOR);
         multiprocess = in.readInt() != 0;
diff --git a/core/java/android/content/pm/UsesPermissionInfo.java b/core/java/android/content/pm/UsesPermissionInfo.java
deleted file mode 100644
index d08548f..0000000
--- a/core/java/android/content/pm/UsesPermissionInfo.java
+++ /dev/null
@@ -1,275 +0,0 @@
-/*
- * Copyright (C) 2018 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.content.pm;
-
-import android.annotation.IntDef;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.lang.annotation.RetentionPolicy;
-/**
- * Information you can retrive about a particular application requested permission. This
- * corresponds to information collected from the AndroidManifest.xml's &lt;uses-permission&gt;
- * tags.
- */
-public final class UsesPermissionInfo extends PackageItemInfo implements Parcelable {
-
-    /**
-     * Flag for {@link #getFlags()}: the requested permission is currently granted to the
-     * application.
-     */
-    public static final int FLAG_REQUESTED_PERMISSION_GRANTED = 1 << 1;
-
-    /** @hide */
-    @IntDef(flag = true, prefix = {"FLAG_"}, value = {FLAG_REQUESTED_PERMISSION_GRANTED})
-    @java.lang.annotation.Retention(RetentionPolicy.SOURCE)
-    public @interface Flags {}
-
-    /** An unset value for {@link #getDataSentOffDevice()},
-     * {@link #getDataSharedWithThirdParty()}, and {@link #getDataUsedForMonetization()}
-     */
-    public static final int USAGE_UNDEFINED = 0;
-
-    /**
-     * A yes value for {@link #getDataSentOffDevice()}, {@link #getDataSharedWithThirdParty()},
-     * and {@link #getDataUsedForMonetization()} corresponding to the <code>yes</code> value of
-     * {@link android.R.attr#dataSentOffDevice}, {@link android.R.attr#dataSharedWithThirdParty},
-     * and {@link android.R.attr#dataUsedForMonetization} attributes.
-     */
-    public static final int USAGE_YES = 1;
-
-    /**
-     * A user triggered only value for {@link #getDataSentOffDevice()},
-     * {@link #getDataSharedWithThirdParty()}, and {@link #getDataUsedForMonetization()}
-     * corresponding to the <code>userTriggered</code> value of
-     * {@link android.R.attr#dataSentOffDevice}, {@link android.R.attr#dataSharedWithThirdParty},
-     * and {@link android.R.attr#dataUsedForMonetization} attributes.
-     */
-    public static final int USAGE_USER_TRIGGERED = 2;
-
-    /**
-     * A no value for {@link #getDataSentOffDevice()}, {@link #getDataSharedWithThirdParty()},
-     * and {@link #getDataUsedForMonetization()} corresponding to the <code>no</code> value of
-     * {@link android.R.attr#dataSentOffDevice}, {@link android.R.attr#dataSharedWithThirdParty},
-     * and {@link android.R.attr#dataUsedForMonetization} attributes.
-     */
-    public static final int USAGE_NO = 3;
-
-    /** @hide */
-    @IntDef(prefix = {"USAGE_"}, value = {
-        USAGE_UNDEFINED,
-        USAGE_YES,
-        USAGE_USER_TRIGGERED,
-        USAGE_NO})
-    @java.lang.annotation.Retention(RetentionPolicy.SOURCE)
-    public @interface Usage {}
-
-    /**
-     * An unset value for {@link #getDataRetention}.
-     */
-    public static final int RETENTION_UNDEFINED = 0;
-
-    /**
-     * A data not retained value for {@link #getDataRetention()} corresponding to the
-     * <code>notRetained</code> value of {@link android.R.attr#dataRetentionTime}.
-     */
-    public static final int RETENTION_NOT_RETAINED = 1;
-
-    /**
-     * A user selected value for {@link #getDataRetention()} corresponding to the
-     * <code>userSelected</code> value of {@link android.R.attr#dataRetentionTime}.
-     */
-    public static final int RETENTION_USER_SELECTED = 2;
-
-    /**
-     * An unlimited value for {@link #getDataRetention()} corresponding to the
-     * <code>unlimited</code> value of {@link android.R.attr#dataRetentionTime}.
-     */
-    public static final int RETENTION_UNLIMITED = 3;
-
-    /**
-     * A specified value for {@link #getDataRetention()} corresponding to providing the number of
-     * weeks data is retained in {@link android.R.attr#dataRetentionTime}. The number of weeks
-     * is available in {@link #getDataRetentionWeeks()}.
-     */
-    public static final int RETENTION_SPECIFIED = 4;
-
-    /** @hide */
-    @IntDef(prefix = {"RETENTION_"}, value = {
-        RETENTION_UNDEFINED,
-        RETENTION_NOT_RETAINED,
-        RETENTION_USER_SELECTED,
-        RETENTION_UNLIMITED,
-        RETENTION_SPECIFIED})
-    @java.lang.annotation.Retention(RetentionPolicy.SOURCE)
-    public @interface Retention {}
-
-    private final String mPermission;
-    private final @Flags int mFlags;
-    private final @Usage int mDataSentOffDevice;
-    private final @Usage int mDataSharedWithThirdParty;
-    private final @Usage int mDataUsedForMonetization;
-    private final @Retention int mDataRetention;
-    private final int mDataRetentionWeeks;
-
-    /** @hide */
-    public UsesPermissionInfo(String permission) {
-        mPermission = permission;
-        mDataSentOffDevice = USAGE_UNDEFINED;
-        mDataSharedWithThirdParty = USAGE_UNDEFINED;
-        mDataUsedForMonetization = USAGE_UNDEFINED;
-        mDataRetention = RETENTION_UNDEFINED;
-        mDataRetentionWeeks = -1;
-        mFlags = 0;
-    }
-
-    /** @hide */
-    public UsesPermissionInfo(String permission,
-            @Usage int dataSentOffDevice, @Usage int dataSharedWithThirdParty,
-            @Usage int dataUsedForMonetization, @Retention int dataRetention,
-            int dataRetentionWeeks) {
-        mPermission = permission;
-        mDataSentOffDevice = dataSentOffDevice;
-        mDataSharedWithThirdParty = dataSharedWithThirdParty;
-        mDataUsedForMonetization = dataUsedForMonetization;
-        mDataRetention = dataRetention;
-        mDataRetentionWeeks = dataRetentionWeeks;
-        mFlags = 0;
-    }
-
-    /** @hide */
-    public UsesPermissionInfo(UsesPermissionInfo orig) {
-        this(orig, orig.mFlags);
-    }
-
-    /** @hide */
-    public UsesPermissionInfo(UsesPermissionInfo orig, int flags) {
-        super(orig);
-        mPermission = orig.mPermission;
-        mFlags = flags;
-        mDataSentOffDevice = orig.mDataSentOffDevice;
-        mDataSharedWithThirdParty = orig.mDataSharedWithThirdParty;
-        mDataUsedForMonetization = orig.mDataUsedForMonetization;
-        mDataRetention = orig.mDataRetention;
-        mDataRetentionWeeks = orig.mDataRetentionWeeks;
-    }
-
-    /**
-     * The name of the requested permission.
-     */
-    public String getPermission() {
-        return mPermission;
-    }
-
-    public @Flags int getFlags() {
-        return mFlags;
-    }
-
-    /**
-     * If the application sends the data guarded by this permission off the device.
-     *
-     * See {@link android.R.attr#dataSentOffDevice}
-     */
-    public @Usage int getDataSentOffDevice() {
-        return mDataSentOffDevice;
-    }
-
-    /**
-     * If the application or its services shares the data guarded by this permission with third
-     * parties.
-     *
-     * See {@link android.R.attr#dataSharedWithThirdParty}
-     */
-    public @Usage int getDataSharedWithThirdParty() {
-        return mDataSharedWithThirdParty;
-    }
-
-    /**
-     * If the application or its services use the data guarded by this permission for monetization
-     * purposes.
-     *
-     * See {@link android.R.attr#dataUsedForMonetization}
-     */
-    public @Usage int getDataUsedForMonetization() {
-        return mDataUsedForMonetization;
-    }
-
-    /**
-     * How long the application or its services store the data guarded by this permission.
-     * If set to {@link #RETENTION_SPECIFIED} {@link #getDataRetentionWeeks()} will contain the
-     * number of weeks the data is stored.
-     *
-     * See {@link android.R.attr#dataRetentionTime}
-     */
-    public @Retention int getDataRetention() {
-        return mDataRetention;
-    }
-
-    /**
-     * If {@link #getDataRetention()} is {@link #RETENTION_SPECIFIED} the number of weeks the
-     * application or its services store data guarded by this permission.
-     *
-     * @throws IllegalStateException if {@link #getDataRetention} is not
-     * {@link #RETENTION_SPECIFIED}.
-     */
-    public int getDataRetentionWeeks() {
-        if (mDataRetention != RETENTION_SPECIFIED) {
-            throw new IllegalStateException("Data retention weeks not specified");
-        }
-        return mDataRetentionWeeks;
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        super.writeToParcel(dest, flags);
-        dest.writeString(mPermission);
-        dest.writeInt(mFlags);
-        dest.writeInt(mDataSentOffDevice);
-        dest.writeInt(mDataSharedWithThirdParty);
-        dest.writeInt(mDataUsedForMonetization);
-        dest.writeInt(mDataRetention);
-        dest.writeInt(mDataRetentionWeeks);
-    }
-
-    private UsesPermissionInfo(Parcel source) {
-        super(source);
-        mPermission = source.readString();
-        mFlags = source.readInt();
-        mDataSentOffDevice = source.readInt();
-        mDataSharedWithThirdParty = source.readInt();
-        mDataUsedForMonetization = source.readInt();
-        mDataRetention = source.readInt();
-        mDataRetentionWeeks = source.readInt();
-    }
-
-    public static final Creator<UsesPermissionInfo> CREATOR =
-            new Creator<UsesPermissionInfo>() {
-                @Override
-                public UsesPermissionInfo createFromParcel(Parcel source) {
-                    return new UsesPermissionInfo(source);
-                }
-                @Override
-                public UsesPermissionInfo[] newArray(int size) {
-                    return new UsesPermissionInfo[size];
-                }
-            };
-}
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index 9e0a9ba..49b4cb0 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -47,6 +47,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
+import java.util.Map;
 
 /**
  * Provides access to an application's raw asset files; see {@link Resources}
@@ -1051,6 +1052,14 @@
         }
     }
 
+    int[] getAttributeResolutionStack(long themePtr, @AttrRes int defStyleAttr,
+            @StyleRes int defStyleRes, @StyleRes int xmlStyle) {
+        synchronized (this) {
+            return nativeAttributeResolutionStack(
+                    mObject, themePtr, xmlStyle, defStyleAttr, defStyleRes);
+        }
+    }
+
     @UnsupportedAppUsage
     boolean resolveAttrs(long themePtr, @AttrRes int defStyleAttr, @StyleRes int defStyleRes,
             @Nullable int[] inValues, @NonNull int[] inAttrs, @NonNull int[] outValues,
@@ -1337,6 +1346,17 @@
         }
     }
 
+    /**
+     * @hide
+     */
+    @GuardedBy("this")
+    public @Nullable Map<String, String> getOverlayableMap(String packageName) {
+        synchronized (this) {
+            ensureValidLocked();
+            return nativeGetOverlayableMap(mObject, packageName);
+        }
+    }
+
     @GuardedBy("this")
     private void incRefsLocked(long id) {
         if (DEBUG_REFS) {
@@ -1419,6 +1439,8 @@
     private static native @Nullable String nativeGetLastResourceResolution(long ptr);
 
     // Style attribute retrieval native methods.
+    private static native int[] nativeAttributeResolutionStack(long ptr, long themePtr,
+            @StyleRes int xmlStyleRes, @AttrRes int defStyleAttr, @StyleRes int defStyleRes);
     private static native void nativeApplyStyle(long ptr, long themePtr, @AttrRes int defStyleAttr,
             @StyleRes int defStyleRes, long xmlParserPtr, @NonNull int[] inAttrs,
             long outValuesAddress, long outIndicesAddress);
@@ -1452,6 +1474,8 @@
 
     private static native void nativeVerifySystemIdmaps();
     private static native String[] nativeCreateIdmapsForStaticOverlaysTargetingAndroid();
+    private static native @Nullable Map nativeGetOverlayableMap(long ptr,
+            @NonNull String packageName);
 
     // Global debug native methods.
     /**
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 59db49e..a2ae994 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -1725,6 +1725,68 @@
         public void rebase() {
             mThemeImpl.rebase();
         }
+
+        /**
+         * Returns the resource ID for the style specified using {@code style="..."} in the
+         * {@link AttributeSet}'s backing XML element or {@link Resources#ID_NULL} otherwise if not
+         * specified or otherwise not applicable.
+         * <p>
+         * Each {@link android.view.View} can have an explicit style specified in the layout file.
+         * This style is used first during the {@link android.view.View} attribute resolution, then
+         * if an attribute is not defined there the resource system looks at default style and theme
+         * as fallbacks.
+         *
+         * @param set The base set of attribute values.
+         *
+         * @return The resource ID for the style specified using {@code style="..."} in the
+         *      {@link AttributeSet}'s backing XML element or {@link Resources#ID_NULL} otherwise
+         *      if not specified or otherwise not applicable.
+         */
+        @StyleRes
+        public int getExplicitStyle(@Nullable AttributeSet set) {
+            if (set == null) {
+                return ID_NULL;
+            }
+            int styleAttr = set.getStyleAttribute();
+            if (styleAttr == ID_NULL) {
+                return ID_NULL;
+            }
+            String styleAttrType = getResources().getResourceTypeName(styleAttr);
+            if ("attr".equals(styleAttrType)) {
+                TypedValue explicitStyle = new TypedValue();
+                boolean resolved = resolveAttribute(styleAttr, explicitStyle, true);
+                if (resolved) {
+                    return explicitStyle.resourceId;
+                }
+            } else if ("style".equals(styleAttrType)) {
+                return styleAttr;
+            }
+            return ID_NULL;
+        }
+
+        /**
+         * Returns the ordered list of resource ID that are considered when resolving attribute
+         * values when making an equivalent call to
+         * {@link #obtainStyledAttributes(AttributeSet, int[], int, int)} . The list will include
+         * a set of explicit styles ({@code explicitStyleRes} and it will include the default styles
+         * ({@code defStyleAttr} and {@code defStyleRes}).
+         *
+         * @param defStyleAttr An attribute in the current theme that contains a
+         *                     reference to a style resource that supplies
+         *                     defaults values for the TypedArray.  Can be
+         *                     0 to not look for defaults.
+         * @param defStyleRes A resource identifier of a style resource that
+         *                    supplies default values for the TypedArray,
+         *                    used only if defStyleAttr is 0 or can not be found
+         *                    in the theme.  Can be 0 to not look for defaults.
+         * @param explicitStyleRes A resource identifier of an explicit style resource.
+         * @return ordered list of resource ID that are considered when resolving attribute values.
+         */
+        public int[] getAttributeResolutionStack(@AttrRes int defStyleAttr,
+                @StyleRes int defStyleRes, @StyleRes int explicitStyleRes) {
+            return mThemeImpl.getAttributeResolutionStack(
+                    defStyleAttr, defStyleRes, explicitStyleRes);
+        }
     }
 
     static class ThemeKey implements Cloneable {
diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java
index 9898079..da064c9 100644
--- a/core/java/android/content/res/ResourcesImpl.java
+++ b/core/java/android/content/res/ResourcesImpl.java
@@ -1488,6 +1488,32 @@
                 }
             }
         }
+
+        /**
+         * Returns the ordered list of resource ID that are considered when resolving attribute
+         * values when making an equivalent call to
+         * {@link #obtainStyledAttributes(Resources.Theme, AttributeSet, int[], int, int)}. The list
+         * will include a set of explicit styles ({@code explicitStyleRes} and it will include the
+         * default styles ({@code defStyleAttr} and {@code defStyleRes}).
+         *
+         * @param defStyleAttr An attribute in the current theme that contains a
+         *                     reference to a style resource that supplies
+         *                     defaults values for the TypedArray.  Can be
+         *                     0 to not look for defaults.
+         * @param defStyleRes A resource identifier of a style resource that
+         *                    supplies default values for the TypedArray,
+         *                    used only if defStyleAttr is 0 or can not be found
+         *                    in the theme.  Can be 0 to not look for defaults.
+         * @param explicitStyleRes A resource identifier of an explicit style resource.
+         * @return ordered list of resource ID that are considered when resolving attribute values.
+         */
+        public int[] getAttributeResolutionStack(@AttrRes int defStyleAttr,
+                @StyleRes int defStyleRes, @StyleRes int explicitStyleRes) {
+            synchronized (mKey) {
+                return mAssets.getAttributeResolutionStack(
+                        mTheme, defStyleAttr, defStyleRes, explicitStyleRes);
+            }
+        }
     }
 
     private static class LookupStack {
diff --git a/core/java/android/content/rollback/PackageRollbackInfo.java b/core/java/android/content/rollback/PackageRollbackInfo.java
index 0ec4018..1d0ab5a 100644
--- a/core/java/android/content/rollback/PackageRollbackInfo.java
+++ b/core/java/android/content/rollback/PackageRollbackInfo.java
@@ -22,6 +22,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.IntArray;
+import android.util.SparseLongArray;
 
 import java.util.ArrayList;
 
@@ -73,6 +74,18 @@
      */
     private final boolean mIsApex;
 
+    /*
+     * The list of users the package is installed for.
+     */
+    // NOTE: Not a part of the Parcelable representation of this object.
+    private final IntArray mInstalledUsers;
+
+    /**
+     * A mapping between user and an inode of theirs CE data snapshot.
+     */
+    // NOTE: Not a part of the Parcelable representation of this object.
+    private final SparseLongArray mCeSnapshotInodes;
+
     /**
      * Returns the name of the package to roll back from.
      */
@@ -126,15 +139,33 @@
     }
 
     /** @hide */
+    public IntArray getInstalledUsers() {
+        return mInstalledUsers;
+    }
+
+    /** @hide */
+    public SparseLongArray getCeSnapshotInodes() {
+        return mCeSnapshotInodes;
+    }
+
+    /** @hide */
+    public void putCeSnapshotInode(int userId, long ceSnapshotInode) {
+        mCeSnapshotInodes.put(userId, ceSnapshotInode);
+    }
+
+    /** @hide */
     public PackageRollbackInfo(VersionedPackage packageRolledBackFrom,
             VersionedPackage packageRolledBackTo,
             @NonNull IntArray pendingBackups, @NonNull ArrayList<RestoreInfo> pendingRestores,
-            boolean isApex) {
+            boolean isApex, @NonNull IntArray installedUsers,
+            @NonNull SparseLongArray ceSnapshotInodes) {
         this.mVersionRolledBackFrom = packageRolledBackFrom;
         this.mVersionRolledBackTo = packageRolledBackTo;
         this.mPendingBackups = pendingBackups;
         this.mPendingRestores = pendingRestores;
         this.mIsApex = isApex;
+        this.mInstalledUsers = installedUsers;
+        this.mCeSnapshotInodes = ceSnapshotInodes;
     }
 
     private PackageRollbackInfo(Parcel in) {
@@ -143,6 +174,8 @@
         this.mIsApex = in.readBoolean();
         this.mPendingRestores = null;
         this.mPendingBackups = null;
+        this.mInstalledUsers = null;
+        this.mCeSnapshotInodes = null;
     }
 
     @Override
diff --git a/core/java/android/debug/AdbManagerInternal.java b/core/java/android/debug/AdbManagerInternal.java
index 4469f0f..51eb7fc 100644
--- a/core/java/android/debug/AdbManagerInternal.java
+++ b/core/java/android/debug/AdbManagerInternal.java
@@ -16,6 +16,8 @@
 
 package android.debug;
 
+import java.io.File;
+
 /**
  * This class allows the control of ADB-related functions that should only be called from the system
  * server.
@@ -41,4 +43,14 @@
      * Returns {@code true} if ADB debugging is enabled.
      */
     public abstract boolean isAdbEnabled();
+
+    /**
+     * Returns the file that contains all of the ADB keys used by the device.
+     */
+    public abstract File getAdbKeysFile();
+
+    /**
+     * Returns the file that contains all of the ADB keys and their last used time.
+     */
+    public abstract File getAdbTempKeysFile();
 }
diff --git a/core/java/android/hardware/biometrics/BiometricConstants.java b/core/java/android/hardware/biometrics/BiometricConstants.java
index c814b7c..1cb7eb0 100644
--- a/core/java/android/hardware/biometrics/BiometricConstants.java
+++ b/core/java/android/hardware/biometrics/BiometricConstants.java
@@ -17,6 +17,7 @@
 package android.hardware.biometrics;
 
 import android.annotation.UnsupportedAppUsage;
+import android.app.KeyguardManager;
 
 
 /**
@@ -126,6 +127,13 @@
     int BIOMETRIC_ERROR_NEGATIVE_BUTTON = 13;
 
     /**
+     * The device does not have pin, pattern, or password set up. See
+     * {@link BiometricPrompt.Builder#setAllowDeviceCredential(boolean)} and
+     * {@link KeyguardManager#isDeviceSecure()}
+     */
+    int BIOMETRIC_ERROR_NO_DEVICE_CREDENTIAL = 14;
+
+    /**
      * @hide
      */
     @UnsupportedAppUsage
diff --git a/core/java/android/hardware/biometrics/BiometricFaceConstants.java b/core/java/android/hardware/biometrics/BiometricFaceConstants.java
index b708ef1..459ec62 100644
--- a/core/java/android/hardware/biometrics/BiometricFaceConstants.java
+++ b/core/java/android/hardware/biometrics/BiometricFaceConstants.java
@@ -16,6 +16,7 @@
 
 package android.hardware.biometrics;
 
+import android.app.KeyguardManager;
 import android.hardware.face.FaceManager;
 
 /**
@@ -134,6 +135,13 @@
     public static final int FACE_ERROR_NEGATIVE_BUTTON = 13;
 
     /**
+     * The device does not have pin, pattern, or password set up. See
+     * {@link BiometricPrompt.Builder#setAllowDeviceCredential(boolean)} and
+     * {@link KeyguardManager#isDeviceSecure()}
+     */
+    public static final int BIOMETRIC_ERROR_NO_DEVICE_CREDENTIAL = 14;
+
+    /**
      * @hide
      */
     public static final int FACE_ERROR_VENDOR_BASE = 1000;
diff --git a/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java b/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java
index 041b2e6..6cbab47 100644
--- a/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java
+++ b/core/java/android/hardware/biometrics/BiometricFingerprintConstants.java
@@ -17,6 +17,7 @@
 package android.hardware.biometrics;
 
 import android.annotation.UnsupportedAppUsage;
+import android.app.KeyguardManager;
 import android.hardware.fingerprint.FingerprintManager;
 
 /**
@@ -119,6 +120,14 @@
     public static final int FINGERPRINT_ERROR_NEGATIVE_BUTTON = 13;
 
     /**
+     * The device does not have pin, pattern, or password set up. See
+     * {@link BiometricPrompt.Builder#setAllowDeviceCredential(boolean)} and
+     * {@link KeyguardManager#isDeviceSecure()}
+     * @hide
+     */
+    public static final int BIOMETRIC_ERROR_NO_DEVICE_CREDENTIAL = 14;
+
+    /**
      * @hide
      */
     @UnsupportedAppUsage
diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java
index d569a78..baf972b 100644
--- a/core/java/android/hardware/biometrics/BiometricPrompt.java
+++ b/core/java/android/hardware/biometrics/BiometricPrompt.java
@@ -23,6 +23,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
+import android.app.KeyguardManager;
 import android.content.Context;
 import android.content.DialogInterface;
 import android.os.Binder;
@@ -80,7 +81,7 @@
     /**
      * @hide
      */
-    public static final String KEY_ENABLE_FALLBACK = "enable_fallback";
+    public static final String KEY_ALLOW_DEVICE_CREDENTIAL = "allow_device_credential";
 
     /**
      * Error/help message will show for this amount of time.
@@ -203,7 +204,8 @@
          * "Cancel" button, but may be also used to show an alternative method for authentication,
          * such as screen that asks for a backup password.
          *
-         * Note that this should not be set if {@link #setEnableFallback(boolean)} is set to true.
+         * Note that this should not be set if {@link #setAllowDeviceCredential(boolean)
+         * is set to true.
          *
          * @param text
          * @return
@@ -250,7 +252,10 @@
 
         /**
          * The user will first be prompted to authenticate with biometrics, but also given the
-         * option to authenticate with their device PIN, pattern, or password.
+         * option to authenticate with their device PIN, pattern, or password. Developers should
+         * first check {@link KeyguardManager#isDeviceSecure()} before enabling this. If the device
+         * is not secure, {@link BiometricPrompt#BIOMETRIC_ERROR_NO_DEVICE_CREDENTIAL} will be
+         * returned in {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)}}
          *
          * Note that {@link #setNegativeButton(CharSequence, Executor,
          * DialogInterface.OnClickListener)} should not be set if this is set to true.
@@ -259,8 +264,8 @@
          *               credentials (PIN, pattern, or password).
          * @return
          */
-        public Builder setEnableFallback(boolean enable) {
-            mBundle.putBoolean(KEY_ENABLE_FALLBACK, enable);
+        public Builder setAllowDeviceCredential(boolean enable) {
+            mBundle.putBoolean(KEY_ALLOW_DEVICE_CREDENTIAL, enable);
             return this;
         }
 
@@ -273,7 +278,7 @@
             final CharSequence title = mBundle.getCharSequence(KEY_TITLE);
             final CharSequence negative = mBundle.getCharSequence(KEY_NEGATIVE_TEXT);
             final boolean useDefaultTitle = mBundle.getBoolean(KEY_USE_DEFAULT_TITLE);
-            final boolean enableFallback = mBundle.getBoolean(KEY_ENABLE_FALLBACK);
+            final boolean enableFallback = mBundle.getBoolean(KEY_ALLOW_DEVICE_CREDENTIAL);
 
             if (TextUtils.isEmpty(title) && !useDefaultTitle) {
                 throw new IllegalArgumentException("Title must be set and non-empty");
@@ -281,7 +286,7 @@
                 throw new IllegalArgumentException("Negative text must be set and non-empty");
             } else if (!TextUtils.isEmpty(negative) && enableFallback) {
                 throw new IllegalArgumentException("Can't have both negative button behavior"
-                        + " and fallback enabled");
+                        + " and device credential enabled");
             }
             return new BiometricPrompt(mContext, mBundle, mPositiveButtonInfo, mNegativeButtonInfo);
         }
@@ -541,8 +546,8 @@
         if (callback == null) {
             throw new IllegalArgumentException("Must supply a callback");
         }
-        if (mBundle.getBoolean(KEY_ENABLE_FALLBACK)) {
-            throw new IllegalArgumentException("Fallback not supported with crypto");
+        if (mBundle.getBoolean(KEY_ALLOW_DEVICE_CREDENTIAL)) {
+            throw new IllegalArgumentException("Device credential not supported with crypto");
         }
         authenticateInternal(crypto, cancel, executor, callback, mContext.getUserId());
     }
diff --git a/core/java/android/hardware/biometrics/IBiometricService.aidl b/core/java/android/hardware/biometrics/IBiometricService.aidl
index e4336d1..a20e2bf 100644
--- a/core/java/android/hardware/biometrics/IBiometricService.aidl
+++ b/core/java/android/hardware/biometrics/IBiometricService.aidl
@@ -54,7 +54,7 @@
 
     // TODO(b/123378871): Remove when moved.
     // CDCA needs to send results to BiometricService if it was invoked using BiometricPrompt's
-    // setEnableFallback method, since there's no way for us to intercept onActivityResult.
+    // setAllowDeviceCredential method, since there's no way for us to intercept onActivityResult.
     // CDCA is launched from BiometricService (startActivityAsUser) instead of *ForResult.
     void onConfirmDeviceCredentialSuccess();
     // TODO(b/123378871): Remove when moved.
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 1881a0cd..0e4ff78 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -1159,9 +1159,10 @@
      * <li>Each output JPEG size in android.scaler.availableStreamConfigurations will have at least
      * one corresponding size that has the same aspect ratio in availableThumbnailSizes,
      * and vice versa.</li>
-     * <li>All non-<code>(0, 0)</code> sizes will have non-zero widths and heights.
-     * This key is available on all devices.</li>
+     * <li>All non-<code>(0, 0)</code> sizes will have non-zero widths and heights.</li>
      * </ul>
+     * <p>This list is also used as supported thumbnail sizes for HEIC image format capture.</p>
+     * <p>This key is available on all devices.</p>
      *
      * @see CaptureRequest#JPEG_THUMBNAIL_SIZE
      */
@@ -3838,6 +3839,74 @@
     public static final Key<int[]> DISTORTION_CORRECTION_AVAILABLE_MODES =
             new Key<int[]>("android.distortionCorrection.availableModes", int[].class);
 
+    /**
+     * <p>The available HEIC (ISO/IEC 23008-12) stream
+     * configurations that this camera device supports
+     * (i.e. format, width, height, output/input stream).</p>
+     * <p>The configurations are listed as <code>(format, width, height, input?)</code> tuples.</p>
+     * <p>If the camera device supports HEIC image format, it will support identical set of stream
+     * combinations involving HEIC image format, compared to the combinations involving JPEG
+     * image format as required by the device's hardware level and capabilities.</p>
+     * <p>All the static, control, and dynamic metadata tags related to JPEG apply to HEIC formats.
+     * Configuring JPEG and HEIC streams at the same time is not supported.</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * <p><b>Limited capability</b> -
+     * Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the
+     * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p>
+     *
+     * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+     * @hide
+     */
+    public static final Key<android.hardware.camera2.params.StreamConfiguration[]> HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS =
+            new Key<android.hardware.camera2.params.StreamConfiguration[]>("android.heic.availableHeicStreamConfigurations", android.hardware.camera2.params.StreamConfiguration[].class);
+
+    /**
+     * <p>This lists the minimum frame duration for each
+     * format/size combination for HEIC output formats.</p>
+     * <p>This should correspond to the frame duration when only that
+     * stream is active, with all processing (typically in android.*.mode)
+     * set to either OFF or FAST.</p>
+     * <p>When multiple streams are used in a request, the minimum frame
+     * duration will be max(individual stream min durations).</p>
+     * <p>See {@link CaptureRequest#SENSOR_FRAME_DURATION android.sensor.frameDuration} and
+     * android.scaler.availableStallDurations for more details about
+     * calculating the max frame rate.</p>
+     * <p><b>Units</b>: (format, width, height, ns) x n</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * <p><b>Limited capability</b> -
+     * Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the
+     * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p>
+     *
+     * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+     * @see CaptureRequest#SENSOR_FRAME_DURATION
+     * @hide
+     */
+    public static final Key<android.hardware.camera2.params.StreamConfigurationDuration[]> HEIC_AVAILABLE_HEIC_MIN_FRAME_DURATIONS =
+            new Key<android.hardware.camera2.params.StreamConfigurationDuration[]>("android.heic.availableHeicMinFrameDurations", android.hardware.camera2.params.StreamConfigurationDuration[].class);
+
+    /**
+     * <p>This lists the maximum stall duration for each
+     * output format/size combination for HEIC streams.</p>
+     * <p>A stall duration is how much extra time would get added
+     * to the normal minimum frame duration for a repeating request
+     * that has streams with non-zero stall.</p>
+     * <p>This functions similarly to
+     * android.scaler.availableStallDurations for HEIC
+     * streams.</p>
+     * <p>All HEIC output stream formats may have a nonzero stall
+     * duration.</p>
+     * <p><b>Units</b>: (format, width, height, ns) x n</p>
+     * <p><b>Optional</b> - This value may be {@code null} on some devices.</p>
+     * <p><b>Limited capability</b> -
+     * Present on all camera devices that report being at least {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL_LIMITED HARDWARE_LEVEL_LIMITED} devices in the
+     * {@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL android.info.supportedHardwareLevel} key</p>
+     *
+     * @see CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL
+     * @hide
+     */
+    public static final Key<android.hardware.camera2.params.StreamConfigurationDuration[]> HEIC_AVAILABLE_HEIC_STALL_DURATIONS =
+            new Key<android.hardware.camera2.params.StreamConfigurationDuration[]>("android.heic.availableHeicStallDurations", android.hardware.camera2.params.StreamConfigurationDuration[].class);
+
     /*~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~
      * End generated code
      *~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~@~O@*/
diff --git a/core/java/android/hardware/camera2/CameraDevice.java b/core/java/android/hardware/camera2/CameraDevice.java
index 9c213f2..20fc53f 100644
--- a/core/java/android/hardware/camera2/CameraDevice.java
+++ b/core/java/android/hardware/camera2/CameraDevice.java
@@ -356,12 +356,6 @@
      * </table><br>
      * </p>
      *
-     * <p>MONOCHROME-capability ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES}
-     * includes {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME MONOCHROME}) devices
-     * supporting {@link android.graphics.ImageFormat#Y8 Y8} support substituting {@code YUV}
-     * streams with {@code Y8} in all guaranteed stream combinations for the device's hardware level
-     * and capabilities.</p>
-     *
      * <p>FULL-level ({@link CameraCharacteristics#INFO_SUPPORTED_HARDWARE_LEVEL}
      * {@code == }{@link CameraMetadata#INFO_SUPPORTED_HARDWARE_LEVEL_FULL FULL}) devices
      * support at least the following stream combinations in addition to those for
@@ -435,6 +429,18 @@
      * </table><br>
      * </p>
      *
+     * <p>MONOCHROME-capability ({@link CameraCharacteristics#REQUEST_AVAILABLE_CAPABILITIES}
+     * includes {@link CameraMetadata#REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME MONOCHROME}) devices
+     * supporting {@link android.graphics.ImageFormat#Y8 Y8} support substituting {@code YUV}
+     * streams with {@code Y8} in all guaranteed stream combinations for the device's hardware level
+     * and capabilities.</p>
+     *
+     * <p>Devices capable of outputting HEIC formats ({@link StreamConfigurationMap#getOutputFormats}
+     * contains {@link android.graphics.ImageFormat#HEIC}) will support substituting {@code JPEG}
+     * streams with {@code HEIC} in all guaranteed stream combinations for the device's hardware
+     * level and capabilities. Calling createCaptureSession with both JPEG and HEIC outputs is not
+     * supported.</p>
+     *
      * <p>Clients can access the above mandatory stream combination tables via
      * {@link android.hardware.camera2.params.MandatoryStreamCombination}.</p>
      *
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 3d3a916..5250701 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -2126,6 +2126,7 @@
      * <p>Setting a location object in a request will include the GPS coordinates of the location
      * into any JPEG images captured based on the request. These coordinates can then be
      * viewed by anyone who receives the JPEG image.</p>
+     * <p>This tag is also used for HEIC image capture.</p>
      * <p>This key is available on all devices.</p>
      */
     @PublicKey
@@ -2136,6 +2137,7 @@
     /**
      * <p>GPS coordinates to include in output JPEG
      * EXIF.</p>
+     * <p>This tag is also used for HEIC image capture.</p>
      * <p><b>Range of valid values:</b><br>
      * (-180 - 180], [-90,90], [-inf, inf]</p>
      * <p>This key is available on all devices.</p>
@@ -2147,6 +2149,7 @@
     /**
      * <p>32 characters describing GPS algorithm to
      * include in EXIF.</p>
+     * <p>This tag is also used for HEIC image capture.</p>
      * <p>This key is available on all devices.</p>
      * @hide
      */
@@ -2156,6 +2159,7 @@
     /**
      * <p>Time GPS fix was made to include in
      * EXIF.</p>
+     * <p>This tag is also used for HEIC image capture.</p>
      * <p><b>Units</b>: UTC in seconds since January 1, 1970</p>
      * <p>This key is available on all devices.</p>
      * @hide
@@ -2195,6 +2199,10 @@
      * </code></pre>
      * <p>For EXTERNAL cameras the sensor orientation will always be set to 0 and the facing will
      * also be set to EXTERNAL. The above code is not relevant in such case.</p>
+     * <p>This tag is also used to describe the orientation of the HEIC image capture, in which
+     * case the rotation is reflected by
+     * {@link android.media.ExifInterface#TAG_ORIENTATION EXIF orientation flag}, and not by
+     * rotating the image data itself.</p>
      * <p><b>Units</b>: Degrees in multiples of 90</p>
      * <p><b>Range of valid values:</b><br>
      * 0, 90, 180, 270</p>
@@ -2209,7 +2217,8 @@
     /**
      * <p>Compression quality of the final JPEG
      * image.</p>
-     * <p>85-95 is typical usage range.</p>
+     * <p>85-95 is typical usage range. This tag is also used to describe the quality
+     * of the HEIC image capture.</p>
      * <p><b>Range of valid values:</b><br>
      * 1-100; larger is higher quality</p>
      * <p>This key is available on all devices.</p>
@@ -2221,6 +2230,7 @@
     /**
      * <p>Compression quality of JPEG
      * thumbnail.</p>
+     * <p>This tag is also used to describe the quality of the HEIC image capture.</p>
      * <p><b>Range of valid values:</b><br>
      * 1-100; larger is higher quality</p>
      * <p>This key is available on all devices.</p>
@@ -2253,6 +2263,10 @@
      *   orientation is requested. LEGACY device will always report unrotated thumbnail
      *   size.</li>
      * </ul>
+     * <p>The tag is also used as thumbnail size for HEIC image format capture, in which case the
+     * the thumbnail rotation is reflected by
+     * {@link android.media.ExifInterface#TAG_ORIENTATION EXIF orientation flag}, and not by
+     * rotating the thumbnail data itself.</p>
      * <p><b>Range of valid values:</b><br>
      * {@link CameraCharacteristics#JPEG_AVAILABLE_THUMBNAIL_SIZES android.jpeg.availableThumbnailSizes}</p>
      * <p>This key is available on all devices.</p>
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 8982b40..13ad092 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -2450,6 +2450,7 @@
      * <p>Setting a location object in a request will include the GPS coordinates of the location
      * into any JPEG images captured based on the request. These coordinates can then be
      * viewed by anyone who receives the JPEG image.</p>
+     * <p>This tag is also used for HEIC image capture.</p>
      * <p>This key is available on all devices.</p>
      */
     @PublicKey
@@ -2460,6 +2461,7 @@
     /**
      * <p>GPS coordinates to include in output JPEG
      * EXIF.</p>
+     * <p>This tag is also used for HEIC image capture.</p>
      * <p><b>Range of valid values:</b><br>
      * (-180 - 180], [-90,90], [-inf, inf]</p>
      * <p>This key is available on all devices.</p>
@@ -2471,6 +2473,7 @@
     /**
      * <p>32 characters describing GPS algorithm to
      * include in EXIF.</p>
+     * <p>This tag is also used for HEIC image capture.</p>
      * <p>This key is available on all devices.</p>
      * @hide
      */
@@ -2480,6 +2483,7 @@
     /**
      * <p>Time GPS fix was made to include in
      * EXIF.</p>
+     * <p>This tag is also used for HEIC image capture.</p>
      * <p><b>Units</b>: UTC in seconds since January 1, 1970</p>
      * <p>This key is available on all devices.</p>
      * @hide
@@ -2519,6 +2523,10 @@
      * </code></pre>
      * <p>For EXTERNAL cameras the sensor orientation will always be set to 0 and the facing will
      * also be set to EXTERNAL. The above code is not relevant in such case.</p>
+     * <p>This tag is also used to describe the orientation of the HEIC image capture, in which
+     * case the rotation is reflected by
+     * {@link android.media.ExifInterface#TAG_ORIENTATION EXIF orientation flag}, and not by
+     * rotating the image data itself.</p>
      * <p><b>Units</b>: Degrees in multiples of 90</p>
      * <p><b>Range of valid values:</b><br>
      * 0, 90, 180, 270</p>
@@ -2533,7 +2541,8 @@
     /**
      * <p>Compression quality of the final JPEG
      * image.</p>
-     * <p>85-95 is typical usage range.</p>
+     * <p>85-95 is typical usage range. This tag is also used to describe the quality
+     * of the HEIC image capture.</p>
      * <p><b>Range of valid values:</b><br>
      * 1-100; larger is higher quality</p>
      * <p>This key is available on all devices.</p>
@@ -2545,6 +2554,7 @@
     /**
      * <p>Compression quality of JPEG
      * thumbnail.</p>
+     * <p>This tag is also used to describe the quality of the HEIC image capture.</p>
      * <p><b>Range of valid values:</b><br>
      * 1-100; larger is higher quality</p>
      * <p>This key is available on all devices.</p>
@@ -2577,6 +2587,10 @@
      *   orientation is requested. LEGACY device will always report unrotated thumbnail
      *   size.</li>
      * </ul>
+     * <p>The tag is also used as thumbnail size for HEIC image format capture, in which case the
+     * the thumbnail rotation is reflected by
+     * {@link android.media.ExifInterface#TAG_ORIENTATION EXIF orientation flag}, and not by
+     * rotating the thumbnail data itself.</p>
      * <p><b>Range of valid values:</b><br>
      * {@link CameraCharacteristics#JPEG_AVAILABLE_THUMBNAIL_SIZES android.jpeg.availableThumbnailSizes}</p>
      * <p>This key is available on all devices.</p>
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index 7877a4d..65026b6 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -1133,6 +1133,9 @@
                             /*dynamicDepthConfigurations*/ null,
                             /*dynamicDepthMinFrameDurations*/ null,
                             /*dynamicDepthStallDurations*/ null,
+                            /*heicconfiguration*/ null,
+                            /*heicminduration*/ null,
+                            /*heicstallduration*/ null,
                             /*highspeedvideoconfigurations*/ null,
                             /*inputoutputformatsmap*/ null, listHighResolution, supportsPrivate[i]);
                     break;
@@ -1144,6 +1147,9 @@
                             /*dynamicDepthConfigurations*/ null,
                             /*dynamicDepthMinFrameDurations*/ null,
                             /*dynamicDepthStallDurations*/ null,
+                            /*heicconfiguration*/ null,
+                            /*heicminduration*/ null,
+                            /*heicstallduration*/ null,
                             highSpeedVideoConfigurations,
                             /*inputoutputformatsmap*/ null, listHighResolution, supportsPrivate[i]);
                     break;
@@ -1155,6 +1161,9 @@
                             /*dynamicDepthConfigurations*/ null,
                             /*dynamicDepthMinFrameDurations*/ null,
                             /*dynamicDepthStallDurations*/ null,
+                            /*heicconfiguration*/ null,
+                            /*heicminduration*/ null,
+                            /*heicstallduration*/ null,
                             /*highSpeedVideoConfigurations*/ null,
                             inputOutputFormatsMap, listHighResolution, supportsPrivate[i]);
                     break;
@@ -1166,6 +1175,9 @@
                             /*dynamicDepthConfigurations*/ null,
                             /*dynamicDepthMinFrameDurations*/ null,
                             /*dynamicDepthStallDurations*/ null,
+                            /*heicconfiguration*/ null,
+                            /*heicminduration*/ null,
+                            /*heicstallduration*/ null,
                             /*highSpeedVideoConfigurations*/ null,
                             /*inputOutputFormatsMap*/ null, listHighResolution, supportsPrivate[i]);
             }
@@ -1230,6 +1242,12 @@
                 CameraCharacteristics.DEPTH_AVAILABLE_DYNAMIC_DEPTH_MIN_FRAME_DURATIONS);
         StreamConfigurationDuration[] dynamicDepthStallDurations = getBase(
                 CameraCharacteristics.DEPTH_AVAILABLE_DYNAMIC_DEPTH_STALL_DURATIONS);
+        StreamConfiguration[] heicConfigurations = getBase(
+                CameraCharacteristics.HEIC_AVAILABLE_HEIC_STREAM_CONFIGURATIONS);
+        StreamConfigurationDuration[] heicMinFrameDurations = getBase(
+                CameraCharacteristics.HEIC_AVAILABLE_HEIC_MIN_FRAME_DURATIONS);
+        StreamConfigurationDuration[] heicStallDurations = getBase(
+                CameraCharacteristics.HEIC_AVAILABLE_HEIC_STALL_DURATIONS);
         HighSpeedVideoConfiguration[] highSpeedVideoConfigurations = getBase(
                 CameraCharacteristics.CONTROL_AVAILABLE_HIGH_SPEED_VIDEO_CONFIGURATIONS);
         ReprocessFormatsMap inputOutputFormatsMap = getBase(
@@ -1239,7 +1257,9 @@
                 configurations, minFrameDurations, stallDurations,
                 depthConfigurations, depthMinFrameDurations, depthStallDurations,
                 dynamicDepthConfigurations, dynamicDepthMinFrameDurations,
-                dynamicDepthStallDurations, highSpeedVideoConfigurations, inputOutputFormatsMap,
+                dynamicDepthStallDurations, heicConfigurations,
+                heicMinFrameDurations, heicStallDurations,
+                highSpeedVideoConfigurations, inputOutputFormatsMap,
                 listHighResolution);
     }
 
diff --git a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
index a22e008..996f997 100644
--- a/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
+++ b/core/java/android/hardware/camera2/params/StreamConfigurationMap.java
@@ -79,6 +79,22 @@
      * @param configurations a non-{@code null} array of {@link StreamConfiguration}
      * @param minFrameDurations a non-{@code null} array of {@link StreamConfigurationDuration}
      * @param stallDurations a non-{@code null} array of {@link StreamConfigurationDuration}
+     * @param depthConfigurations a non-{@code null} array of depth {@link StreamConfiguration}
+     * @param depthMinFrameDurations a non-{@code null} array of depth
+     *        {@link StreamConfigurationDuration}
+     * @param depthStallDurations a non-{@code null} array of depth
+     *        {@link StreamConfigurationDuration}
+     * @param dynamicDepthConfigurations a non-{@code null} array of dynamic depth
+     *        {@link StreamConfiguration}
+     * @param dynamicDepthMinFrameDurations a non-{@code null} array of dynamic depth
+     *        {@link StreamConfigurationDuration}
+     * @param dynamicDepthStallDurations a non-{@code null} array of dynamic depth
+     *        {@link StreamConfigurationDuration}
+     * @param heicConfigurations a non-{@code null} array of heic {@link StreamConfiguration}
+     * @param heicMinFrameDurations a non-{@code null} array of heic
+     *        {@link StreamConfigurationDuration}
+     * @param heicStallDurations a non-{@code null} array of heic
+     *        {@link StreamConfigurationDuration}
      * @param highSpeedVideoConfigurations an array of {@link HighSpeedVideoConfiguration}, null if
      *        camera device does not support high speed video recording
      * @param listHighResolution a flag indicating whether the device supports BURST_CAPTURE
@@ -98,14 +114,19 @@
             StreamConfiguration[] dynamicDepthConfigurations,
             StreamConfigurationDuration[] dynamicDepthMinFrameDurations,
             StreamConfigurationDuration[] dynamicDepthStallDurations,
+            StreamConfiguration[] heicConfigurations,
+            StreamConfigurationDuration[] heicMinFrameDurations,
+            StreamConfigurationDuration[] heicStallDurations,
             HighSpeedVideoConfiguration[] highSpeedVideoConfigurations,
             ReprocessFormatsMap inputOutputFormatsMap,
             boolean listHighResolution) {
         this(configurations, minFrameDurations, stallDurations,
                     depthConfigurations, depthMinFrameDurations, depthStallDurations,
                     dynamicDepthConfigurations, dynamicDepthMinFrameDurations,
-                    dynamicDepthStallDurations, highSpeedVideoConfigurations, inputOutputFormatsMap,
-                    listHighResolution, /*enforceImplementationDefined*/ true);
+                    dynamicDepthStallDurations,
+                    heicConfigurations, heicMinFrameDurations, heicStallDurations,
+                    highSpeedVideoConfigurations, inputOutputFormatsMap, listHighResolution,
+                    /*enforceImplementationDefined*/ true);
     }
 
     /**
@@ -117,6 +138,22 @@
      * @param configurations a non-{@code null} array of {@link StreamConfiguration}
      * @param minFrameDurations a non-{@code null} array of {@link StreamConfigurationDuration}
      * @param stallDurations a non-{@code null} array of {@link StreamConfigurationDuration}
+     * @param depthConfigurations a non-{@code null} array of depth {@link StreamConfiguration}
+     * @param depthMinFrameDurations a non-{@code null} array of depth
+     *        {@link StreamConfigurationDuration}
+     * @param depthStallDurations a non-{@code null} array of depth
+     *        {@link StreamConfigurationDuration}
+     * @param dynamicDepthConfigurations a non-{@code null} array of dynamic depth
+     *        {@link StreamConfiguration}
+     * @param dynamicDepthMinFrameDurations a non-{@code null} array of dynamic depth
+     *        {@link StreamConfigurationDuration}
+     * @param dynamicDepthStallDurations a non-{@code null} array of dynamic depth
+     *        {@link StreamConfigurationDuration}
+     * @param heicConfigurations a non-{@code null} array of heic {@link StreamConfiguration}
+     * @param heicMinFrameDurations a non-{@code null} array of heic
+     *        {@link StreamConfigurationDuration}
+     * @param heicStallDurations a non-{@code null} array of heic
+     *        {@link StreamConfigurationDuration}
      * @param highSpeedVideoConfigurations an array of {@link HighSpeedVideoConfiguration}, null if
      *        camera device does not support high speed video recording
      * @param listHighResolution a flag indicating whether the device supports BURST_CAPTURE
@@ -138,14 +175,23 @@
             StreamConfiguration[] dynamicDepthConfigurations,
             StreamConfigurationDuration[] dynamicDepthMinFrameDurations,
             StreamConfigurationDuration[] dynamicDepthStallDurations,
+            StreamConfiguration[] heicConfigurations,
+            StreamConfigurationDuration[] heicMinFrameDurations,
+            StreamConfigurationDuration[] heicStallDurations,
             HighSpeedVideoConfiguration[] highSpeedVideoConfigurations,
             ReprocessFormatsMap inputOutputFormatsMap,
             boolean listHighResolution,
             boolean enforceImplementationDefined) {
 
+        if (configurations == null &&
+                depthConfigurations == null &&
+                heicConfigurations == null) {
+            throw new NullPointerException("At least one of color/depth/heic configurations " +
+                    "must not be null");
+        }
+
         if (configurations == null) {
             // If no color configurations exist, ensure depth ones do
-            checkArrayElementsNotNull(depthConfigurations, "depthConfigurations");
             mConfigurations = new StreamConfiguration[0];
             mMinFrameDurations = new StreamConfigurationDuration[0];
             mStallDurations = new StreamConfigurationDuration[0];
@@ -183,6 +229,19 @@
                     "dynamicDepthStallDurations");
         }
 
+        if (heicConfigurations == null) {
+            mHeicConfigurations = new StreamConfiguration[0];
+            mHeicMinFrameDurations = new StreamConfigurationDuration[0];
+            mHeicStallDurations = new StreamConfigurationDuration[0];
+        } else {
+            mHeicConfigurations = checkArrayElementsNotNull(heicConfigurations,
+                    "heicConfigurations");
+            mHeicMinFrameDurations = checkArrayElementsNotNull(heicMinFrameDurations,
+                    "heicMinFrameDurations");
+            mHeicStallDurations = checkArrayElementsNotNull(heicStallDurations,
+                    "heicStallDurations");
+        }
+
         if (highSpeedVideoConfigurations == null) {
             mHighSpeedVideoConfigurations = new HighSpeedVideoConfiguration[0];
         } else {
@@ -235,6 +294,17 @@
                     mDynamicDepthOutputFormats.get(config.getFormat()) + 1);
         }
 
+        // For each heic format, track how many sizes there are available to configure
+        for (StreamConfiguration config : mHeicConfigurations) {
+            if (!config.isOutput()) {
+                // Ignoring input depth configs
+                continue;
+            }
+
+            mHeicOutputFormats.put(config.getFormat(),
+                    mHeicOutputFormats.get(config.getFormat()) + 1);
+        }
+
         if (configurations != null && enforceImplementationDefined &&
                 mOutputFormats.indexOfKey(HAL_PIXEL_FORMAT_IMPLEMENTATION_DEFINED) < 0) {
             throw new AssertionError(
@@ -302,7 +372,16 @@
         if (mInputOutputFormatsMap == null) {
             return new int[0];
         }
-        return mInputOutputFormatsMap.getOutputs(inputFormat);
+
+        int[] outputs = mInputOutputFormatsMap.getOutputs(inputFormat);
+        if (mHeicOutputFormats.size() > 0) {
+            // All reprocessing formats map contain JPEG.
+            int[] outputsWithHeic = Arrays.copyOf(outputs, outputs.length+1);
+            outputsWithHeic[outputs.length] = ImageFormat.HEIC;
+            return outputsWithHeic;
+        } else {
+            return outputs;
+        }
     }
 
     /**
@@ -366,6 +445,8 @@
             return mDepthOutputFormats.indexOfKey(internalFormat) >= 0;
         } else if (dataspace == HAL_DATASPACE_DYNAMIC_DEPTH) {
             return mDynamicDepthOutputFormats.indexOfKey(internalFormat) >= 0;
+        } else if (dataspace == HAL_DATASPACE_HEIF) {
+            return mHeicOutputFormats.indexOfKey(internalFormat) >= 0;
         } else {
             return getFormatsMap(/*output*/true).indexOfKey(internalFormat) >= 0;
         }
@@ -479,6 +560,7 @@
         StreamConfiguration[] configs =
                 surfaceDataspace == HAL_DATASPACE_DEPTH ? mDepthConfigurations :
                 surfaceDataspace == HAL_DATASPACE_DYNAMIC_DEPTH ? mDynamicDepthConfigurations :
+                surfaceDataspace == HAL_DATASPACE_HEIF ? mHeicConfigurations :
                 mConfigurations;
         for (StreamConfiguration config : configs) {
             if (config.getFormat() == surfaceFormat && config.isOutput()) {
@@ -512,9 +594,10 @@
         int dataspace = imageFormatToDataspace(format);
 
         StreamConfiguration[] configs =
-            dataspace == HAL_DATASPACE_DEPTH ? mDepthConfigurations :
-            dataspace == HAL_DATASPACE_DYNAMIC_DEPTH ? mDynamicDepthConfigurations :
-            mConfigurations;
+                dataspace == HAL_DATASPACE_DEPTH ? mDepthConfigurations :
+                dataspace == HAL_DATASPACE_DYNAMIC_DEPTH ? mDynamicDepthConfigurations :
+                dataspace == HAL_DATASPACE_HEIF ? mHeicConfigurations :
+                mConfigurations;
         for (StreamConfiguration config : configs) {
             if ((config.getFormat() == internalFormat) && config.isOutput() &&
                     config.getSize().equals(size)) {
@@ -1033,6 +1116,9 @@
                     Arrays.equals(mDynamicDepthMinFrameDurations,
                             other.mDynamicDepthMinFrameDurations) &&
                     Arrays.equals(mDynamicDepthStallDurations, other.mDynamicDepthStallDurations) &&
+                    Arrays.equals(mHeicConfigurations, other.mHeicConfigurations) &&
+                    Arrays.equals(mHeicMinFrameDurations, other.mHeicMinFrameDurations) &&
+                    Arrays.equals(mHeicStallDurations, other.mHeicStallDurations) &&
                     Arrays.equals(mHighSpeedVideoConfigurations,
                             other.mHighSpeedVideoConfigurations);
         }
@@ -1049,7 +1135,9 @@
                 mConfigurations, mMinFrameDurations, mStallDurations,
                 mDepthConfigurations, mDepthMinFrameDurations, mDepthStallDurations,
                 mDynamicDepthConfigurations, mDynamicDepthMinFrameDurations,
-                mDynamicDepthStallDurations, mHighSpeedVideoConfigurations);
+                mDynamicDepthStallDurations, mHeicConfigurations,
+                mHeicMinFrameDurations, mHeicStallDurations,
+                mHighSpeedVideoConfigurations);
     }
 
     // Check that the argument is supported by #getOutputFormats or #getInputFormats
@@ -1068,6 +1156,10 @@
                 if (mDynamicDepthOutputFormats.indexOfKey(internalFormat) >= 0) {
                     return format;
                 }
+            } else if (internalDataspace == HAL_DATASPACE_HEIF) {
+                if (mHeicOutputFormats.indexOfKey(internalFormat) >= 0) {
+                    return format;
+                }
             } else {
                 if (mAllOutputFormats.indexOfKey(internalFormat) >= 0) {
                     return format;
@@ -1108,8 +1200,9 @@
             case HAL_PIXEL_FORMAT_Y16:
                 return format;
             case ImageFormat.JPEG:
+            case ImageFormat.HEIC:
                 throw new IllegalArgumentException(
-                        "ImageFormat.JPEG is an unknown internal format");
+                        "An unknown internal format: " + format);
             default:
                 return checkArgumentFormat(format);
         }
@@ -1267,6 +1360,8 @@
      * <ul>
      * <li>ImageFormat.JPEG => HAL_PIXEL_FORMAT_BLOB
      * <li>ImageFormat.DEPTH_POINT_CLOUD => HAL_PIXEL_FORMAT_BLOB
+     * <li>ImageFormat.DEPTH_JPEG => HAL_PIXEL_FORMAT_BLOB
+     * <li>ImageFormat.HEIC => HAL_PIXEL_FORMAT_BLOB
      * <li>ImageFormat.DEPTH16 => HAL_PIXEL_FORMAT_Y16
      * </ul>
      * </p>
@@ -1292,6 +1387,7 @@
             case ImageFormat.JPEG:
             case ImageFormat.DEPTH_POINT_CLOUD:
             case ImageFormat.DEPTH_JPEG:
+            case ImageFormat.HEIC:
                 return HAL_PIXEL_FORMAT_BLOB;
             case ImageFormat.DEPTH16:
                 return HAL_PIXEL_FORMAT_Y16;
@@ -1312,6 +1408,7 @@
      * <li>ImageFormat.DEPTH_POINT_CLOUD => HAL_DATASPACE_DEPTH
      * <li>ImageFormat.DEPTH16 => HAL_DATASPACE_DEPTH
      * <li>ImageFormat.DEPTH_JPEG => HAL_DATASPACE_DYNAMIC_DEPTH
+     * <li>ImageFormat.HEIC => HAL_DATASPACE_HEIF
      * <li>others => HAL_DATASPACE_UNKNOWN
      * </ul>
      * </p>
@@ -1343,6 +1440,8 @@
                 return HAL_DATASPACE_DEPTH;
             case ImageFormat.DEPTH_JPEG:
                 return HAL_DATASPACE_DYNAMIC_DEPTH;
+            case ImageFormat.HEIC:
+                return HAL_DATASPACE_HEIF;
             default:
                 return HAL_DATASPACE_UNKNOWN;
         }
@@ -1394,14 +1493,17 @@
                 !output ? mInputFormats :
                 dataspace == HAL_DATASPACE_DEPTH ? mDepthOutputFormats :
                 dataspace == HAL_DATASPACE_DYNAMIC_DEPTH ? mDynamicDepthOutputFormats :
+                dataspace == HAL_DATASPACE_HEIF ? mHeicOutputFormats :
                 highRes ? mHighResOutputFormats :
                 mOutputFormats;
 
         int sizesCount = formatsMap.get(format);
         if ( ((!output || (dataspace == HAL_DATASPACE_DEPTH ||
-                            dataspace == HAL_DATASPACE_DYNAMIC_DEPTH)) && sizesCount == 0) ||
+                            dataspace == HAL_DATASPACE_DYNAMIC_DEPTH ||
+                            dataspace == HAL_DATASPACE_HEIF)) && sizesCount == 0) ||
                 (output && (dataspace != HAL_DATASPACE_DEPTH &&
-                            dataspace != HAL_DATASPACE_DYNAMIC_DEPTH) &&
+                            dataspace != HAL_DATASPACE_DYNAMIC_DEPTH &&
+                            dataspace != HAL_DATASPACE_HEIF) &&
                  mAllOutputFormats.get(format) == 0)) {
             // Only throw if this is really not supported at all
             throw new IllegalArgumentException("format not available");
@@ -1413,10 +1515,12 @@
         StreamConfiguration[] configurations =
                 (dataspace == HAL_DATASPACE_DEPTH) ? mDepthConfigurations :
                 (dataspace == HAL_DATASPACE_DYNAMIC_DEPTH) ? mDynamicDepthConfigurations :
+                (dataspace == HAL_DATASPACE_HEIF) ? mHeicConfigurations :
                 mConfigurations;
         StreamConfigurationDuration[] minFrameDurations =
                 (dataspace == HAL_DATASPACE_DEPTH) ? mDepthMinFrameDurations :
                 (dataspace == HAL_DATASPACE_DYNAMIC_DEPTH) ? mDynamicDepthMinFrameDurations :
+                (dataspace == HAL_DATASPACE_HEIF) ? mHeicMinFrameDurations :
                 mMinFrameDurations;
 
         for (StreamConfiguration config : configurations) {
@@ -1445,7 +1549,8 @@
         }
 
         // Dynamic depth streams can have both fast and also high res modes.
-        if ((sizeIndex != sizesCount) && (dataspace == HAL_DATASPACE_DYNAMIC_DEPTH)) {
+        if ((sizeIndex != sizesCount) && (dataspace == HAL_DATASPACE_DYNAMIC_DEPTH ||
+                dataspace == HAL_DATASPACE_HEIF)) {
 
             if (sizeIndex > sizesCount) {
                 throw new AssertionError(
@@ -1485,6 +1590,9 @@
                 // Only one publicly dynamic depth format is available.
                 formats[i++] = ImageFormat.DEPTH_JPEG;
             }
+            if (mHeicOutputFormats.size() > 0) {
+                formats[i++] = ImageFormat.HEIC;
+            }
         }
         if (formats.length != i) {
             throw new AssertionError("Too few formats " + i + ", expected " + formats.length);
@@ -1529,10 +1637,14 @@
             case DURATION_MIN_FRAME:
                 return (dataspace == HAL_DATASPACE_DEPTH) ? mDepthMinFrameDurations :
                         (dataspace == HAL_DATASPACE_DYNAMIC_DEPTH) ?
-                        mDynamicDepthMinFrameDurations : mMinFrameDurations;
+                        mDynamicDepthMinFrameDurations :
+                        (dataspace == HAL_DATASPACE_HEIF) ? mHeicMinFrameDurations :
+                        mMinFrameDurations;
+
             case DURATION_STALL:
                 return (dataspace == HAL_DATASPACE_DEPTH) ? mDepthStallDurations :
                         (dataspace == HAL_DATASPACE_DYNAMIC_DEPTH) ? mDynamicDepthStallDurations :
+                        (dataspace == HAL_DATASPACE_HEIF) ? mHeicStallDurations :
                         mStallDurations;
             default:
                 throw new IllegalArgumentException("duration was invalid");
@@ -1546,6 +1658,7 @@
         if (output) {
             size += mDepthOutputFormats.size();
             size += mDynamicDepthOutputFormats.size();
+            size += mHeicOutputFormats.size();
         }
 
         return size;
@@ -1569,6 +1682,7 @@
         StreamConfiguration[] configurations =
                 (dataspace == HAL_DATASPACE_DEPTH) ? mDepthConfigurations :
                 (dataspace == HAL_DATASPACE_DYNAMIC_DEPTH) ? mDynamicDepthConfigurations :
+                (dataspace == HAL_DATASPACE_HEIF) ? mHeicConfigurations :
                 mConfigurations;
 
         for (int i = 0; i < configurations.length; i++) {
@@ -1767,6 +1881,8 @@
                 return "RAW_DEPTH";
             case ImageFormat.PRIVATE:
                 return "PRIVATE";
+            case ImageFormat.HEIC:
+                return "HEIC";
             default:
                 return "UNKNOWN";
         }
@@ -1795,7 +1911,7 @@
 
     private static final int HAL_DATASPACE_DEPTH = 0x1000;
     private static final int HAL_DATASPACE_DYNAMIC_DEPTH = 0x1002;
-
+    private static final int HAL_DATASPACE_HEIF = 0x1003;
     private static final long DURATION_20FPS_NS = 50000000L;
     /**
      * @see #getDurations(int, int)
@@ -1815,6 +1931,10 @@
     private final StreamConfigurationDuration[] mDynamicDepthMinFrameDurations;
     private final StreamConfigurationDuration[] mDynamicDepthStallDurations;
 
+    private final StreamConfiguration[] mHeicConfigurations;
+    private final StreamConfigurationDuration[] mHeicMinFrameDurations;
+    private final StreamConfigurationDuration[] mHeicStallDurations;
+
     private final HighSpeedVideoConfiguration[] mHighSpeedVideoConfigurations;
     private final ReprocessFormatsMap mInputOutputFormatsMap;
 
@@ -1834,6 +1954,9 @@
     private final SparseIntArray mDepthOutputFormats = new SparseIntArray();
     /** internal format -> num dynamic depth output sizes mapping, for HAL_DATASPACE_DYNAMIC_DEPTH */
     private final SparseIntArray mDynamicDepthOutputFormats = new SparseIntArray();
+    /** internal format -> num heic output sizes mapping, for HAL_DATASPACE_HEIF */
+    private final SparseIntArray mHeicOutputFormats = new SparseIntArray();
+
     /** High speed video Size -> FPS range count mapping*/
     private final HashMap</*HighSpeedVideoSize*/Size, /*Count*/Integer> mHighSpeedVideoSizeMap =
             new HashMap<Size, Integer>();
diff --git a/core/java/android/hardware/display/NightDisplayListener.java b/core/java/android/hardware/display/NightDisplayListener.java
new file mode 100644
index 0000000..468f833
--- /dev/null
+++ b/core/java/android/hardware/display/NightDisplayListener.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.display;
+
+import android.annotation.NonNull;
+import android.annotation.UserIdInt;
+import android.app.ActivityManager;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.Looper;
+import android.provider.Settings.Secure;
+
+import java.time.LocalTime;
+
+/**
+ * @hide
+ */
+public class NightDisplayListener {
+
+    private final Context mContext;
+    private final int mUserId;
+    private final ColorDisplayManager mManager;
+
+    private ContentObserver mContentObserver;
+    private Callback mCallback;
+
+    public NightDisplayListener(@NonNull Context context) {
+        this(context, ActivityManager.getCurrentUser());
+    }
+
+    public NightDisplayListener(@NonNull Context context, @UserIdInt int userId) {
+        mContext = context.getApplicationContext();
+        mUserId = userId;
+        mManager = mContext.getSystemService(ColorDisplayManager.class);
+    }
+
+    /**
+     * Register a callback to be invoked whenever the Night display settings are changed.
+     */
+    public void setCallback(Callback callback) {
+        final Callback oldCallback = mCallback;
+        if (oldCallback != callback) {
+            mCallback = callback;
+
+            if (mContentObserver == null) {
+                mContentObserver = new ContentObserver(new Handler(Looper.getMainLooper())) {
+                    @Override
+                    public void onChange(boolean selfChange, Uri uri) {
+                        super.onChange(selfChange, uri);
+                        onSettingChanged(uri);
+                    }
+                };
+            }
+
+            if (callback == null) {
+                // Stop listening for changes now that there IS NOT a callback.
+                mContext.getContentResolver().unregisterContentObserver(mContentObserver);
+            } else if (oldCallback == null) {
+                // Start listening for changes now that there IS a callback.
+                final ContentResolver cr = mContext.getContentResolver();
+                cr.registerContentObserver(Secure.getUriFor(Secure.NIGHT_DISPLAY_ACTIVATED),
+                        false /* notifyForDescendants */, mContentObserver, mUserId);
+                cr.registerContentObserver(Secure.getUriFor(Secure.NIGHT_DISPLAY_AUTO_MODE),
+                        false /* notifyForDescendants */, mContentObserver, mUserId);
+                cr.registerContentObserver(Secure.getUriFor(Secure.NIGHT_DISPLAY_CUSTOM_START_TIME),
+                        false /* notifyForDescendants */, mContentObserver, mUserId);
+                cr.registerContentObserver(Secure.getUriFor(Secure.NIGHT_DISPLAY_CUSTOM_END_TIME),
+                        false /* notifyForDescendants */, mContentObserver, mUserId);
+                cr.registerContentObserver(Secure.getUriFor(Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE),
+                        false /* notifyForDescendants */, mContentObserver, mUserId);
+            }
+        }
+    }
+
+    private void onSettingChanged(Uri uri) {
+        final String setting = uri == null ? null : uri.getLastPathSegment();
+        if (setting == null || mCallback == null) {
+            return;
+        }
+
+        switch (setting) {
+            case Secure.NIGHT_DISPLAY_ACTIVATED:
+                mCallback.onActivated(mManager.isNightDisplayActivated());
+                break;
+            case Secure.NIGHT_DISPLAY_AUTO_MODE:
+                mCallback.onAutoModeChanged(mManager.getNightDisplayAutoMode());
+                break;
+            case Secure.NIGHT_DISPLAY_CUSTOM_START_TIME:
+                mCallback.onCustomStartTimeChanged(mManager.getNightDisplayCustomStartTime());
+                break;
+            case Secure.NIGHT_DISPLAY_CUSTOM_END_TIME:
+                mCallback.onCustomEndTimeChanged(mManager.getNightDisplayCustomEndTime());
+                break;
+            case Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE:
+                mCallback.onColorTemperatureChanged(mManager.getNightDisplayColorTemperature());
+                break;
+        }
+    }
+
+    /**
+     * Callback invoked whenever the Night display settings are changed.
+     */
+    public interface Callback {
+        /**
+         * Callback invoked when the activated state changes.
+         *
+         * @param activated {@code true} if Night display is activated
+         */
+        default void onActivated(boolean activated) {}
+        /**
+         * Callback invoked when the auto mode changes.
+         *
+         * @param autoMode the auto mode to use
+         */
+        default void onAutoModeChanged(int autoMode) {}
+        /**
+         * Callback invoked when the time to automatically activate Night display changes.
+         *
+         * @param startTime the local time to automatically activate Night display
+         */
+        default void onCustomStartTimeChanged(LocalTime startTime) {}
+        /**
+         * Callback invoked when the time to automatically deactivate Night display changes.
+         *
+         * @param endTime the local time to automatically deactivate Night display
+         */
+        default void onCustomEndTimeChanged(LocalTime endTime) {}
+
+        /**
+         * Callback invoked when the color temperature changes.
+         *
+         * @param colorTemperature the color temperature to tint the screen
+         */
+        default void onColorTemperatureChanged(int colorTemperature) {}
+    }
+}
diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java
index c9a7830..efe24e5 100644
--- a/core/java/android/hardware/face/FaceManager.java
+++ b/core/java/android/hardware/face/FaceManager.java
@@ -565,16 +565,16 @@
      */
     public static String getErrorString(Context context, int errMsg, int vendorCode) {
         switch (errMsg) {
-            case FACE_ERROR_UNABLE_TO_PROCESS:
-                return context.getString(
-                        com.android.internal.R.string.face_error_unable_to_process);
             case FACE_ERROR_HW_UNAVAILABLE:
                 return context.getString(
                         com.android.internal.R.string.face_error_hw_not_available);
-            case FACE_ERROR_NO_SPACE:
-                return context.getString(com.android.internal.R.string.face_error_no_space);
+            case FACE_ERROR_UNABLE_TO_PROCESS:
+                return context.getString(
+                        com.android.internal.R.string.face_error_unable_to_process);
             case FACE_ERROR_TIMEOUT:
                 return context.getString(com.android.internal.R.string.face_error_timeout);
+            case FACE_ERROR_NO_SPACE:
+                return context.getString(com.android.internal.R.string.face_error_no_space);
             case FACE_ERROR_CANCELED:
                 return context.getString(com.android.internal.R.string.face_error_canceled);
             case FACE_ERROR_LOCKOUT:
@@ -629,6 +629,24 @@
                 return context.getString(R.string.face_acquired_poor_gaze);
             case FACE_ACQUIRED_NOT_DETECTED:
                 return context.getString(R.string.face_acquired_not_detected);
+            case FACE_ACQUIRED_TOO_MUCH_MOTION:
+                return context.getString(R.string.face_acquired_too_much_motion);
+            case FACE_ACQUIRED_RECALIBRATE:
+                return context.getString(R.string.face_acquired_recalibrate);
+            case FACE_ACQUIRED_TOO_DIFFERENT:
+                return context.getString(R.string.face_acquired_too_different);
+            case FACE_ACQUIRED_TOO_SIMILAR:
+                return context.getString(R.string.face_acquired_too_similar);
+            case FACE_ACQUIRED_PAN_TOO_EXTREME:
+                return context.getString(R.string.face_acquired_pan_too_extreme);
+            case FACE_ACQUIRED_TILT_TOO_EXTREME:
+                return context.getString(R.string.face_acquired_tilt_too_extreme);
+            case FACE_ACQUIRED_ROLL_TOO_EXTREME:
+                return context.getString(R.string.face_acquired_roll_too_extreme);
+            case FACE_ACQUIRED_FACE_OBSCURED:
+                return context.getString(R.string.face_acquired_obscured);
+            case FACE_ACQUIRED_START:
+                return null;
             case FACE_ACQUIRED_VENDOR: {
                 String[] msgArray = context.getResources().getStringArray(
                         R.array.face_acquired_vendor);
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index bb98211..80d404d 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -949,17 +949,17 @@
      */
     public static String getErrorString(Context context, int errMsg, int vendorCode) {
         switch (errMsg) {
+            case FINGERPRINT_ERROR_HW_UNAVAILABLE:
+                return context.getString(
+                        com.android.internal.R.string.fingerprint_error_hw_not_available);
             case FINGERPRINT_ERROR_UNABLE_TO_PROCESS:
                 return context.getString(
                     com.android.internal.R.string.fingerprint_error_unable_to_process);
-            case FINGERPRINT_ERROR_HW_UNAVAILABLE:
-                return context.getString(
-                    com.android.internal.R.string.fingerprint_error_hw_not_available);
+            case FINGERPRINT_ERROR_TIMEOUT:
+                return context.getString(com.android.internal.R.string.fingerprint_error_timeout);
             case FINGERPRINT_ERROR_NO_SPACE:
                 return context.getString(
                     com.android.internal.R.string.fingerprint_error_no_space);
-            case FINGERPRINT_ERROR_TIMEOUT:
-                return context.getString(com.android.internal.R.string.fingerprint_error_timeout);
             case FINGERPRINT_ERROR_CANCELED:
                 return context.getString(com.android.internal.R.string.fingerprint_error_canceled);
             case FINGERPRINT_ERROR_LOCKOUT:
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 866ea16..2aca55a 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -68,6 +68,7 @@
 import java.lang.annotation.RetentionPolicy;
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
+import java.net.Socket;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.List;
@@ -1889,7 +1890,8 @@
      * @param callback A {@link SocketKeepalive.Callback}. Used for notifications about keepalive
      *        changes. Must be extended by applications that use this API.
      *
-     * @return A {@link SocketKeepalive} object, which can be used to control this keepalive object.
+     * @return A {@link SocketKeepalive} object that can be used to control the keepalive on the
+     *         given socket.
      **/
     public SocketKeepalive createSocketKeepalive(@NonNull Network network,
             @NonNull UdpEncapsulationSocket socket,
@@ -1918,6 +1920,8 @@
      * @param callback A {@link SocketKeepalive.Callback}. Used for notifications about keepalive
      *        changes. Must be extended by applications that use this API.
      *
+     * @return A {@link SocketKeepalive} object that can be used to control the keepalive on the
+     *         given socket.
      * @hide
      */
     @SystemApi
@@ -1933,6 +1937,34 @@
     }
 
     /**
+     * Request that keepalives be started on a TCP socket.
+     * The socket must be established.
+     *
+     * @param network The {@link Network} the socket is on.
+     * @param socket The socket that needs to be kept alive.
+     * @param executor The executor on which callback will be invoked. This implementation assumes
+     *                 the provided {@link Executor} runs the callbacks in sequence with no
+     *                 concurrency. Failing this, no guarantee of correctness can be made. It is
+     *                 the responsibility of the caller to ensure the executor provides this
+     *                 guarantee. A simple way of creating such an executor is with the standard
+     *                 tool {@code Executors.newSingleThreadExecutor}.
+     * @param callback A {@link SocketKeepalive.Callback}. Used for notifications about keepalive
+     *        changes. Must be extended by applications that use this API.
+     *
+     * @return A {@link SocketKeepalive} object that can be used to control the keepalive on the
+     *         given socket.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD)
+    public SocketKeepalive createSocketKeepalive(@NonNull Network network,
+            @NonNull Socket socket,
+            @NonNull Executor executor,
+            @NonNull Callback callback) {
+        return new TcpSocketKeepalive(mService, network, socket, executor, callback);
+    }
+
+    /**
      * Ensure that a network route exists to deliver traffic to the specified
      * host via the specified network interface. An attempt to add a route that
      * already exists is ignored, but treated as successful.
@@ -3891,6 +3923,25 @@
     }
 
     /**
+     * Requests that the system open the captive portal app with the specified extras.
+     *
+     * <p>This endpoint is exclusively for use by the NetworkStack and is protected by the
+     * corresponding permission.
+     * @param appExtras Extras to include in the app start intent.
+     * @hide
+     */
+    @SystemApi
+    @TestApi
+    @RequiresPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK)
+    public void startCaptivePortalApp(Bundle appExtras) {
+        try {
+            mService.startCaptivePortalAppInternal(appExtras);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Determine whether the device is configured to avoid bad wifi.
      * @hide
      */
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 1148ac1..872671f 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -27,6 +27,7 @@
 import android.net.NetworkRequest;
 import android.net.NetworkState;
 import android.net.ProxyInfo;
+import android.os.Bundle;
 import android.os.IBinder;
 import android.os.Messenger;
 import android.os.ParcelFileDescriptor;
@@ -167,6 +168,7 @@
     void setAcceptUnvalidated(in Network network, boolean accept, boolean always);
     void setAvoidUnvalidated(in Network network);
     void startCaptivePortalApp(in Network network);
+    void startCaptivePortalAppInternal(in Bundle appExtras);
 
     boolean getAvoidBadWifi();
     int getMultipathPreference(in Network Network);
@@ -188,6 +190,9 @@
             int intervalSeconds, in Messenger messenger, in IBinder binder, String srcAddr,
             String dstAddr);
 
+    void startTcpKeepalive(in Network network, in FileDescriptor fd, int intervalSeconds,
+            in Messenger messenger, in IBinder binder);
+
     void stopKeepalive(in Network network, int slot);
 
     String getCaptivePortalServerUrl();
diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java
index c3783783..273f8cd 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -178,6 +178,26 @@
      */
     public static final int EVENT_SOCKET_KEEPALIVE = BASE + 13;
 
+    // TODO: move the above 2 constants down so they are in order once merge conflicts are resolved
+    /**
+     * Sent by the KeepaliveTracker to NetworkAgent to add a packet filter.
+     *
+     * For TCP keepalive offloads, keepalive packets are sent by the firmware. However, because the
+     * remote site will send ACK packets in response to the keepalive packets, the firmware also
+     * needs to be configured to properly filter the ACKs to prevent the system from waking up.
+     * This does not happen with UDP, so this message is TCP-specific.
+     * arg1 = slot number of the keepalive to filter for.
+     * obj = the keepalive packet to send repeatedly.
+     */
+    public static final int CMD_ADD_KEEPALIVE_PACKET_FILTER = BASE + 16;
+
+    /**
+     * Sent by the KeepaliveTracker to NetworkAgent to remove a packet filter. See
+     * {@link #CMD_ADD_KEEPALIVE_PACKET_FILTER}.
+     * arg1 = slot number of the keepalive packet filter to remove.
+     */
+    public static final int CMD_REMOVE_KEEPALIVE_PACKET_FILTER = BASE + 17;
+
     /**
      * Sent by ConnectivityService to inform this network transport of signal strength thresholds
      * that when crossed should trigger a system wakeup and a NetworkCapabilities update.
@@ -329,6 +349,14 @@
                 preventAutomaticReconnect();
                 break;
             }
+            case CMD_ADD_KEEPALIVE_PACKET_FILTER: {
+                addKeepalivePacketFilter(msg);
+                break;
+            }
+            case CMD_REMOVE_KEEPALIVE_PACKET_FILTER: {
+                removeKeepalivePacketFilter(msg);
+                break;
+            }
         }
     }
 
@@ -478,6 +506,24 @@
     }
 
     /**
+     * Called by ConnectivityService to add specific packet filter to network hardware to block
+     * ACKs matching the sent keepalive packets. Implementations that support this feature must
+     * override this method.
+     */
+    protected void addKeepalivePacketFilter(Message msg) {
+        onSocketKeepaliveEvent(msg.arg1, SocketKeepalive.ERROR_HARDWARE_UNSUPPORTED);
+    }
+
+    /**
+     * Called by ConnectivityService to remove a packet filter installed with
+     * {@link #addKeepalivePacketFilter(Message)}. Implementations that support this feature
+     * must override this method.
+     */
+    protected void removeKeepalivePacketFilter(Message msg) {
+        onSocketKeepaliveEvent(msg.arg1, SocketKeepalive.ERROR_HARDWARE_UNSUPPORTED);
+    }
+
+    /**
      * Called by ConnectivityService to inform this network transport of signal strength thresholds
      * that when crossed should trigger a system wakeup and a NetworkCapabilities update.
      */
diff --git a/core/java/android/net/SocketKeepalive.java b/core/java/android/net/SocketKeepalive.java
index 7ea1bef..07728be 100644
--- a/core/java/android/net/SocketKeepalive.java
+++ b/core/java/android/net/SocketKeepalive.java
@@ -19,6 +19,7 @@
 import android.annotation.IntDef;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Looper;
@@ -155,7 +156,7 @@
     @NonNull private final SocketKeepalive.Callback mCallback;
     @NonNull private final Looper mLooper;
     @NonNull final Messenger mMessenger;
-    @NonNull Integer mSlot;
+    @Nullable Integer mSlot;
 
     SocketKeepalive(@NonNull IConnectivityManager service, @NonNull Network network,
             @NonNull Executor executor, @NonNull Callback callback) {
diff --git a/core/java/android/net/TcpSocketKeepalive.java b/core/java/android/net/TcpSocketKeepalive.java
new file mode 100644
index 0000000..8f6ee7b
--- /dev/null
+++ b/core/java/android/net/TcpSocketKeepalive.java
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+import android.annotation.NonNull;
+import android.os.Binder;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.io.FileDescriptor;
+import java.net.Socket;
+import java.util.concurrent.Executor;
+
+/** @hide */
+final class TcpSocketKeepalive extends SocketKeepalive {
+
+    private final Socket mSocket;
+
+    TcpSocketKeepalive(@NonNull IConnectivityManager service,
+            @NonNull Network network,
+            @NonNull Socket socket,
+            @NonNull Executor executor,
+            @NonNull Callback callback) {
+        super(service, network, executor, callback);
+        mSocket = socket;
+    }
+
+    /**
+     * Starts keepalives. {@code mSocket} must be a connected TCP socket.
+     *
+     * - The application must not write to or read from the socket after calling this method, until
+     *   onDataReceived, onStopped, or onError are called. If it does, the keepalive will fail
+     *   with {@link #ERROR_SOCKET_NOT_IDLE}, or {@code #ERROR_INVALID_SOCKET} if the socket
+     *   experienced an error (as in poll(2) returned POLLERR); if this happens, the data received
+     *   from the socket may be invalid, and the socket can't be recovered.
+     * - If the socket has data in the send or receive buffer, then this call will fail with
+     *   {@link #ERROR_SOCKET_NOT_IDLE} and can be retried after the data has been processed.
+     *   An app could ensure this by using an application-layer protocol where it can receive
+     *   acknowledgement that it will go into keepalive mode. It could then go into keepalive
+     *   mode after having read the acknowledgement, draining the socket.
+     */
+    @Override
+    void startImpl(int intervalSec) {
+        try {
+            final FileDescriptor fd = mSocket.getFileDescriptor$();
+            mService.startTcpKeepalive(mNetwork, fd, intervalSec, mMessenger, new Binder());
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error starting packet keepalive: ", e);
+            stopLooper();
+        }
+    }
+
+    @Override
+    void stopImpl() {
+        try {
+            if (mSlot != null) {
+                mService.stopKeepalive(mNetwork, mSlot);
+            }
+        } catch (RemoteException e) {
+            Log.e(TAG, "Error stopping packet keepalive: ", e);
+            stopLooper();
+        }
+    }
+}
diff --git a/core/java/android/net/ip/IIpClient.aidl b/core/java/android/net/ip/IIpClient.aidl
index 7769ec2..a4a80e1 100644
--- a/core/java/android/net/ip/IIpClient.aidl
+++ b/core/java/android/net/ip/IIpClient.aidl
@@ -17,6 +17,7 @@
 
 import android.net.ProxyInfoParcelable;
 import android.net.ProvisioningConfigurationParcelable;
+import android.net.TcpKeepalivePacketDataParcelable;
 
 /** @hide */
 oneway interface IIpClient {
@@ -29,4 +30,6 @@
     void setTcpBufferSizes(in String tcpBufferSizes);
     void setHttpProxy(in ProxyInfoParcelable proxyInfo);
     void setMulticastFilter(boolean enabled);
+    void addKeepalivePacketFilter(int slot, in TcpKeepalivePacketDataParcelable pkt);
+    void removeKeepalivePacketFilter(int slot);
 }
diff --git a/core/java/android/os/BatterySaverPolicyConfig.java b/core/java/android/os/BatterySaverPolicyConfig.java
index b6e2b69..a107a7a 100644
--- a/core/java/android/os/BatterySaverPolicyConfig.java
+++ b/core/java/android/os/BatterySaverPolicyConfig.java
@@ -47,10 +47,11 @@
     private final boolean mEnableAdjustBrightness;
     private final boolean mEnableDataSaver;
     private final boolean mEnableFirewall;
+    private final boolean mEnableNightMode;
     private final boolean mEnableQuickDoze;
     private final boolean mForceAllAppsStandby;
     private final boolean mForceBackgroundCheck;
-    private final int mGpsMode;
+    private final int mLocationMode;
 
     private BatterySaverPolicyConfig(Builder in) {
         mAdjustBrightnessFactor = Math.max(0, Math.min(in.mAdjustBrightnessFactor, 1f));
@@ -67,11 +68,12 @@
         mEnableAdjustBrightness = in.mEnableAdjustBrightness;
         mEnableDataSaver = in.mEnableDataSaver;
         mEnableFirewall = in.mEnableFirewall;
+        mEnableNightMode = in.mEnableNightMode;
         mEnableQuickDoze = in.mEnableQuickDoze;
         mForceAllAppsStandby = in.mForceAllAppsStandby;
         mForceBackgroundCheck = in.mForceBackgroundCheck;
-        mGpsMode = Math.max(PowerManager.MIN_LOCATION_MODE,
-                Math.min(in.mGpsMode, PowerManager.MAX_LOCATION_MODE));
+        mLocationMode = Math.max(PowerManager.MIN_LOCATION_MODE,
+                Math.min(in.mLocationMode, PowerManager.MAX_LOCATION_MODE));
     }
 
     private BatterySaverPolicyConfig(Parcel in) {
@@ -101,10 +103,11 @@
         mEnableAdjustBrightness = in.readBoolean();
         mEnableDataSaver = in.readBoolean();
         mEnableFirewall = in.readBoolean();
+        mEnableNightMode = in.readBoolean();
         mEnableQuickDoze = in.readBoolean();
         mForceAllAppsStandby = in.readBoolean();
         mForceBackgroundCheck = in.readBoolean();
-        mGpsMode = Math.max(PowerManager.MIN_LOCATION_MODE,
+        mLocationMode = Math.max(PowerManager.MIN_LOCATION_MODE,
                 Math.min(in.readInt(), PowerManager.MAX_LOCATION_MODE));
     }
 
@@ -150,10 +153,11 @@
         dest.writeBoolean(mEnableAdjustBrightness);
         dest.writeBoolean(mEnableDataSaver);
         dest.writeBoolean(mEnableFirewall);
+        dest.writeBoolean(mEnableNightMode);
         dest.writeBoolean(mEnableQuickDoze);
         dest.writeBoolean(mForceAllAppsStandby);
         dest.writeBoolean(mForceBackgroundCheck);
-        dest.writeInt(mGpsMode);
+        dest.writeInt(mLocationMode);
     }
 
     @Override
@@ -168,11 +172,12 @@
                 + "animation_disabled=" + mDisableAnimation + ","
                 + "aod_disabled=" + mDisableAod + ","
                 + "datasaver_disabled=" + !mEnableDataSaver + ","
+                + "enable_night_mode=" + mEnableNightMode + ","
                 + "firewall_disabled=" + !mEnableFirewall + ","
                 + "force_all_apps_standby=" + mForceAllAppsStandby + ","
                 + "force_background_check=" + mForceBackgroundCheck + ","
                 + "fullbackup_deferred=" + mDeferFullBackup + ","
-                + "gps_mode=" + mGpsMode + ","
+                + "gps_mode=" + mLocationMode + ","
                 + "keyvaluebackup_deferred=" + mDeferKeyValueBackup + ","
                 + "launch_boost_disabled=" + mDisableLaunchBoost + ","
                 + "optional_sensors_disabled=" + mDisableOptionalSensors + ","
@@ -260,6 +265,11 @@
         return mEnableFirewall;
     }
 
+    /** Whether or not to enable night mode while in Battery Saver. */
+    public boolean getEnableNightMode() {
+        return mEnableNightMode;
+    }
+
     /** Whether or not to enable Quick Doze while in Battery Saver. */
     public boolean getEnableQuickDoze() {
         return mEnableQuickDoze;
@@ -275,9 +285,9 @@
         return mForceBackgroundCheck;
     }
 
-    /** The GPS mode while in Battery Saver. */
-    public int getGpsMode() {
-        return mGpsMode;
+    /** The location mode while in Battery Saver. */
+    public int getLocationMode() {
+        return mLocationMode;
     }
 
     /** Builder class for constructing {@link BatterySaverPolicyConfig} objects. */
@@ -297,10 +307,11 @@
         private boolean mEnableAdjustBrightness = false;
         private boolean mEnableDataSaver = false;
         private boolean mEnableFirewall = false;
+        private boolean mEnableNightMode = false;
         private boolean mEnableQuickDoze = false;
         private boolean mForceAllAppsStandby = false;
         private boolean mForceBackgroundCheck = false;
-        private int mGpsMode = PowerManager.LOCATION_MODE_NO_CHANGE;
+        private int mLocationMode = PowerManager.LOCATION_MODE_NO_CHANGE;
 
         public Builder() {
         }
@@ -424,6 +435,13 @@
             return this;
         }
 
+        /** Set whether or not to enable night mode while in Battery Saver. */
+        @NonNull
+        public Builder setEnableNightMode(boolean enableNightMode) {
+            mEnableNightMode = enableNightMode;
+            return this;
+        }
+
         /** Set whether or not to enable Quick Doze while in Battery Saver. */
         @NonNull
         public Builder setEnableQuickDoze(boolean enableQuickDoze) {
@@ -445,10 +463,10 @@
             return this;
         }
 
-        /** Set the GPS mode while in Battery Saver. */
+        /** Set the location mode while in Battery Saver. */
         @NonNull
-        public Builder setGpsMode(@PowerManager.LocationPowerSaveMode int gpsMode) {
-            mGpsMode = gpsMode;
+        public Builder setLocationMode(@PowerManager.LocationPowerSaveMode int locationMode) {
+            mLocationMode = locationMode;
             return this;
         }
 
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 2d61a4e..83a7654 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -1120,11 +1120,9 @@
         /** The name identifying the system partition. */
         public static final String PARTITION_NAME_SYSTEM = "system";
 
-        private String mName;
-        private String mFingerprint;
-        private long mTimeMs;
-
-        public Partition() {}
+        private final String mName;
+        private final String mFingerprint;
+        private final long mTimeMs;
 
         private Partition(String name, String fingerprint, long timeMs) {
             mName = name;
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index 68f9288..269c781 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.res.AssetFileDescriptor;
@@ -59,6 +60,9 @@
 
     private static final boolean DEBUG = false;
     private static final String TAG = "GraphicsEnvironment";
+    private static final String SYSTEM_DRIVER_NAME = "system";
+    private static final String SYSTEM_DRIVER_VERSION_NAME = "";
+    private static final long SYSTEM_DRIVER_VERSION_CODE = 0;
     private static final String PROPERTY_GFX_DRIVER = "ro.gfx.driver.0";
     private static final String ANGLE_RULES_FILE = "a4a_rules.json";
     private static final String ANGLE_TEMP_RULES = "debug.angle.rules";
@@ -74,9 +78,14 @@
      * Set up GraphicsEnvironment
      */
     public void setup(Context context, Bundle coreSettings) {
-        setupGpuLayers(context, coreSettings);
-        setupAngle(context, coreSettings, context.getPackageName());
-        chooseDriver(context, coreSettings);
+        final PackageManager pm = context.getPackageManager();
+        final String packageName = context.getPackageName();
+        setupGpuLayers(context, coreSettings, pm, packageName);
+        setupAngle(context, coreSettings, pm, packageName);
+        if (!chooseDriver(context, coreSettings, pm, packageName)) {
+            setGpuStats(SYSTEM_DRIVER_NAME, SYSTEM_DRIVER_VERSION_NAME, SYSTEM_DRIVER_VERSION_CODE,
+                    packageName);
+        }
     }
 
     /**
@@ -102,11 +111,10 @@
     /**
      * Return the debug layer app's on-disk and in-APK lib directories
      */
-    private static String getDebugLayerAppPaths(Context context, String app) {
+    private static String getDebugLayerAppPaths(PackageManager pm, String app) {
         final ApplicationInfo appInfo;
         try {
-            appInfo = context.getPackageManager().getApplicationInfo(
-                    app, PackageManager.MATCH_ALL);
+            appInfo = pm.getApplicationInfo(app, PackageManager.MATCH_ALL);
         } catch (PackageManager.NameNotFoundException e) {
             Log.w(TAG, "Debug layer app '" + app + "' not installed");
 
@@ -132,8 +140,8 @@
      * Set up layer search paths for all apps
      * If debuggable, check for additional debug settings
      */
-    private void setupGpuLayers(Context context, Bundle coreSettings) {
-
+    private void setupGpuLayers(
+            Context context, Bundle coreSettings, PackageManager pm, String packageName) {
         String layerPaths = "";
 
         // Only enable additional debug functionality if the following conditions are met:
@@ -149,8 +157,6 @@
 
                 final String gpuDebugApp = coreSettings.getString(Settings.Global.GPU_DEBUG_APP);
 
-                final String packageName = context.getPackageName();
-
                 if ((gpuDebugApp != null && packageName != null)
                         && (!gpuDebugApp.isEmpty() && !packageName.isEmpty())
                         && gpuDebugApp.equals(packageName)) {
@@ -161,14 +167,13 @@
                     // the layers specified by the app.
                     layerPaths = mDebugLayerPath + ":";
 
-
                     // If there is a debug layer app specified, add its path.
                     final String gpuDebugLayerApp =
                             coreSettings.getString(Settings.Global.GPU_DEBUG_LAYER_APP);
 
                     if (gpuDebugLayerApp != null && !gpuDebugLayerApp.isEmpty()) {
                         Log.i(TAG, "GPU debug layer app: " + gpuDebugLayerApp);
-                        final String paths = getDebugLayerAppPaths(context, gpuDebugLayerApp);
+                        final String paths = getDebugLayerAppPaths(pm, gpuDebugLayerApp);
                         if (paths != null) {
                             // Append the path so files placed in the app's base directory will
                             // override the external path
@@ -280,11 +285,11 @@
     /**
      * Get the ANGLE package name.
      */
-    private String getAnglePackageName(Context context) {
+    private String getAnglePackageName(PackageManager pm) {
         final Intent intent = new Intent(ACTION_ANGLE_FOR_ANDROID);
 
-        final List<ResolveInfo> resolveInfos = context.getPackageManager().queryIntentActivities(
-                intent, PackageManager.MATCH_SYSTEM_ONLY);
+        final List<ResolveInfo> resolveInfos =
+                pm.queryIntentActivities(intent, PackageManager.MATCH_SYSTEM_ONLY);
         if (resolveInfos.size() != 1) {
             Log.e(TAG, "Invalid number of ANGLE packages. Required: 1, Found: "
                     + resolveInfos.size());
@@ -369,14 +374,13 @@
      */
     private boolean setupAngleRulesApk(String anglePkgName,
             ApplicationInfo angleInfo,
-            Context context,
+            PackageManager pm,
             String packageName,
             String paths,
             String devOptIn) {
         // Pass the rules file to loader for ANGLE decisions
         try {
-            final AssetManager angleAssets =
-                    context.getPackageManager().getResourcesForApplication(angleInfo).getAssets();
+            final AssetManager angleAssets = pm.getResourcesForApplication(angleInfo).getAssets();
 
             try {
                 final AssetFileDescriptor assetsFd = angleAssets.openFd(ANGLE_RULES_FILE);
@@ -411,7 +415,7 @@
     /**
      * Pass ANGLE details down to trigger enable logic
      */
-    public void setupAngle(Context context, Bundle bundle, String packageName) {
+    public void setupAngle(Context context, Bundle bundle, PackageManager pm, String packageName) {
         if (packageName.isEmpty()) {
             Log.v(TAG, "No package name available yet, skipping ANGLE setup");
             return;
@@ -449,7 +453,7 @@
             Log.v(TAG, "ANGLE developer option for " + packageName + ": " + devOptIn);
         }
 
-        final String anglePkgName = getAnglePackageName(context);
+        final String anglePkgName = getAnglePackageName(pm);
         if (anglePkgName.isEmpty()) {
             Log.e(TAG, "Failed to find ANGLE package.");
             return;
@@ -457,8 +461,7 @@
 
         final ApplicationInfo angleInfo;
         try {
-            angleInfo = context.getPackageManager().getApplicationInfo(anglePkgName,
-                PackageManager.MATCH_SYSTEM_ONLY);
+            angleInfo = pm.getApplicationInfo(anglePkgName, PackageManager.MATCH_SYSTEM_ONLY);
         } catch (PackageManager.NameNotFoundException e) {
             Log.w(TAG, "ANGLE package '" + anglePkgName + "' not installed");
             return;
@@ -480,7 +483,7 @@
             return;
         }
 
-        if (setupAngleRulesApk(anglePkgName, angleInfo, context, packageName, paths, devOptIn)) {
+        if (setupAngleRulesApk(anglePkgName, angleInfo, pm, packageName, paths, devOptIn)) {
             // We setup ANGLE with rules from the APK, so we're done here.
             return;
         }
@@ -489,28 +492,30 @@
     /**
      * Choose whether the current process should use the builtin or an updated driver.
      */
-    private static void chooseDriver(Context context, Bundle coreSettings) {
+    private static boolean chooseDriver(
+            Context context, Bundle coreSettings, PackageManager pm, String packageName) {
         final String driverPackageName = SystemProperties.get(PROPERTY_GFX_DRIVER);
         if (driverPackageName == null || driverPackageName.isEmpty()) {
-            return;
+            return false;
         }
 
-        final ApplicationInfo driverInfo;
+        final PackageInfo driverPackageInfo;
         try {
-            driverInfo = context.getPackageManager().getApplicationInfo(driverPackageName,
-                    PackageManager.MATCH_SYSTEM_ONLY);
+            driverPackageInfo =
+                    pm.getPackageInfo(driverPackageName, PackageManager.MATCH_SYSTEM_ONLY);
         } catch (PackageManager.NameNotFoundException e) {
             Log.w(TAG, "driver package '" + driverPackageName + "' not installed");
-            return;
+            return false;
         }
 
         // O drivers are restricted to the sphal linker namespace, so don't try to use
         // packages unless they declare they're compatible with that restriction.
-        if (driverInfo.targetSdkVersion < Build.VERSION_CODES.O) {
+        final ApplicationInfo driverAppInfo = driverPackageInfo.applicationInfo;
+        if (driverAppInfo.targetSdkVersion < Build.VERSION_CODES.O) {
             if (DEBUG) {
                 Log.w(TAG, "updated driver package is not known to be compatible with O");
             }
-            return;
+            return false;
         }
 
         // To minimize risk of driver updates crippling the device beyond user repair, never use an
@@ -519,7 +524,7 @@
         final ApplicationInfo ai = context.getApplicationInfo();
         if (ai.isPrivilegedApp() || (ai.isSystemApp() && !ai.isUpdatedSystemApp())) {
             if (DEBUG) Log.v(TAG, "ignoring driver package for privileged/non-updated system app");
-            return;
+            return false;
         }
 
         // GAME_DRIVER_ALL_APPS
@@ -531,28 +536,28 @@
             if (DEBUG) {
                 Log.w(TAG, "Game Driver is turned off on this device");
             }
-            return;
+            return false;
         }
 
         if (gameDriverAllApps != 1) {
             // GAME_DRIVER_OPT_OUT_APPS has higher priority than GAME_DRIVER_OPT_IN_APPS
             if (getGlobalSettingsString(coreSettings, Settings.Global.GAME_DRIVER_OPT_OUT_APPS)
-                            .contains(ai.packageName)) {
+                            .contains(packageName)) {
                 if (DEBUG) {
-                    Log.w(TAG, ai.packageName + " opts out from Game Driver.");
+                    Log.w(TAG, packageName + " opts out from Game Driver.");
                 }
-                return;
+                return false;
             }
             final boolean isOptIn =
                     getGlobalSettingsString(coreSettings, Settings.Global.GAME_DRIVER_OPT_IN_APPS)
-                            .contains(ai.packageName);
+                            .contains(packageName);
             if (!isOptIn
                     && !getGlobalSettingsString(coreSettings, Settings.Global.GAME_DRIVER_WHITELIST)
-                        .contains(ai.packageName)) {
+                                .contains(packageName)) {
                 if (DEBUG) {
-                    Log.w(TAG, ai.packageName + " is not on the whitelist.");
+                    Log.w(TAG, packageName + " is not on the whitelist.");
                 }
-                return;
+                return false;
             }
 
             if (!isOptIn) {
@@ -566,12 +571,12 @@
                         final Blacklists blacklistsProto =
                                 Blacklists.parseFrom(Base64.decode(base64String, BASE64_FLAGS));
                         final List<Blacklist> blacklists = blacklistsProto.getBlacklistsList();
-                        final long driverVersionCode = driverInfo.longVersionCode;
+                        final long driverVersionCode = driverAppInfo.longVersionCode;
                         for (Blacklist blacklist : blacklists) {
                             if (blacklist.getVersionCode() == driverVersionCode) {
-                                for (String packageName : blacklist.getPackageNamesList()) {
-                                    if (packageName == ai.packageName) {
-                                        return;
+                                for (String pkgName : blacklist.getPackageNamesList()) {
+                                    if (pkgName == packageName) {
+                                        return false;
                                     }
                                 }
                                 break;
@@ -586,27 +591,32 @@
             }
         }
 
-        final String abi = chooseAbi(driverInfo);
+        final String abi = chooseAbi(driverAppInfo);
         if (abi == null) {
             if (DEBUG) {
                 // This is the normal case for the pre-installed empty driver package, don't spam
-                if (driverInfo.isUpdatedSystemApp()) {
+                if (driverAppInfo.isUpdatedSystemApp()) {
                     Log.w(TAG, "updated driver package has no compatible native libraries");
                 }
             }
-            return;
+            return false;
         }
 
+        setGpuStats(driverPackageName, driverPackageInfo.versionName, driverAppInfo.longVersionCode,
+                packageName);
+
         final StringBuilder sb = new StringBuilder();
-        sb.append(driverInfo.nativeLibraryDir)
+        sb.append(driverAppInfo.nativeLibraryDir)
           .append(File.pathSeparator);
-        sb.append(driverInfo.sourceDir)
+        sb.append(driverAppInfo.sourceDir)
           .append("!/lib/")
           .append(abi);
         final String paths = sb.toString();
 
         if (DEBUG) Log.v(TAG, "gfx driver package libs: " + paths);
         setDriverPath(paths);
+
+        return true;
     }
 
     /**
@@ -646,7 +656,8 @@
     private static native void setDebugLayers(String layers);
     private static native void setDebugLayersGLES(String layers);
     private static native void setDriverPath(String path);
-    private static native void setAngleInfo(String path, String appPackage,
-                                            String devOptIn, FileDescriptor rulesFd,
-                                            long rulesOffset, long rulesLength);
+    private static native void setGpuStats(String driverPackageName, String driverVersionName,
+            long driverVersionCode, String appPackageName);
+    private static native void setAngleInfo(String path, String appPackage, String devOptIn,
+            FileDescriptor rulesFd, long rulesOffset, long rulesLength);
 }
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index 093897a..bdef575 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -42,7 +42,7 @@
     boolean isWakeLockLevelSupported(int level);
 
     void userActivity(long time, int event, int flags);
-    void wakeUp(long time, String reason, String opPackageName);
+    void wakeUp(long time, int reason, String details, String opPackageName);
     void goToSleep(long time, int reason, int flags);
     void nap(long time);
     boolean isInteractive();
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index be673ad..2ecf9d1 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -435,6 +435,106 @@
     public static final int GO_TO_SLEEP_FLAG_NO_DOZE = 1 << 0;
 
     /**
+     * @hide
+     */
+    @IntDef(prefix = { "WAKE_REASON_" }, value = {
+            WAKE_REASON_UNKNOWN,
+            WAKE_REASON_POWER_BUTTON,
+            WAKE_REASON_APPLICATION,
+            WAKE_REASON_PLUGGED_IN,
+            WAKE_REASON_GESTURE,
+            WAKE_REASON_CAMERA_LAUNCH,
+            WAKE_REASON_WAKE_KEY,
+            WAKE_REASON_WAKE_MOTION,
+            WAKE_REASON_HDMI,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface WakeReason{}
+
+    /**
+     * Wake up reason code: Waking for an unknown reason.
+     * @hide
+     */
+    public static final int WAKE_REASON_UNKNOWN = 0;
+
+    /**
+     * Wake up reason code: Waking up due to power button press.
+     * @hide
+     */
+    public static final int WAKE_REASON_POWER_BUTTON = 1;
+
+    /**
+     * Wake up reason code: Waking up because an application requested it.
+     * @hide
+     */
+    public static final int WAKE_REASON_APPLICATION = 2;
+
+    /**
+     * Wake up reason code: Waking up due to being plugged in or docked on a wireless charger.
+     * @hide
+     */
+    public static final int WAKE_REASON_PLUGGED_IN = 3;
+
+    /**
+     * Wake up reason code: Waking up due to a user performed gesture (e.g. douple tapping on the
+     * screen).
+     * @hide
+     */
+    public static final int WAKE_REASON_GESTURE = 4;
+
+    /**
+     * Wake up reason code: Waking up due to the camera being launched.
+     * @hide
+     */
+    public static final int WAKE_REASON_CAMERA_LAUNCH = 5;
+
+    /**
+     * Wake up reason code: Waking up because a wake key other than power was pressed.
+     * @hide
+     */
+    public static final int WAKE_REASON_WAKE_KEY = 6;
+
+    /**
+     * Wake up reason code: Waking up because a wake motion was performed.
+     *
+     * For example, a trackball that was set to wake the device up was spun.
+     * @hide
+     */
+    public static final int WAKE_REASON_WAKE_MOTION = 7;
+
+    /**
+     * Wake up reason code: Waking due to HDMI.
+     * @hide
+     */
+    public static final int WAKE_REASON_HDMI = 8;
+
+    /**
+     * Wake up reason code: Waking due to the lid being opened.
+     * @hide
+     */
+    public static final int WAKE_REASON_LID = 9;
+
+    /**
+     * Convert the wake reason to a string for debugging purposes.
+     * @hide
+     */
+    public static String wakeReasonToString(@WakeReason int wakeReason) {
+        switch (wakeReason) {
+            case WAKE_REASON_UNKNOWN: return "WAKE_REASON_UNKNOWN";
+            case WAKE_REASON_POWER_BUTTON: return "WAKE_REASON_POWER_BUTTON";
+            case WAKE_REASON_APPLICATION: return "WAKE_REASON_APPLICATION";
+            case WAKE_REASON_PLUGGED_IN: return "WAKE_REASON_PLUGGED_IN";
+            case WAKE_REASON_GESTURE: return "WAKE_REASON_GESTURE";
+            case WAKE_REASON_CAMERA_LAUNCH: return "WAKE_REASON_CAMERA_LAUNCH";
+            case WAKE_REASON_WAKE_KEY: return "WAKE_REASON_WAKE_KEY";
+            case WAKE_REASON_WAKE_MOTION: return "WAKE_REASON_WAKE_MOTION";
+            case WAKE_REASON_HDMI: return "WAKE_REASON_HDMI";
+            case WAKE_REASON_LID: return "WAKE_REASON_LID";
+            default: return Integer.toString(wakeReason);
+        }
+    }
+
+    /**
      * The value to pass as the 'reason' argument to reboot() to reboot into
      * recovery mode for tasks other than applying system updates, such as
      * doing factory resets.
@@ -975,22 +1075,68 @@
      * @see #userActivity
      * @see #goToSleep
      *
+     * @deprecated Use {@link #wakeUp(long, int, String)} instead.
      * @removed Requires signature permission.
      */
+    @Deprecated
     public void wakeUp(long time) {
-        try {
-            mService.wakeUp(time, "wakeUp", mContext.getOpPackageName());
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
+        wakeUp(time, WAKE_REASON_UNKNOWN, "wakeUp");
     }
 
     /**
+     * Forces the device to wake up from sleep.
+     * <p>
+     * If the device is currently asleep, wakes it up, otherwise does nothing.
+     * This is what happens when the power key is pressed to turn on the screen.
+     * </p><p>
+     * Requires the {@link android.Manifest.permission#DEVICE_POWER} permission.
+     * </p>
+     *
+     * @param time The time when the request to wake up was issued, in the
+     * {@link SystemClock#uptimeMillis()} time base.  This timestamp is used to correctly
+     * order the wake up request with other power management functions.  It should be set
+     * to the timestamp of the input event that caused the request to wake up.
+     *
+     * @param details A free form string to explain the specific details behind the wake up for
+     *                debugging purposes.
+     *
+     * @see #userActivity
+     * @see #goToSleep
+     *
+     * @deprecated Use {@link #wakeUp(long, int, String)} instead.
      * @hide
      */
-    public void wakeUp(long time, String reason) {
+    @Deprecated
+    public void wakeUp(long time, String details) {
+        wakeUp(time, WAKE_REASON_UNKNOWN, details);
+    }
+
+    /**
+     * Forces the device to wake up from sleep.
+     * <p>
+     * If the device is currently asleep, wakes it up, otherwise does nothing.
+     * This is what happens when the power key is pressed to turn on the screen.
+     * </p><p>
+     * Requires the {@link android.Manifest.permission#DEVICE_POWER} permission.
+     * </p>
+     *
+     * @param time The time when the request to wake up was issued, in the
+     * {@link SystemClock#uptimeMillis()} time base.  This timestamp is used to correctly
+     * order the wake up request with other power management functions.  It should be set
+     * to the timestamp of the input event that caused the request to wake up.
+     *
+     * @param reason The reason for the wake up.
+     *
+     * @param details A free form string to explain the specific details behind the wake up for
+     *                debugging purposes.
+     *
+     * @see #userActivity
+     * @see #goToSleep
+     * @hide
+     */
+    public void wakeUp(long time, @WakeReason int reason, String details) {
         try {
-            mService.wakeUp(time, reason, mContext.getOpPackageName());
+            mService.wakeUp(time, reason, details, mContext.getOpPackageName());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index d2ab053..9e97e37 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -526,11 +526,12 @@
                                   @Nullable String packageName,
                                   @Nullable String[] packagesForUid,
                                   @Nullable String[] visibleVols,
+                                  @Nullable String sandboxId,
                                   @Nullable String[] zygoteArgs) {
         return ZYGOTE_PROCESS.start(processClass, niceName, uid, gid, gids,
                     runtimeFlags, mountExternal, targetSdkVersion, seInfo,
                     abi, instructionSet, appDataDir, invokeWith, packageName,
-                    packagesForUid, visibleVols, /*useBlastulaPool=*/ true, zygoteArgs);
+                    packagesForUid, visibleVols, sandboxId, /*useBlastulaPool=*/ true, zygoteArgs);
     }
 
     /** @hide */
@@ -547,11 +548,12 @@
                                   @Nullable String packageName,
                                   @Nullable String[] packagesForUid,
                                   @Nullable String[] visibleVols,
+                                  @Nullable String sandboxId,
                                   @Nullable String[] zygoteArgs) {
         return WebViewZygote.getProcess().start(processClass, niceName, uid, gid, gids,
                     runtimeFlags, mountExternal, targetSdkVersion, seInfo,
                     abi, instructionSet, appDataDir, invokeWith, packageName,
-                    packagesForUid, visibleVols, /*useBlastulaPool=*/ false, zygoteArgs);
+                    packagesForUid, visibleVols, sandboxId, /*useBlastulaPool=*/ false, zygoteArgs);
     }
 
     /**
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 0a60764..e2b5730 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -734,10 +734,13 @@
     public static final String DISALLOW_SYSTEM_ERROR_DIALOGS = "no_system_error_dialogs";
 
     /**
-     * Specifies if what is copied in the clipboard of this profile can
-     * be pasted in related profiles. Does not restrict if the clipboard of related profiles can be
-     * pasted in this profile.
-     * The default value is <code>false</code>.
+     * Specifies if the clipboard contents can be exported by pasting the data into other users or
+     * profiles. This restriction doesn't prevent import, such as someone pasting clipboard data
+     * from other profiles or users. The default value is {@code false}.
+     *
+     * <p><strong>Note</strong>: Because it's possible to extract data from screenshots using
+     * optical character recognition (OCR), we strongly recommend combining this user restriction
+     * with {@link DevicePolicyManager#setScreenCaptureDisabled(ComponentName, boolean)}.
      *
      * <p>Key for user restrictions.
      * <p>Type: Boolean
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index e94ad2b..ee3d354 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -324,13 +324,15 @@
                                                   @Nullable String packageName,
                                                   @Nullable String[] packagesForUid,
                                                   @Nullable String[] visibleVols,
+                                                  @Nullable String sandboxId,
                                                   boolean useBlastulaPool,
                                                   @Nullable String[] zygoteArgs) {
         try {
             return startViaZygote(processClass, niceName, uid, gid, gids,
                     runtimeFlags, mountExternal, targetSdkVersion, seInfo,
                     abi, instructionSet, appDataDir, invokeWith, /*startChildZygote=*/false,
-                    packageName, packagesForUid, visibleVols, useBlastulaPool, zygoteArgs);
+                    packageName, packagesForUid, visibleVols, sandboxId,
+                    useBlastulaPool, zygoteArgs);
         } catch (ZygoteStartFailedEx ex) {
             Log.e(LOG_TAG,
                     "Starting VM process through Zygote failed");
@@ -541,6 +543,7 @@
                                                       @Nullable String packageName,
                                                       @Nullable String[] packagesForUid,
                                                       @Nullable String[] visibleVols,
+                                                      @Nullable String sandboxId,
                                                       boolean useBlastulaPool,
                                                       @Nullable String[] extraArgs)
                                                       throws ZygoteStartFailedEx {
@@ -639,6 +642,10 @@
             argsForZygote.add(sb.toString());
         }
 
+        if (sandboxId != null) {
+            argsForZygote.add("--sandbox-id=" + sandboxId);
+        }
+
         argsForZygote.add(processClass);
 
         if (extraArgs != null) {
@@ -1014,7 +1021,7 @@
                     gids, runtimeFlags, 0 /* mountExternal */, 0 /* targetSdkVersion */, seInfo,
                     abi, instructionSet, null /* appDataDir */, null /* invokeWith */,
                     true /* startChildZygote */, null /* packageName */,
-                    null /* packagesForUid */, null /* visibleVolumes */,
+                    null /* packagesForUid */, null /* visibleVolumes */, null /* sandboxId */,
                     false /* useBlastulaPool */, extraArgs);
         } catch (ZygoteStartFailedEx ex) {
             throw new RuntimeException("Starting child-zygote through Zygote failed", ex);
diff --git a/core/java/android/os/storage/StorageManagerInternal.java b/core/java/android/os/storage/StorageManagerInternal.java
index f521c68..03b2c2c 100644
--- a/core/java/android/os/storage/StorageManagerInternal.java
+++ b/core/java/android/os/storage/StorageManagerInternal.java
@@ -132,4 +132,9 @@
      * @param listener The listener that will be notified on reset events.
      */
     public abstract void addResetListener(ResetListener listener);
+
+    /**
+     * Return the sandboxId for the given package on external storage.
+     */
+    public abstract String getSandboxId(String packageName);
 }
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index de54a8aa..f63c0adb 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -772,19 +772,6 @@
          * @param callBlockReason The reason why the call is blocked.
          * @param callScreeningAppName The call screening application name which block the call.
          * @param callScreeningComponentName The call screening component name which block the call.
-         * @param callIdPackageName The package name of the
-         *      {@link android.telecom.CallScreeningService} which provided
-         *      {@link CallIdentification}.
-         * @param callIdAppName The app name of the {@link android.telecom.CallScreeningService}
-         *                      which provided {@link CallIdentification}.
-         * @param callIdName The caller name provided by the
-         *      {@link android.telecom.CallScreeningService}.
-         * @param callIdDescription The caller description provided by the
-         *      {@link android.telecom.CallScreeningService}.
-         * @param callIdDetails The caller details provided by the
-         *      {@link android.telecom.CallScreeningService}.
-         * @param callIdCallType The caller type provided by the
-         *      {@link android.telecom.CallScreeningService}.
          *
          * @result The URI of the call log entry belonging to the user that made or received this
          *        call.  This could be of the shadow provider.  Do not return it to non-system apps,
@@ -803,37 +790,10 @@
                         number, userToBeInsertedTo, addForAllUsers));
             }
             final ContentResolver resolver = context.getContentResolver();
-            int numberPresentation = PRESENTATION_ALLOWED;
 
-            TelecomManager tm = null;
-            try {
-                tm = TelecomManager.from(context);
-            } catch (UnsupportedOperationException e) {}
+            String accountAddress = getLogAccountAddress(context, accountHandle);
 
-            String accountAddress = null;
-            if (tm != null && accountHandle != null) {
-                PhoneAccount account = tm.getPhoneAccount(accountHandle);
-                if (account != null) {
-                    Uri address = account.getSubscriptionAddress();
-                    if (address != null) {
-                        accountAddress = address.getSchemeSpecificPart();
-                    }
-                }
-            }
-
-            // Remap network specified number presentation types
-            // PhoneConstants.PRESENTATION_xxx to calllog number presentation types
-            // Calls.PRESENTATION_xxx, in order to insulate the persistent calllog
-            // from any future radio changes.
-            // If the number field is empty set the presentation type to Unknown.
-            if (presentation == PhoneConstants.PRESENTATION_RESTRICTED) {
-                numberPresentation = PRESENTATION_RESTRICTED;
-            } else if (presentation == PhoneConstants.PRESENTATION_PAYPHONE) {
-                numberPresentation = PRESENTATION_PAYPHONE;
-            } else if (TextUtils.isEmpty(number)
-                    || presentation == PhoneConstants.PRESENTATION_UNKNOWN) {
-                numberPresentation = PRESENTATION_UNKNOWN;
-            }
+            int numberPresentation = getLogNumberPresentation(number, presentation);
             if (numberPresentation != PRESENTATION_ALLOWED) {
                 number = "";
                 if (ci != null) {
@@ -1138,8 +1098,7 @@
             if (TextUtils.isEmpty(countryIso)) {
                 return;
             }
-            final String normalizedNumber = PhoneNumberUtils.formatNumberToE164(number,
-                    getCurrentCountryIso(context));
+            final String normalizedNumber = PhoneNumberUtils.formatNumberToE164(number, countryIso);
             if (TextUtils.isEmpty(normalizedNumber)) {
                 return;
             }
@@ -1148,6 +1107,54 @@
             resolver.update(Data.CONTENT_URI, values, Data._ID + "=?", new String[] {dataId});
         }
 
+        /**
+         * Remap network specified number presentation types
+         * PhoneConstants.PRESENTATION_xxx to calllog number presentation types
+         * Calls.PRESENTATION_xxx, in order to insulate the persistent calllog
+         * from any future radio changes.
+         * If the number field is empty set the presentation type to Unknown.
+         */
+        private static int getLogNumberPresentation(String number, int presentation) {
+            if (presentation == PhoneConstants.PRESENTATION_RESTRICTED) {
+                return presentation;
+            }
+
+            if (presentation == PhoneConstants.PRESENTATION_PAYPHONE) {
+                return presentation;
+            }
+
+            if (TextUtils.isEmpty(number)
+                    || presentation == PhoneConstants.PRESENTATION_UNKNOWN) {
+                return PRESENTATION_UNKNOWN;
+            }
+
+            return PRESENTATION_ALLOWED;
+        }
+
+        private static String getLogAccountAddress(Context context,
+                PhoneAccountHandle accountHandle) {
+            TelecomManager tm = null;
+            try {
+                tm = TelecomManager.from(context);
+            } catch (UnsupportedOperationException e) {
+                if (VERBOSE_LOG) {
+                    Log.v(LOG_TAG, "No TelecomManager found to get account address.");
+                }
+            }
+
+            String accountAddress = null;
+            if (tm != null && accountHandle != null) {
+                PhoneAccount account = tm.getPhoneAccount(accountHandle);
+                if (account != null) {
+                    Uri address = account.getSubscriptionAddress();
+                    if (address != null) {
+                        accountAddress = address.getSchemeSpecificPart();
+                    }
+                }
+            }
+            return accountAddress;
+        }
+
         private static String getCurrentCountryIso(Context context) {
             String countryIso = null;
             final CountryDetector detector = (CountryDetector) context.getSystemService(
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 5ac31dc..41d3cbb 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -72,45 +72,13 @@
     public static final String NAMESPACE_AUTOFILL = "autofill";
 
     /**
-     * ContentCapture-related properties definitions.
-     *
-     * @hide
-     */
-    @SystemApi
-    public interface ContentCapture {
-        String NAMESPACE = "content_capture";
-
-        /**
-         * Property used by {@code com.android.server.SystemServer} on start to decide whether
-         * the Content Capture service should be created or not.
-         *
-         * <p>Possible values are:
-         *
-         * <ul>
-         *   <li>If set to {@code default}, it will only be set if the OEM provides and defines the
-         *   service name by overlaying {@code config_defaultContentCaptureService} (this is the
-         *   "default" mode)
-         *   <li>If set to {@code always}, it will always be enabled, even when the resource is not
-         *   overlaid (this is useful during development and to run the CTS tests on AOSP builds).
-         *   <li>Otherwise, it's explicitly disabled (this could work as a "kill switch" so OEMs
-         *   can disable it remotely in case of emergency by setting to something else (like
-         *   {@code "false"}); notice that it's also disabled if the OEM doesn't explicitly set one
-         *   of the values above).
-         * </ul>
-         *
-         * @hide
-         */
-        // TODO(b/121153631): revert back to SERVICE_EXPLICITLY_ENABLED approach
-        String PROPERTY_CONTENTCAPTURE_ENABLED = "enable_contentcapture";
-    }
-
-    /**
      * Namespace for content capture feature used by on-device machine intelligence
      * to provide suggestions in a privacy-safe manner.
      *
      * @hide
      */
     @SystemApi
+    @TestApi
     public static final String NAMESPACE_CONTENT_CAPTURE = "content_capture";
 
     /**
@@ -154,21 +122,6 @@
     }
 
     /**
-     * Namespace for all runtime related features.
-     *
-     * @hide
-     */
-    @SystemApi
-    public interface Runtime {
-        String NAMESPACE = "runtime";
-
-        /**
-         * Whether or not we use the precompiled layout.
-         */
-        String USE_PRECOMPILED_LAYOUT = "view.precompiled_layout_enabled";
-    }
-
-    /**
      * Namespace for all runtime native related features.
      *
      * @hide
@@ -375,6 +328,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     @RequiresPermission(READ_DEVICE_CONFIG)
     public static String getProperty(String namespace, String name) {
         ContentResolver contentResolver = ActivityThread.currentApplication().getContentResolver();
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 67c8400..0b38420 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -157,10 +157,6 @@
     public static final String PARAM_DELETE_DATA = "deletedata";
 
     /** {@hide} */
-    public static final String PARAM_PRIMARY = "primary";
-    /** {@hide} */
-    public static final String PARAM_SECONDARY = "secondary";
-    /** {@hide} */
     public static final String PARAM_INCLUDE_PENDING = "includePending";
     /** {@hide} */
     public static final String PARAM_INCLUDE_TRASHED = "includeTrashed";
@@ -543,7 +539,9 @@
      * @see MediaStore#setIncludeTrashed(Uri)
      * @see MediaStore#trash(Context, Uri)
      * @see MediaStore#untrash(Context, Uri)
+     * @removed
      */
+    @Deprecated
     public static @NonNull Uri setIncludeTrashed(@NonNull Uri uri) {
         return uri.buildUpon().appendQueryParameter(PARAM_INCLUDE_TRASHED, "1").build();
     }
@@ -580,14 +578,7 @@
      */
     public static @NonNull Uri createPending(@NonNull Context context,
             @NonNull PendingParams params) {
-        final Uri.Builder builder = params.insertUri.buildUpon();
-        if (!TextUtils.isEmpty(params.primaryDirectory)) {
-            builder.appendQueryParameter(PARAM_PRIMARY, params.primaryDirectory);
-        }
-        if (!TextUtils.isEmpty(params.secondaryDirectory)) {
-            builder.appendQueryParameter(PARAM_SECONDARY, params.secondaryDirectory);
-        }
-        return context.getContentResolver().insert(builder.build(), params.insertValues);
+        return context.getContentResolver().insert(params.insertUri, params.insertValues);
     }
 
     /**
@@ -610,10 +601,6 @@
         public final Uri insertUri;
         /** {@hide} */
         public final ContentValues insertValues;
-        /** {@hide} */
-        public String primaryDirectory;
-        /** {@hide} */
-        public String secondaryDirectory;
 
         /**
          * Create parameters that describe a pending media item.
@@ -655,7 +642,11 @@
          * @see MediaColumns#PRIMARY_DIRECTORY
          */
         public void setPrimaryDirectory(@Nullable String primaryDirectory) {
-            this.primaryDirectory = primaryDirectory;
+            if (primaryDirectory == null) {
+                this.insertValues.remove(MediaColumns.PRIMARY_DIRECTORY);
+            } else {
+                this.insertValues.put(MediaColumns.PRIMARY_DIRECTORY, primaryDirectory);
+            }
         }
 
         /**
@@ -668,7 +659,11 @@
          * @see MediaColumns#SECONDARY_DIRECTORY
          */
         public void setSecondaryDirectory(@Nullable String secondaryDirectory) {
-            this.secondaryDirectory = secondaryDirectory;
+            if (secondaryDirectory == null) {
+                this.insertValues.remove(MediaColumns.SECONDARY_DIRECTORY);
+            } else {
+                this.insertValues.put(MediaColumns.SECONDARY_DIRECTORY, secondaryDirectory);
+            }
         }
 
         /**
@@ -797,7 +792,9 @@
      * @see MediaStore#setIncludeTrashed(Uri)
      * @see MediaStore#trash(Context, Uri)
      * @see MediaStore#untrash(Context, Uri)
+     * @removed
      */
+    @Deprecated
     public static void trash(@NonNull Context context, @NonNull Uri uri) {
         trash(context, uri, 48 * DateUtils.HOUR_IN_MILLIS);
     }
@@ -815,7 +812,9 @@
      * @see MediaStore#setIncludeTrashed(Uri)
      * @see MediaStore#trash(Context, Uri)
      * @see MediaStore#untrash(Context, Uri)
+     * @removed
      */
+    @Deprecated
     public static void trash(@NonNull Context context, @NonNull Uri uri,
             @DurationMillisLong long timeoutMillis) {
         if (timeoutMillis < 0) {
@@ -837,7 +836,9 @@
      * @see MediaStore#setIncludeTrashed(Uri)
      * @see MediaStore#trash(Context, Uri)
      * @see MediaStore#untrash(Context, Uri)
+     * @removed
      */
+    @Deprecated
     public static void untrash(@NonNull Context context, @NonNull Uri uri) {
         final ContentValues values = new ContentValues();
         values.put(MediaColumns.IS_TRASHED, 0);
@@ -884,7 +885,9 @@
          * hash is calculated.
          * <p>
          * Type: BLOB
+         * @removed
          */
+        @Deprecated
         public static final String HASH = "_hash";
 
         /**
@@ -921,8 +924,22 @@
         public static final String DATE_MODIFIED = "date_modified";
 
         /**
-         * The MIME type of the file
-         * <P>Type: TEXT</P>
+         * The MIME type of the media item.
+         * <p>
+         * This is typically defined based on the file extension of the media
+         * item. However, it may be the value of the {@code format} attribute
+         * defined by the <em>Dublin Core Media Initiative</em> standard,
+         * extracted from any XMP metadata contained within this media item.
+         * <p class="note">
+         * Note: the {@code format} attribute may be ignored if the top-level
+         * MIME type disagrees with the file extension. For example, it's
+         * reasonable for an {@code image/jpeg} file to declare a {@code format}
+         * of {@code image/vnd.google.panorama360+jpg}, but declaring a
+         * {@code format} of {@code audio/ogg} would be ignored.
+         * <p>
+         * This is a read-only column that is automatically computed.
+         * <p>
+         * Type: TEXT
          */
         public static final String MIME_TYPE = "mime_type";
 
@@ -965,7 +982,9 @@
          * @see MediaStore#setIncludeTrashed(Uri)
          * @see MediaStore#trash(Context, Uri)
          * @see MediaStore#untrash(Context, Uri)
+         * @removed
          */
+        @Deprecated
         public static final String IS_TRASHED = "is_trashed";
 
         /**
@@ -974,7 +993,9 @@
          * {@link #IS_PENDING} or {@link #IS_TRASHED}.
          * <p>
          * Type: INTEGER
+         * @removed
          */
+        @Deprecated
         public static final String DATE_EXPIRES = "date_expires";
 
         /**
@@ -991,6 +1012,8 @@
          * Package name that contributed this media. The value may be
          * {@code NULL} if ownership cannot be reliably determined.
          * <p>
+         * This is a read-only column that is automatically computed.
+         * <p>
          * Type: TEXT
          */
         public static final String OWNER_PACKAGE_NAME = "owner_package_name";
@@ -1014,6 +1037,52 @@
          * @see PendingParams#setSecondaryDirectory(String)
          */
         public static final String SECONDARY_DIRECTORY = "secondary_directory";
+
+        /**
+         * The "document ID" GUID as defined by the <em>XMP Media
+         * Management</em> standard, extracted from any XMP metadata contained
+         * within this media item. The value is {@code null} when no metadata
+         * was found.
+         * <p>
+         * Each "document ID" is created once for each new resource. Different
+         * renditions of that resource are expected to have different IDs.
+         * <p>
+         * This is a read-only column that is automatically computed.
+         * <p>
+         * Type: TEXT
+         */
+        public static final String DOCUMENT_ID = "document_id";
+
+        /**
+         * The "instance ID" GUID as defined by the <em>XMP Media
+         * Management</em> standard, extracted from any XMP metadata contained
+         * within this media item. The value is {@code null} when no metadata
+         * was found.
+         * <p>
+         * This "instance ID" changes with each save operation of a specific
+         * "document ID".
+         * <p>
+         * This is a read-only column that is automatically computed.
+         * <p>
+         * Type: TEXT
+         */
+        public static final String INSTANCE_ID = "instance_id";
+
+        /**
+         * The "original document ID" GUID as defined by the <em>XMP Media
+         * Management</em> standard, extracted from any XMP metadata contained
+         * within this media item.
+         * <p>
+         * This "original document ID" links a resource to its original source.
+         * For example, when you save a PSD document as a JPEG, then convert the
+         * JPEG to GIF format, the "original document ID" of both the JPEG and
+         * GIF files is the "document ID" of the original PSD file.
+         * <p>
+         * This is a read-only column that is automatically computed.
+         * <p>
+         * Type: TEXT
+         */
+        public static final String ORIGINAL_DOCUMENT_ID = "original_document_id";
     }
 
     /**
@@ -3097,20 +3166,29 @@
 
         final ArrayList<File> res = new ArrayList<>();
         if (VOLUME_INTERNAL.equals(volumeName)) {
-            res.add(new File(Environment.getRootDirectory(), "media"));
-            res.add(new File(Environment.getOemDirectory(), "media"));
-            res.add(new File(Environment.getProductDirectory(), "media"));
+            addCanoncialFile(res, new File(Environment.getRootDirectory(), "media"));
+            addCanoncialFile(res, new File(Environment.getOemDirectory(), "media"));
+            addCanoncialFile(res, new File(Environment.getProductDirectory(), "media"));
         } else {
-            res.add(getVolumePath(volumeName));
+            addCanoncialFile(res, getVolumePath(volumeName));
             final UserManager um = AppGlobals.getInitialApplication()
                     .getSystemService(UserManager.class);
             if (VOLUME_EXTERNAL.equals(volumeName) && um.isDemoUser()) {
-                res.add(Environment.getDataPreloadsMediaDirectory());
+                addCanoncialFile(res, Environment.getDataPreloadsMediaDirectory());
             }
         }
         return res;
     }
 
+    private static void addCanoncialFile(List<File> list, File file) {
+        try {
+            list.add(file.getCanonicalFile());
+        } catch (IOException e) {
+            Log.w(TAG, "Failed to resolve " + file + ": " + e);
+            list.add(file);
+        }
+    }
+
     /**
      * Uri for querying the state of the media scanner.
      */
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 90749bb..de84e71 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -8289,11 +8289,22 @@
          * The value is boolean (1 or 0).
          * @hide
          */
+        @TestApi
         public static final String NOTIFICATION_BADGING = "notification_badging";
 
         private static final Validator NOTIFICATION_BADGING_VALIDATOR = BOOLEAN_VALIDATOR;
 
         /**
+         * Whether the notification bubbles are globally enabled
+         * The value is boolean (1 or 0).
+         * @hide
+         */
+        @TestApi
+        public static final String NOTIFICATION_BUBBLES = "notification_bubbles";
+
+        private static final Validator NOTIFICATION_BUBBLES_VALIDATOR = BOOLEAN_VALIDATOR;
+
+        /**
          * Whether notifications are dismissed by a right-to-left swipe (instead of a left-to-right
          * swipe).
          *
@@ -8604,6 +8615,7 @@
             ASSIST_GESTURE_WAKE_ENABLED,
             VR_DISPLAY_MODE,
             NOTIFICATION_BADGING,
+            NOTIFICATION_BUBBLES,
             NOTIFICATION_DISMISS_RTL,
             QS_AUTO_ADDED_TILES,
             SCREENSAVER_ENABLED,
@@ -8766,6 +8778,7 @@
             VALIDATORS.put(ASSIST_GESTURE_WAKE_ENABLED, ASSIST_GESTURE_WAKE_ENABLED_VALIDATOR);
             VALIDATORS.put(VR_DISPLAY_MODE, VR_DISPLAY_MODE_VALIDATOR);
             VALIDATORS.put(NOTIFICATION_BADGING, NOTIFICATION_BADGING_VALIDATOR);
+            VALIDATORS.put(NOTIFICATION_BUBBLES, NOTIFICATION_BUBBLES_VALIDATOR);
             VALIDATORS.put(NOTIFICATION_DISMISS_RTL, NOTIFICATION_DISMISS_RTL_VALIDATOR);
             VALIDATORS.put(QS_AUTO_ADDED_TILES, QS_AUTO_ADDED_TILES_VALIDATOR);
             VALIDATORS.put(SCREENSAVER_ENABLED, SCREENSAVER_ENABLED_VALIDATOR);
@@ -9288,6 +9301,13 @@
         public static final String DEBUG_VIEW_ATTRIBUTES = "debug_view_attributes";
 
         /**
+         * Which application package is allowed to save View attribute data.
+         * @hide
+         */
+        public static final String DEBUG_VIEW_ATTRIBUTES_APPLICATION_PACKAGE =
+                "debug_view_attributes_application_package";
+
+        /**
          * Whether assisted GPS should be enabled or not.
          * @hide
          */
@@ -14010,6 +14030,7 @@
             INSTANT_APP_SETTINGS.add(TRANSITION_ANIMATION_SCALE);
             INSTANT_APP_SETTINGS.add(ANIMATOR_DURATION_SCALE);
             INSTANT_APP_SETTINGS.add(DEBUG_VIEW_ATTRIBUTES);
+            INSTANT_APP_SETTINGS.add(DEBUG_VIEW_ATTRIBUTES_APPLICATION_PACKAGE);
             INSTANT_APP_SETTINGS.add(WTF_IS_FATAL);
             INSTANT_APP_SETTINGS.add(SEND_ACTION_APP_ERROR);
             INSTANT_APP_SETTINGS.add(ZEN_MODE);
diff --git a/core/java/android/rolecontrollerservice/IRoleControllerService.aidl b/core/java/android/rolecontrollerservice/IRoleControllerService.aidl
index 4e98201..40852ea 100644
--- a/core/java/android/rolecontrollerservice/IRoleControllerService.aidl
+++ b/core/java/android/rolecontrollerservice/IRoleControllerService.aidl
@@ -23,13 +23,13 @@
  */
 oneway interface IRoleControllerService {
 
-    void onAddRoleHolder(in String roleName, in String packageName,
+    void onAddRoleHolder(in String roleName, in String packageName, int flags,
                          in IRoleManagerCallback callback);
 
-    void onRemoveRoleHolder(in String roleName, in String packageName,
+    void onRemoveRoleHolder(in String roleName, in String packageName, int flags,
                            in IRoleManagerCallback callback);
 
-    void onClearRoleHolders(in String roleName, in IRoleManagerCallback callback);
+    void onClearRoleHolders(in String roleName, int flags, in IRoleManagerCallback callback);
 
     void onGrantDefaultRoles(in IRoleManagerCallback callback);
 
diff --git a/core/java/android/rolecontrollerservice/RoleControllerService.java b/core/java/android/rolecontrollerservice/RoleControllerService.java
index 5403cfa..c846b07 100644
--- a/core/java/android/rolecontrollerservice/RoleControllerService.java
+++ b/core/java/android/rolecontrollerservice/RoleControllerService.java
@@ -61,32 +61,33 @@
         return new IRoleControllerService.Stub() {
 
             @Override
-            public void onAddRoleHolder(String roleName, String packageName,
+            public void onAddRoleHolder(String roleName, String packageName, int flags,
                     IRoleManagerCallback callback) {
                 Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
                 Preconditions.checkStringNotEmpty(packageName,
                         "packageName cannot be null or empty");
                 Preconditions.checkNotNull(callback, "callback cannot be null");
-                RoleControllerService.this.onAddRoleHolder(roleName, packageName,
+                RoleControllerService.this.onAddRoleHolder(roleName, packageName, flags,
                         new RoleManagerCallbackDelegate(callback));
             }
 
             @Override
-            public void onRemoveRoleHolder(String roleName, String packageName,
+            public void onRemoveRoleHolder(String roleName, String packageName, int flags,
                     IRoleManagerCallback callback) {
                 Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
                 Preconditions.checkStringNotEmpty(packageName,
                         "packageName cannot be null or empty");
                 Preconditions.checkNotNull(callback, "callback cannot be null");
-                RoleControllerService.this.onRemoveRoleHolder(roleName, packageName,
+                RoleControllerService.this.onRemoveRoleHolder(roleName, packageName, flags,
                         new RoleManagerCallbackDelegate(callback));
             }
 
             @Override
-            public void onClearRoleHolders(String roleName, IRoleManagerCallback callback) {
+            public void onClearRoleHolders(String roleName, int flags,
+                    IRoleManagerCallback callback) {
                 Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
                 Preconditions.checkNotNull(callback, "callback cannot be null");
-                RoleControllerService.this.onClearRoleHolders(roleName,
+                RoleControllerService.this.onClearRoleHolders(roleName, flags,
                         new RoleManagerCallbackDelegate(callback));
             }
 
@@ -113,37 +114,41 @@
      *
      * @param roleName the name of the role to add the role holder for
      * @param packageName the package name of the application to add to the role holders
+     * @param flags optional behavior flags
      * @param callback the callback for whether this call is successful
      *
-     * @see RoleManager#addRoleHolderAsUser(String, String, UserHandle, Executor,
+     * @see RoleManager#addRoleHolderAsUser(String, String, int, UserHandle, Executor,
      *      RoleManagerCallback)
      */
     public abstract void onAddRoleHolder(@NonNull String roleName, @NonNull String packageName,
-            @NonNull RoleManagerCallback callback);
+            @RoleManager.ManageHoldersFlags int flags, @NonNull RoleManagerCallback callback);
 
     /**
      * Remove a specific application from the holders of a role.
      *
      * @param roleName the name of the role to remove the role holder for
      * @param packageName the package name of the application to remove from the role holders
+     * @param flags optional behavior flags
      * @param callback the callback for whether this call is successful
      *
-     * @see RoleManager#removeRoleHolderAsUser(String, String, UserHandle, Executor,
+     * @see RoleManager#removeRoleHolderAsUser(String, String, int, UserHandle, Executor,
      *      RoleManagerCallback)
      */
     public abstract void onRemoveRoleHolder(@NonNull String roleName, @NonNull String packageName,
-            @NonNull RoleManagerCallback callback);
+            @RoleManager.ManageHoldersFlags int flags, @NonNull RoleManagerCallback callback);
 
     /**
      * Remove all holders of a role.
      *
      * @param roleName the name of the role to remove role holders for
+     * @param flags optional behavior flags
      * @param callback the callback for whether this call is successful
      *
-     * @see RoleManager#clearRoleHoldersAsUser(String, UserHandle, Executor, RoleManagerCallback)
+     * @see RoleManager#clearRoleHoldersAsUser(String, int, UserHandle, Executor,
+     *      RoleManagerCallback)
      */
     public abstract void onClearRoleHolders(@NonNull String roleName,
-            @NonNull RoleManagerCallback callback);
+            @RoleManager.ManageHoldersFlags int flags, @NonNull RoleManagerCallback callback);
 
     /**
      * Cleanup appop/permissions state in response to sms kill switch toggle
diff --git a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
index 8e0f522..81d066d 100644
--- a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
+++ b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
@@ -234,7 +234,12 @@
     }
 
     /**
-     * Implementation specific {@code dump}.
+     * Implementation specific {@code dump}. The child class can override the method to provide
+     * additional information about the Service's state into the dumpsys output.
+     *
+     * @param pw The PrintWriter to which you should dump your state.  This will be closed for
+     * you after you return.
+     * @param args additional arguments to the dump request.
      */
     protected void dump(@NonNull PrintWriter pw,
             @SuppressWarnings("unused") @NonNull String[] args) {
diff --git a/core/java/android/app/SmsAppService.java b/core/java/android/service/carrier/CarrierMessagingClientService.java
similarity index 67%
rename from core/java/android/app/SmsAppService.java
rename to core/java/android/service/carrier/CarrierMessagingClientService.java
index 3829d71..13f4fc4 100644
--- a/core/java/android/app/SmsAppService.java
+++ b/core/java/android/service/carrier/CarrierMessagingClientService.java
@@ -13,8 +13,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.app;
+package android.service.carrier;
 
+import android.app.Service;
 import android.content.ComponentName;
 import android.content.Intent;
 import android.os.IBinder;
@@ -24,10 +25,11 @@
  * it so that the process is always running, which allows the app to have a persistent connection
  * to the server.
  *
- * <p>The service must have an {@link android.telephony.TelephonyManager#ACTION_SMS_APP_SERVICE}
+ * <p>The service must have an
+ * {@link android.telephony.TelephonyManager#ACTION_CARRIER_MESSAGING_CLIENT_SERVICE}
  * action in the intent handler, and be protected with
- * {@link android.Manifest.permission#BIND_SMS_APP_SERVICE}. However the service does not have to
- * be exported.
+ * {@link android.Manifest.permission#BIND_CARRIER_MESSAGING_CLIENT_SERVICE}.
+ * However the service does not have to be exported.
  *
  * <p>The service must be associated with a non-main process, meaning it must have an
  * {@code android:process} tag in its manifest entry.
@@ -45,27 +47,27 @@
  *
  * <p>Example: First, define a subclass in the application:
  * <pre>
- * public class MySmsAppService extends SmsAppService {
+ * public class MyCarrierMessagingClientService extends CarrierMessagingClientService {
  * }
  * </pre>
  * Then, declare it in its {@code AndroidManifest.xml}:
  * <pre>
  * &lt;service
- *    android:name=".MySmsAppService"
+ *    android:name=".MyCarrierMessagingClientService"
  *    android:exported="false"
  *    android:process=":persistent"
- *    android:permission="android.permission.BIND_SMS_APP_SERVICE"&gt;
+ *    android:permission="android.permission.BIND_CARRIER_MESSAGING_CLIENT_SERVICE"&gt;
  *    &lt;intent-filter&gt;
- *        &lt;action android:name="android.telephony.action.SMS_APP_SERVICE" /&gt;
+ *        &lt;action android:name="android.telephony.action.CARRIER_MESSAGING_CLIENT_SERVICE" /&gt;
  *    &lt;/intent-filter&gt;
  * &lt;/service&gt;
  * </pre>
  */
-public class SmsAppService extends Service {
-    private final ISmsAppService mImpl;
+public class CarrierMessagingClientService extends Service {
+    private final ICarrierMessagingClientServiceImpl mImpl;
 
-    public SmsAppService() {
-        mImpl = new ISmsAppServiceImpl();
+    public CarrierMessagingClientService() {
+        mImpl = new ICarrierMessagingClientServiceImpl();
     }
 
     @Override
@@ -73,6 +75,6 @@
         return mImpl.asBinder();
     }
 
-    private class ISmsAppServiceImpl extends ISmsAppService.Stub {
+    private class ICarrierMessagingClientServiceImpl extends ICarrierMessagingClientService.Stub {
     }
 }
diff --git a/core/java/android/app/ISmsAppService.aidl b/core/java/android/service/carrier/ICarrierMessagingClientService.aidl
similarity index 88%
rename from core/java/android/app/ISmsAppService.aidl
rename to core/java/android/service/carrier/ICarrierMessagingClientService.aidl
index 1ac2ec6..dbe7d12 100644
--- a/core/java/android/app/ISmsAppService.aidl
+++ b/core/java/android/service/carrier/ICarrierMessagingClientService.aidl
@@ -14,10 +14,10 @@
  * limitations under the License.
  */
 
-package android.app;
+package android.service.carrier;
 
 /**
  * @hide
  */
-interface ISmsAppService {
+interface ICarrierMessagingClientService {
 }
diff --git a/core/java/android/service/dreams/Sandman.java b/core/java/android/service/dreams/Sandman.java
index eeb340b..efb8923 100644
--- a/core/java/android/service/dreams/Sandman.java
+++ b/core/java/android/service/dreams/Sandman.java
@@ -91,8 +91,9 @@
                     // and the UI mode manager starting a dream.  We want the system to already
                     // be awake by the time this happens.  Otherwise the dream may not start.
                     PowerManager powerManager =
-                            (PowerManager)context.getSystemService(Context.POWER_SERVICE);
+                            context.getSystemService(PowerManager.class);
                     powerManager.wakeUp(SystemClock.uptimeMillis(),
+                            PowerManager.WAKE_REASON_PLUGGED_IN,
                             "android.service.dreams:DREAM");
                 } else {
                     Slog.i(TAG, "Activating dream by user request.");
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index d4e8879..d3285bb 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -1503,6 +1503,7 @@
         private boolean mNoisy;
         private ArrayList<Notification.Action> mSmartActions;
         private ArrayList<CharSequence> mSmartReplies;
+        private boolean mCanBubble;
 
         public Ranking() {}
 
@@ -1677,6 +1678,17 @@
             return mLastAudiblyAlertedMs;
         }
 
+        /**
+         * Returns whether the user has allowed bubbles globally, at the app level, and at the
+         * channel level for this notification.
+         *
+         * <p>This does not take into account the current importance of the notification, the
+         * current DND state, or whether the posting app is foreground.</p>
+         */
+        public boolean canBubble() {
+            return mCanBubble;
+        }
+
         /** @hide */
         public boolean isNoisy() {
             return mNoisy;
@@ -1693,7 +1705,7 @@
                 ArrayList<SnoozeCriterion> snoozeCriteria, boolean showBadge,
                 int userSentiment, boolean hidden, long lastAudiblyAlertedMs,
                 boolean noisy, ArrayList<Notification.Action> smartActions,
-                ArrayList<CharSequence> smartReplies) {
+                ArrayList<CharSequence> smartReplies, boolean canBubble) {
             mKey = key;
             mRank = rank;
             mIsAmbient = importance < NotificationManager.IMPORTANCE_LOW;
@@ -1713,6 +1725,7 @@
             mNoisy = noisy;
             mSmartActions = smartActions;
             mSmartReplies = smartReplies;
+            mCanBubble = canBubble;
         }
 
         /**
@@ -1766,6 +1779,7 @@
         private ArrayMap<String, Boolean> mNoisy;
         private ArrayMap<String, ArrayList<Notification.Action>> mSmartActions;
         private ArrayMap<String, ArrayList<CharSequence>> mSmartReplies;
+        private boolean[] mCanBubble;
 
         private RankingMap(NotificationRankingUpdate rankingUpdate) {
             mRankingUpdate = rankingUpdate;
@@ -1796,7 +1810,7 @@
                     getChannel(key), getOverridePeople(key), getSnoozeCriteria(key),
                     getShowBadge(key), getUserSentiment(key), getHidden(key),
                     getLastAudiblyAlerted(key), getNoisy(key), getSmartActions(key),
-                    getSmartReplies(key));
+                    getSmartReplies(key), canBubble(key));
             return rank >= 0;
         }
 
@@ -1972,6 +1986,19 @@
             return mSmartReplies.get(key);
         }
 
+        private boolean canBubble(String key) {
+            synchronized (this) {
+                if (mRanks == null) {
+                    buildRanksLocked();
+                }
+                if (mCanBubble == null) {
+                    mCanBubble = mRankingUpdate.getCanBubble();
+                }
+            }
+            int keyIndex = mRanks.getOrDefault(key, -1);
+            return keyIndex >= 0 ? mCanBubble[keyIndex] : false;
+        }
+
         // Locked by 'this'
         private void buildRanksLocked() {
             String[] orderedKeys = mRankingUpdate.getOrderedKeys();
diff --git a/core/java/android/service/notification/NotificationRankingUpdate.java b/core/java/android/service/notification/NotificationRankingUpdate.java
index ebaeff8..230ae27 100644
--- a/core/java/android/service/notification/NotificationRankingUpdate.java
+++ b/core/java/android/service/notification/NotificationRankingUpdate.java
@@ -41,13 +41,14 @@
     private final Bundle mSmartReplies;
     private final Bundle mLastAudiblyAlerted;
     private final Bundle mNoisy;
+    private final boolean[] mCanBubble;
 
     public NotificationRankingUpdate(String[] keys, String[] interceptedKeys,
             Bundle visibilityOverrides, Bundle suppressedVisualEffects,
             int[] importance, Bundle explanation, Bundle overrideGroupKeys,
             Bundle channels, Bundle overridePeople, Bundle snoozeCriteria,
             Bundle showBadge, Bundle userSentiment, Bundle hidden, Bundle smartActions,
-            Bundle smartReplies, Bundle lastAudiblyAlerted, Bundle noisy) {
+            Bundle smartReplies, Bundle lastAudiblyAlerted, Bundle noisy, boolean[] canBubble) {
         mKeys = keys;
         mInterceptedKeys = interceptedKeys;
         mVisibilityOverrides = visibilityOverrides;
@@ -65,6 +66,7 @@
         mSmartReplies = smartReplies;
         mLastAudiblyAlerted = lastAudiblyAlerted;
         mNoisy = noisy;
+        mCanBubble = canBubble;
     }
 
     public NotificationRankingUpdate(Parcel in) {
@@ -86,6 +88,8 @@
         mSmartReplies = in.readBundle();
         mLastAudiblyAlerted = in.readBundle();
         mNoisy = in.readBundle();
+        mCanBubble = new boolean[mKeys.length];
+        in.readBooleanArray(mCanBubble);
     }
 
     @Override
@@ -112,6 +116,7 @@
         out.writeBundle(mSmartReplies);
         out.writeBundle(mLastAudiblyAlerted);
         out.writeBundle(mNoisy);
+        out.writeBooleanArray(mCanBubble);
     }
 
     public static final Parcelable.Creator<NotificationRankingUpdate> CREATOR
@@ -192,4 +197,8 @@
     public Bundle getNoisy() {
         return mNoisy;
     }
+
+    public boolean[] getCanBubble() {
+        return mCanBubble;
+    }
 }
diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java
index 949328f..915a18e 100644
--- a/core/java/android/text/TextLine.java
+++ b/core/java/android/text/TextLine.java
@@ -94,7 +94,8 @@
     private final DecorationInfo mDecorationInfo = new DecorationInfo();
     private final ArrayList<DecorationInfo> mDecorations = new ArrayList<>();
 
-    @UnsupportedAppUsage
+    /** Not allowed to access. If it's for memory leak workaround, it was already fixed M. */
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     private static final TextLine[] sCached = new TextLine[3];
 
     /**
diff --git a/core/java/android/view/AccessibilityInteractionController.java b/core/java/android/view/AccessibilityInteractionController.java
index 59e562f..62ed901 100644
--- a/core/java/android/view/AccessibilityInteractionController.java
+++ b/core/java/android/view/AccessibilityInteractionController.java
@@ -40,6 +40,7 @@
 import android.view.View.AttachInfo;
 import android.view.accessibility.AccessibilityInteractionClient;
 import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.AccessibilityNodeIdManager;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
 import android.view.accessibility.AccessibilityNodeProvider;
@@ -154,13 +155,7 @@
     }
 
     private boolean isShown(View view) {
-        // The first two checks are made also made by isShown() which
-        // however traverses the tree up to the parent to catch that.
-        // Therefore, we do some fail fast check to minimize the up
-        // tree traversal.
-        return (view.mAttachInfo != null
-                && view.mAttachInfo.mWindowVisibility == View.VISIBLE
-                && view.isShown());
+        return (view != null) && (view.getWindowVisibility() == View.VISIBLE && view.isShown());
     }
 
     public void findAccessibilityNodeInfoByAccessibilityIdClientThread(
@@ -340,13 +335,8 @@
                 return;
             }
             mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = flags;
-            View root = null;
-            if (accessibilityViewId == AccessibilityNodeInfo.ROOT_ITEM_ID) {
-                root = mViewRootImpl.mView;
-            } else {
-                root = findViewByAccessibilityId(accessibilityViewId);
-            }
-            if (root != null && isShown(root)) {
+            final View root = findViewByAccessibilityId(accessibilityViewId);
+            if (root != null) {
                 mPrefetcher.prefetchAccessibilityNodeInfos(
                         root, virtualDescendantId, flags, infos, arguments);
             }
@@ -396,12 +386,7 @@
                 return;
             }
             mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = flags;
-            View root = null;
-            if (accessibilityViewId != AccessibilityNodeInfo.ROOT_ITEM_ID) {
-                root = findViewByAccessibilityId(accessibilityViewId);
-            } else {
-                root = mViewRootImpl.mView;
-            }
+            final View root = findViewByAccessibilityId(accessibilityViewId);
             if (root != null) {
                 final int resolvedViewId = root.getContext().getResources()
                         .getIdentifier(viewId, null, null);
@@ -462,13 +447,8 @@
                 return;
             }
             mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = flags;
-            View root = null;
-            if (accessibilityViewId != AccessibilityNodeInfo.ROOT_ITEM_ID) {
-                root = findViewByAccessibilityId(accessibilityViewId);
-            } else {
-                root = mViewRootImpl.mView;
-            }
-            if (root != null && isShown(root)) {
+            final View root = findViewByAccessibilityId(accessibilityViewId);
+            if (root != null) {
                 AccessibilityNodeProvider provider = root.getAccessibilityNodeProvider();
                 if (provider != null) {
                     infos = provider.findAccessibilityNodeInfosByText(text,
@@ -550,13 +530,8 @@
                 return;
             }
             mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = flags;
-            View root = null;
-            if (accessibilityViewId != AccessibilityNodeInfo.ROOT_ITEM_ID) {
-                root = findViewByAccessibilityId(accessibilityViewId);
-            } else {
-                root = mViewRootImpl.mView;
-            }
-            if (root != null && isShown(root)) {
+            final View root = findViewByAccessibilityId(accessibilityViewId);
+            if (root != null) {
                 switch (focusType) {
                     case AccessibilityNodeInfo.FOCUS_ACCESSIBILITY: {
                         View host = mViewRootImpl.mAccessibilityFocusedHost;
@@ -583,7 +558,7 @@
                     } break;
                     case AccessibilityNodeInfo.FOCUS_INPUT: {
                         View target = root.findFocus();
-                        if (target == null || !isShown(target)) {
+                        if (!isShown(target)) {
                             break;
                         }
                         AccessibilityNodeProvider provider = target.getAccessibilityNodeProvider();
@@ -645,13 +620,8 @@
                 return;
             }
             mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = flags;
-            View root = null;
-            if (accessibilityViewId != AccessibilityNodeInfo.ROOT_ITEM_ID) {
-                root = findViewByAccessibilityId(accessibilityViewId);
-            } else {
-                root = mViewRootImpl.mView;
-            }
-            if (root != null && isShown(root)) {
+            final View root = findViewByAccessibilityId(accessibilityViewId);
+            if (root != null) {
                 View nextView = root.focusSearch(direction);
                 if (nextView != null) {
                     next = nextView.createAccessibilityNodeInfo();
@@ -705,13 +675,8 @@
                 return;
             }
             mViewRootImpl.mAttachInfo.mAccessibilityFetchFlags = flags;
-            View target = null;
-            if (accessibilityViewId != AccessibilityNodeInfo.ROOT_ITEM_ID) {
-                target = findViewByAccessibilityId(accessibilityViewId);
-            } else {
-                target = mViewRootImpl.mView;
-            }
-            if (target != null && isShown(target)) {
+            final View target = findViewByAccessibilityId(accessibilityViewId);
+            if (target != null) {
                 if (action == R.id.accessibilityActionClickOnClickableSpan) {
                     // Handle this hidden action separately
                     succeeded = handleClickableSpanActionUiThread(
@@ -791,15 +756,13 @@
     }
 
     private View findViewByAccessibilityId(int accessibilityId) {
-        View root = mViewRootImpl.mView;
-        if (root == null) {
-            return null;
+        if (accessibilityId == AccessibilityNodeInfo.ROOT_ITEM_ID) {
+            return mViewRootImpl.mView;
+        } else {
+            final View foundView =
+                    AccessibilityNodeIdManager.getInstance().findView(accessibilityId);
+            return isShown(foundView) ? foundView : null;
         }
-        View foundView = root.findViewByAccessibilityId(accessibilityId);
-        if (foundView != null && !isShown(foundView)) {
-            return null;
-        }
-        return foundView;
     }
 
     private void applyAppScaleAndMagnificationSpecIfNeeded(List<AccessibilityNodeInfo> infos,
@@ -1171,7 +1134,7 @@
                         }
                         View child = children.get(i);
                         if (child.getAccessibilityViewId() != current.getAccessibilityViewId()
-                                &&  isShown(child)) {
+                                && isShown(child)) {
                             AccessibilityNodeInfo info = null;
                             AccessibilityNodeProvider provider =
                                 child.getAccessibilityNodeProvider();
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index ccd0fc1..c64386e 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -22,7 +22,6 @@
 import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
 import android.graphics.FrameInfo;
-import android.graphics.Insets;
 import android.hardware.display.DisplayManagerGlobal;
 import android.os.Build;
 import android.os.Handler;
@@ -134,7 +133,7 @@
             };
 
     // Enable/disable vsync for animations and drawing.
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769497)
     private static final boolean USE_VSYNC = SystemProperties.getBoolean(
             "debug.choreographer.vsync", true);
 
@@ -914,25 +913,11 @@
             super(looper, vsyncSource);
         }
 
+        // TODO(b/116025192): physicalDisplayId is ignored because SF only emits VSYNC events for
+        // the internal display and DisplayEventReceiver#scheduleVsync only allows requesting VSYNC
+        // for the internal display implicitly.
         @Override
-        public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {
-            // Ignore vsync from secondary display.
-            // This can be problematic because the call to scheduleVsync() is a one-shot.
-            // We need to ensure that we will still receive the vsync from the primary
-            // display which is the one we really care about.  Ideally we should schedule
-            // vsync for a particular display.
-            // At this time Surface Flinger won't send us vsyncs for secondary displays
-            // but that could change in the future so let's log a message to help us remember
-            // that we need to fix this.
-            if (builtInDisplayId != SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN) {
-                Log.d(TAG, "Received vsync from secondary display, but we don't support "
-                        + "this case yet.  Choreographer needs a way to explicitly request "
-                        + "vsync for a specific display to ensure it doesn't lose track "
-                        + "of its scheduled vsync.");
-                scheduleVsync();
-                return;
-            }
-
+        public void onVsync(long timestampNanos, long physicalDisplayId, int frame) {
             // Post the vsync event to the Handler.
             // The idea is to prevent incoming vsync events from completely starving
             // the message queue.  If there are no messages in the queue with timestamps
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index e3a6bd7..49bae28 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -32,6 +32,7 @@
 import android.graphics.Rect;
 import android.hardware.display.DisplayManager;
 import android.hardware.display.DisplayManagerGlobal;
+import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.Process;
@@ -495,7 +496,7 @@
      * @return True if the display is still valid.
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public boolean getDisplayInfo(DisplayInfo outDisplayInfo) {
         synchronized (this) {
             updateDisplayInfoLocked();
diff --git a/core/java/android/view/DisplayEventReceiver.java b/core/java/android/view/DisplayEventReceiver.java
index edd3f1a..3e8002f 100644
--- a/core/java/android/view/DisplayEventReceiver.java
+++ b/core/java/android/view/DisplayEventReceiver.java
@@ -136,12 +136,11 @@
      *
      * @param timestampNanos The timestamp of the pulse, in the {@link System#nanoTime()}
      * timebase.
-     * @param builtInDisplayId The surface flinger built-in display id such as
-     * {@link SurfaceControl#BUILT_IN_DISPLAY_ID_MAIN}.
+     * @param physicalDisplayId Stable display ID that uniquely describes a (display, port) pair.
      * @param frame The frame number.  Increases by one for each vertical sync interval.
      */
     @UnsupportedAppUsage
-    public void onVsync(long timestampNanos, int builtInDisplayId, int frame) {
+    public void onVsync(long timestampNanos, long physicalDisplayId, int frame) {
     }
 
     /**
@@ -149,12 +148,11 @@
      *
      * @param timestampNanos The timestamp of the event, in the {@link System#nanoTime()}
      * timebase.
-     * @param builtInDisplayId The surface flinger built-in display id such as
-     * {@link SurfaceControl#BUILT_IN_DISPLAY_ID_HDMI}.
+     * @param physicalDisplayId Stable display ID that uniquely describes a (display, port) pair.
      * @param connected True if the display is connected, false if it disconnected.
      */
     @UnsupportedAppUsage
-    public void onHotplug(long timestampNanos, int builtInDisplayId, boolean connected) {
+    public void onHotplug(long timestampNanos, long physicalDisplayId, boolean connected) {
     }
 
     /**
@@ -174,14 +172,14 @@
     // Called from native code.
     @SuppressWarnings("unused")
     @UnsupportedAppUsage
-    private void dispatchVsync(long timestampNanos, int builtInDisplayId, int frame) {
-        onVsync(timestampNanos, builtInDisplayId, frame);
+    private void dispatchVsync(long timestampNanos, long physicalDisplayId, int frame) {
+        onVsync(timestampNanos, physicalDisplayId, frame);
     }
 
     // Called from native code.
     @SuppressWarnings("unused")
     @UnsupportedAppUsage
-    private void dispatchHotplug(long timestampNanos, int builtInDisplayId, boolean connected) {
-        onHotplug(timestampNanos, builtInDisplayId, connected);
+    private void dispatchHotplug(long timestampNanos, long physicalDisplayId, boolean connected) {
+        onHotplug(timestampNanos, physicalDisplayId, connected);
     }
 }
diff --git a/core/java/android/view/DisplayInfo.java b/core/java/android/view/DisplayInfo.java
index 43de1f8..ad8fee9 100644
--- a/core/java/android/view/DisplayInfo.java
+++ b/core/java/android/view/DisplayInfo.java
@@ -27,6 +27,7 @@
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
 import android.graphics.Rect;
+import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.ArraySet;
@@ -157,8 +158,9 @@
      *
      * @hide
      */
+    // Remark on @UnsupportedAppUsage: Display.getCutout should be used instead
     @Nullable
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public DisplayCutout displayCutout;
 
     /**
@@ -281,7 +283,7 @@
         }
     };
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769467)
     public DisplayInfo() {
     }
 
diff --git a/core/java/android/view/DisplayListCanvas.java b/core/java/android/view/DisplayListCanvas.java
index 03d9955..3e749f4 100644
--- a/core/java/android/view/DisplayListCanvas.java
+++ b/core/java/android/view/DisplayListCanvas.java
@@ -37,7 +37,7 @@
     }
 
     /** @hide */
-    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.O)
     public abstract void drawRoundRect(CanvasProperty<Float> left, CanvasProperty<Float> top,
             CanvasProperty<Float> right, CanvasProperty<Float> bottom, CanvasProperty<Float> rx,
             CanvasProperty<Float> ry, CanvasProperty<Paint> paint);
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 8ae4757..2ef7c4b 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -25,6 +25,7 @@
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
 import android.graphics.GraphicBuffer;
+import android.graphics.Insets;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.Region;
@@ -380,6 +381,16 @@
     void getStableInsets(int displayId, out Rect outInsets);
 
     /**
+     * Set the forwarded insets on the display.
+     * <p>
+     * This is only used in case a virtual display is displayed on another display that has insets,
+     * and the bounds of the virtual display is overlapping with the insets from the host display.
+     * In that case, the contents on the virtual display won't be placed over the forwarded insets.
+     * Only the owner of the display is permitted to set the forwarded insets on it.
+     */
+    void setForwardedInsets(int displayId, in Insets insets);
+
+    /**
      * Register shortcut key. Shortcut code is packed as:
      * (MetaState << Integer.SIZE) | KeyCode
      * @hide
diff --git a/core/java/android/view/InputDevice.java b/core/java/android/view/InputDevice.java
index 7295259..868a9de 100644
--- a/core/java/android/view/InputDevice.java
+++ b/core/java/android/view/InputDevice.java
@@ -22,6 +22,7 @@
 import android.content.Context;
 import android.hardware.input.InputDeviceIdentifier;
 import android.hardware.input.InputManager;
+import android.os.Build;
 import android.os.NullVibrator;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -54,7 +55,7 @@
     private final int mProductId;
     private final String mDescriptor;
     private final InputDeviceIdentifier mIdentifier;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     private final boolean mIsExternal;
     private final int mSources;
     private final int mKeyboardType;
@@ -608,10 +609,7 @@
      * peripheral bus), otherwise it is built-in.
      *
      * @return True if the device is external.
-     *
-     * @hide
      */
-    @UnsupportedAppUsage
     public boolean isExternal() {
         return mIsExternal;
     }
diff --git a/core/java/android/view/InsetsAnimationControlImpl.java b/core/java/android/view/InsetsAnimationControlImpl.java
index 583651d..dd88e3c 100644
--- a/core/java/android/view/InsetsAnimationControlImpl.java
+++ b/core/java/android/view/InsetsAnimationControlImpl.java
@@ -33,6 +33,7 @@
 import android.view.InsetsState.InsetSide;
 import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams;
 import android.view.WindowInsets.Type.InsetType;
+import android.view.WindowManager.LayoutParams;
 
 import com.android.internal.annotations.VisibleForTesting;
 
@@ -165,7 +166,8 @@
             @Nullable @InsetSide SparseIntArray typeSideMap) {
         return state.calculateInsets(frame, false /* isScreenRound */,
                 false /* alwaysConsumerNavBar */, null /* displayCutout */,
-                null /* legacyContentInsets */, null /* legacyStableInsets */, typeSideMap)
+                null /* legacyContentInsets */, null /* legacyStableInsets */,
+                LayoutParams.SOFT_INPUT_ADJUST_RESIZE /* legacySoftInputMode*/, typeSideMap)
                .getInsets(mTypes);
     }
 
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 7ad97a6..2586000 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -112,6 +112,8 @@
 
     private int mPendingTypesToShow;
 
+    private int mLastLegacySoftInputMode;
+
     public InsetsController(ViewRootImpl viewRoot) {
         mViewRoot = viewRoot;
         mAnimCallback = () -> {
@@ -126,13 +128,17 @@
             }
             WindowInsets insets = state.calculateInsets(mFrame, mLastInsets.isRound(),
                     mLastInsets.shouldAlwaysConsumeNavBar(), mLastInsets.getDisplayCutout(),
-                    mLastLegacyContentInsets, mLastLegacyStableInsets,
+                    mLastLegacyContentInsets, mLastLegacyStableInsets, mLastLegacySoftInputMode,
                     null /* typeSideMap */);
             mViewRoot.mView.dispatchWindowInsetsAnimationProgress(insets);
         };
     }
 
     void onFrameChanged(Rect frame) {
+        if (mFrame.equals(frame)) {
+            return;
+        }
+        mViewRoot.notifyInsetsChanged();
         mFrame.set(frame);
     }
 
@@ -160,11 +166,12 @@
     @VisibleForTesting
     public WindowInsets calculateInsets(boolean isScreenRound,
             boolean alwaysConsumeNavBar, DisplayCutout cutout, Rect legacyContentInsets,
-            Rect legacyStableInsets) {
+            Rect legacyStableInsets, int legacySoftInputMode) {
         mLastLegacyContentInsets.set(legacyContentInsets);
         mLastLegacyStableInsets.set(legacyStableInsets);
+        mLastLegacySoftInputMode = legacySoftInputMode;
         mLastInsets = mState.calculateInsets(mFrame, isScreenRound, alwaysConsumeNavBar, cutout,
-                legacyContentInsets, legacyStableInsets,
+                legacyContentInsets, legacyStableInsets, legacySoftInputMode,
                 null /* typeSideMap */);
         return mLastInsets;
     }
@@ -257,11 +264,21 @@
 
     private void controlWindowInsetsAnimation(@InsetType int types,
             WindowInsetsAnimationControlListener listener, boolean fromIme) {
+        // If the frame of our window doesn't span the entire display, the control API makes very
+        // little sense, as we don't deal with negative insets. So just cancel immediately.
+        if (!mState.getDisplayFrame().equals(mFrame)) {
+            listener.onCancelled();
+            return;
+        }
+        controlAnimationUnchecked(types, listener, mFrame, fromIme);
+    }
+
+    private void controlAnimationUnchecked(@InsetType int types,
+            WindowInsetsAnimationControlListener listener, Rect frame, boolean fromIme) {
         if (types == 0) {
             // nothing to animate.
             return;
         }
-
         // TODO: Check whether we already have a controller.
         final ArraySet<Integer> internalTypes = mState.toInternalType(types);
         final SparseArray<InsetsSourceConsumer> consumers = new SparseArray<>();
@@ -285,7 +302,7 @@
         }
 
         final InsetsAnimationControlImpl controller = new InsetsAnimationControlImpl(consumers,
-                mFrame, mState, listener, typesReady,
+                frame, mState, listener, typesReady,
                 () -> new SyncRtSurfaceTransactionApplier(mViewRoot.mView), this);
         mAnimationControls.add(controller);
     }
@@ -436,6 +453,7 @@
             // nothing to animate.
             return;
         }
+
         WindowInsetsAnimationControlListener listener = new WindowInsetsAnimationControlListener() {
             @Override
             public void onReady(WindowInsetsAnimationController controller, int types) {
@@ -479,7 +497,10 @@
         // TODO: Instead of clearing this here, properly wire up
         // InsetsAnimationControlImpl.finish() to remove this from mAnimationControls.
         mAnimationControls.clear();
-        controlWindowInsetsAnimation(types, listener, fromIme);
+
+        // Show/hide animations always need to be relative to the display frame, in order that shown
+        // and hidden state insets are correct.
+        controlAnimationUnchecked(types, listener, mState.getDisplayFrame(), fromIme);
     }
 
     private void hideDirectly(@InsetType int types) {
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index 4f809fe6..69f86aa 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -19,6 +19,7 @@
 import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
 import static android.view.ViewRootImpl.NEW_INSETS_MODE_IME;
 import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE;
+import static android.view.WindowInsets.Type.IME;
 import static android.view.WindowInsets.Type.SIZE;
 import static android.view.WindowInsets.Type.indexOf;
 
@@ -34,11 +35,13 @@
 import android.util.SparseIntArray;
 import android.view.WindowInsets.Type;
 import android.view.WindowInsets.Type.InsetType;
+import android.view.WindowManager.LayoutParams;
 
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
+import java.util.Objects;
 
 /**
  * Holder for state of system windows that cause window insets for all other windows in the system.
@@ -104,6 +107,11 @@
 
     private final ArrayMap<Integer, InsetsSource> mSources = new ArrayMap<>();
 
+    /**
+     * The frame of the display these sources are relative to.
+     */
+    private final Rect mDisplayFrame = new Rect();
+
     public InsetsState() {
     }
 
@@ -124,7 +132,7 @@
     public WindowInsets calculateInsets(Rect frame, boolean isScreenRound,
             boolean alwaysConsumeNavBar, DisplayCutout cutout,
             @Nullable Rect legacyContentInsets, @Nullable Rect legacyStableInsets,
-            @Nullable @InsetSide SparseIntArray typeSideMap) {
+            int legacySoftInputMode, @Nullable @InsetSide SparseIntArray typeSideMap) {
         Insets[] typeInsetsMap = new Insets[Type.SIZE];
         Insets[] typeMaxInsetsMap = new Insets[Type.SIZE];
         boolean[] typeVisibilityMap = new boolean[SIZE];
@@ -140,8 +148,12 @@
             if (source == null) {
                 continue;
             }
-            if (ViewRootImpl.sNewInsetsMode != NEW_INSETS_MODE_FULL
-                    && (type == TYPE_TOP_BAR || type == TYPE_NAVIGATION_BAR)) {
+
+            boolean skipSystemBars = ViewRootImpl.sNewInsetsMode != NEW_INSETS_MODE_FULL
+                    && (type == TYPE_TOP_BAR || type == TYPE_NAVIGATION_BAR);
+            boolean skipIme = source.getType() == TYPE_IME
+                    && (legacySoftInputMode & LayoutParams.SOFT_INPUT_ADJUST_RESIZE) == 0;
+            if (skipSystemBars || skipIme) {
                 typeVisibilityMap[indexOf(toPublicType(type))] = source.isVisible();
                 continue;
             }
@@ -209,6 +221,14 @@
         return mSources.computeIfAbsent(type, InsetsSource::new);
     }
 
+    public void setDisplayFrame(Rect frame) {
+        mDisplayFrame.set(frame);
+    }
+
+    public Rect getDisplayFrame() {
+        return mDisplayFrame;
+    }
+
     /**
      * Modifies the state of this class to exclude a certain type to make it ready for dispatching
      * to the client.
@@ -224,6 +244,7 @@
     }
 
     public void set(InsetsState other, boolean copySources) {
+        mDisplayFrame.set(other.mDisplayFrame);
         mSources.clear();
         if (copySources) {
             for (int i = 0; i < other.mSources.size(); i++) {
@@ -323,6 +344,9 @@
 
         InsetsState state = (InsetsState) o;
 
+        if (!mDisplayFrame.equals(state.mDisplayFrame)) {
+            return false;
+        }
         if (mSources.size() != state.mSources.size()) {
             return false;
         }
@@ -341,7 +365,7 @@
 
     @Override
     public int hashCode() {
-        return mSources.hashCode();
+        return Objects.hash(mDisplayFrame, mSources);
     }
 
     public InsetsState(Parcel in) {
@@ -355,9 +379,10 @@
 
     @Override
     public void writeToParcel(Parcel dest, int flags) {
+        dest.writeParcelable(mDisplayFrame, flags);
         dest.writeInt(mSources.size());
         for (int i = 0; i < mSources.size(); i++) {
-            dest.writeParcelable(mSources.valueAt(i), 0 /* flags */);
+            dest.writeParcelable(mSources.valueAt(i), flags);
         }
     }
 
@@ -374,6 +399,7 @@
 
     public void readFromParcel(Parcel in) {
         mSources.clear();
+        mDisplayFrame.set(in.readParcelable(null /* loader */));
         final int size = in.readInt();
         for (int i = 0; i < size; i++) {
             final InsetsSource source = in.readParcelable(null /* loader */);
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index c130250..3f18d8b 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -33,8 +33,6 @@
 import android.os.Message;
 import android.os.SystemProperties;
 import android.os.Trace;
-import android.provider.DeviceConfig;
-import android.text.TextUtils;
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.TypedValue;
@@ -53,6 +51,7 @@
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Method;
 import java.util.HashMap;
+import java.util.Objects;
 
 /**
  * Instantiates a layout XML file into its corresponding {@link android.view.View}
@@ -81,6 +80,8 @@
     private static final String TAG = LayoutInflater.class.getSimpleName();
     private static final boolean DEBUG = false;
 
+    private static final String USE_PRECOMPILED_LAYOUT_SYSTEM_PROPERTY
+        = "view.precompiled_layout_enabled";
     private static final String COMPILED_VIEW_DEX_FILE_NAME = "/compiled_view.dex";
 
     /** Empty stack trace used to avoid log spam in re-throw exceptions. */
@@ -111,7 +112,12 @@
     // The classloader includes the generated compiled_view.dex file.
     private ClassLoader mPrecompiledClassLoader;
 
-    @UnsupportedAppUsage
+    /**
+     * This is not a public API. Two APIs are now available to alleviate the need to access
+     * this directly: {@link #createView(Context, String, String, AttributeSet)} and
+     * {@link #onCreateView(Context, View, String, AttributeSet)}.
+     */
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     final Object[] mConstructorArgs = new Object[2];
 
     @UnsupportedAppUsage
@@ -401,19 +407,8 @@
     }
 
     private void initPrecompiledViews() {
-        // Use the device config if enabled, otherwise default to the system property.
-        String usePrecompiledLayout = DeviceConfig.getProperty(
-                DeviceConfig.Runtime.NAMESPACE,
-                DeviceConfig.Runtime.USE_PRECOMPILED_LAYOUT);
-        boolean enabled = false;
-        if (TextUtils.isEmpty(usePrecompiledLayout)) {
-            enabled = SystemProperties.getBoolean(
-                    DeviceConfig.Runtime.USE_PRECOMPILED_LAYOUT,
-                    false);
-        } else {
-            enabled = Boolean.parseBoolean(usePrecompiledLayout);
-        }
-        initPrecompiledViews(enabled);
+        initPrecompiledViews(
+                SystemProperties.getBoolean(USE_PRECOMPILED_LAYOUT_SYSTEM_PROPERTY, false));
     }
 
     private void initPrecompiledViews(boolean enablePrecompiledViews) {
@@ -733,11 +728,11 @@
         } while (cl != null);
         return false;
     }
-
     /**
      * Low-level function for instantiating a view by name. This attempts to
      * instantiate a view class of the given <var>name</var> found in this
-     * LayoutInflater's ClassLoader.
+     * LayoutInflater's ClassLoader. To use an explicit Context in the View
+     * constructor, use {@link #createView(Context, String, String, AttributeSet)} instead.
      *
      * <p>
      * There are two things that can happen in an error case: either the
@@ -753,6 +748,37 @@
      */
     public final View createView(String name, String prefix, AttributeSet attrs)
             throws ClassNotFoundException, InflateException {
+        Context context = (Context) mConstructorArgs[0];
+        if (context == null) {
+            context = mContext;
+        }
+        return createView(context, name, prefix, attrs);
+    }
+
+    /**
+     * Low-level function for instantiating a view by name. This attempts to
+     * instantiate a view class of the given <var>name</var> found in this
+     * LayoutInflater's ClassLoader.
+     *
+     * <p>
+     * There are two things that can happen in an error case: either the
+     * exception describing the error will be thrown, or a null will be
+     * returned. You must deal with both possibilities -- the former will happen
+     * the first time createView() is called for a class of a particular name,
+     * the latter every time there-after for that class name.
+     *
+     * @param viewContext The context used as the context parameter of the View constructor
+     * @param name The full name of the class to be instantiated.
+     * @param attrs The XML attributes supplied for this instance.
+     *
+     * @return View The newly instantiated view, or null.
+     */
+    @Nullable
+    public final View createView(@NonNull Context viewContext, @NonNull String name,
+            @Nullable String prefix, @Nullable AttributeSet attrs)
+            throws ClassNotFoundException, InflateException {
+        Objects.requireNonNull(viewContext);
+        Objects.requireNonNull(name);
         Constructor<? extends View> constructor = sConstructorMap.get(name);
         if (constructor != null && !verifyClassLoader(constructor)) {
             constructor = null;
@@ -799,22 +825,21 @@
             }
 
             Object lastContext = mConstructorArgs[0];
-            if (mConstructorArgs[0] == null) {
-                // Fill in the context if not already within inflation.
-                mConstructorArgs[0] = mContext;
-            }
+            mConstructorArgs[0] = viewContext;
             Object[] args = mConstructorArgs;
             args[1] = attrs;
 
-            final View view = constructor.newInstance(args);
-            if (view instanceof ViewStub) {
-                // Use the same context when inflating ViewStub later.
-                final ViewStub viewStub = (ViewStub) view;
-                viewStub.setLayoutInflater(cloneInContext((Context) args[0]));
+            try {
+                final View view = constructor.newInstance(args);
+                if (view instanceof ViewStub) {
+                    // Use the same context when inflating ViewStub later.
+                    final ViewStub viewStub = (ViewStub) view;
+                    viewStub.setLayoutInflater(cloneInContext((Context) args[0]));
+                }
+                return view;
+            } finally {
+                mConstructorArgs[0] = lastContext;
             }
-            mConstructorArgs[0] = lastContext;
-            return view;
-
         } catch (NoSuchMethodException e) {
             final InflateException ie = new InflateException(attrs.getPositionDescription()
                     + ": Error inflating class " + (prefix != null ? (prefix + name) : name), e);
@@ -883,6 +908,26 @@
     }
 
     /**
+     * Version of {@link #onCreateView(View, String, AttributeSet)} that also
+     * takes the inflation context.  The default
+     * implementation simply calls {@link #onCreateView(View, String, AttributeSet)}.
+     *
+     * @param viewContext The Context to be used as a constructor parameter for the View
+     * @param parent The future parent of the returned view.  <em>Note that
+     * this may be null.</em>
+     * @param name The fully qualified class name of the View to be create.
+     * @param attrs An AttributeSet of attributes to apply to the View.
+     *
+     * @return View The View created.
+     */
+    @Nullable
+    public View onCreateView(@NonNull Context viewContext, @Nullable View parent,
+            @NonNull String name, @Nullable AttributeSet attrs)
+            throws ClassNotFoundException {
+        return onCreateView(parent, name, attrs);
+    }
+
+    /**
      * Convenience method for calling through to the five-arg createViewFromTag
      * method. This method passes {@code false} for the {@code ignoreThemeAttr}
      * argument and should be used for everything except {@code &gt;include>}
@@ -933,9 +978,9 @@
                 mConstructorArgs[0] = context;
                 try {
                     if (-1 == name.indexOf('.')) {
-                        view = onCreateView(parent, name, attrs);
+                        view = onCreateView(context, parent, name, attrs);
                     } else {
-                        view = createView(name, null, attrs);
+                        view = createView(context, name, null, attrs);
                     }
                 } finally {
                     mConstructorArgs[0] = lastContext;
diff --git a/core/java/android/view/MotionEvent.java b/core/java/android/view/MotionEvent.java
index b6a4a09..b6c4cbb 100644
--- a/core/java/android/view/MotionEvent.java
+++ b/core/java/android/view/MotionEvent.java
@@ -24,6 +24,7 @@
 import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
 import android.graphics.Matrix;
+import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.SystemClock;
@@ -1513,7 +1514,7 @@
     }
 
     // Pointer to the native MotionEvent object that contains the actual data.
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     private long mNativePtr;
 
     private MotionEvent mNext;
diff --git a/core/java/android/view/RemotableViewMethod.java b/core/java/android/view/RemotableViewMethod.java
index 03aed9a..5eff848 100644
--- a/core/java/android/view/RemotableViewMethod.java
+++ b/core/java/android/view/RemotableViewMethod.java
@@ -16,6 +16,8 @@
 
 package android.view;
 
+import android.annotation.TestApi;
+
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -26,6 +28,7 @@
  * This annotation indicates that a method on a subclass of View
  * is alllowed to be used with the {@link android.widget.RemoteViews} mechanism.
  */
+@TestApi
 @Target({ ElementType.METHOD })
 @Retention(RetentionPolicy.RUNTIME)
 public @interface RemotableViewMethod {
diff --git a/core/java/android/view/RenderNodeAnimator.java b/core/java/android/view/RenderNodeAnimator.java
index 78ad0da..1dbc46b 100644
--- a/core/java/android/view/RenderNodeAnimator.java
+++ b/core/java/android/view/RenderNodeAnimator.java
@@ -24,6 +24,7 @@
 import android.graphics.Paint;
 import android.graphics.RecordingCanvas;
 import android.graphics.RenderNode;
+import android.os.Build;
 import android.util.SparseIntArray;
 
 import com.android.internal.util.VirtualRefBasePtr;
@@ -282,7 +283,7 @@
         throw new UnsupportedOperationException();
     }
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.O)
     public void setTarget(View view) {
         mViewTarget = view;
         setTarget(mViewTarget.mRenderNode);
diff --git a/core/java/android/view/ScaleGestureDetector.java b/core/java/android/view/ScaleGestureDetector.java
index dc11d3d..c24b8b2 100644
--- a/core/java/android/view/ScaleGestureDetector.java
+++ b/core/java/android/view/ScaleGestureDetector.java
@@ -18,7 +18,6 @@
 
 import android.annotation.UnsupportedAppUsage;
 import android.content.Context;
-import android.content.res.Resources;
 import android.os.Build;
 import android.os.Handler;
 
@@ -145,7 +144,7 @@
     private boolean mInProgress;
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768938)
     private int mSpanSlop;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768938)
     private int mMinSpan;
 
     private final Handler mHandler;
@@ -200,10 +199,9 @@
                                 Handler handler) {
         mContext = context;
         mListener = listener;
-        mSpanSlop = ViewConfiguration.get(context).getScaledTouchSlop() * 2;
-
-        final Resources res = context.getResources();
-        mMinSpan = res.getDimensionPixelSize(com.android.internal.R.dimen.config_minScalingSpan);
+        final ViewConfiguration viewConfiguration = ViewConfiguration.get(context);
+        mSpanSlop = viewConfiguration.getScaledTouchSlop() * 2;
+        mMinSpan = viewConfiguration.getScaledMinScalingSpan();
         mHandler = handler;
         // Quick scale is enabled by default after JB_MR2
         final int targetSdkVersion = context.getApplicationInfo().targetSdkVersion;
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 8061cc3..1212df0 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -44,6 +44,7 @@
 import android.hardware.HardwareBuffer;
 import android.hardware.display.DisplayedContentSample;
 import android.hardware.display.DisplayedContentSamplingAttributes;
+import android.os.Build;
 import android.os.IBinder;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -61,6 +62,7 @@
 
 import java.io.Closeable;
 import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
 
 /**
  * Handle to an on-screen Surface managed by the system compositor. The SurfaceControl is
@@ -131,7 +133,8 @@
     private static native boolean nativeClearAnimationFrameStats();
     private static native boolean nativeGetAnimationFrameStats(WindowAnimationFrameStats outStats);
 
-    private static native IBinder nativeGetBuiltInDisplay(int physicalDisplayId);
+    private static native long[] nativeGetPhysicalDisplayIds();
+    private static native IBinder nativeGetPhysicalDisplayToken(long physicalDisplayId);
     private static native IBinder nativeCreateDisplay(String name, boolean secure);
     private static native void nativeDestroyDisplay(IBinder displayToken);
     private static native void nativeSetDisplaySurface(long transactionObj,
@@ -329,24 +332,6 @@
      */
     private static final int SURFACE_OPAQUE = 0x02;
 
-
-    /* built-in physical display ids (keep in sync with ISurfaceComposer.h)
-     * these are different from the logical display ids used elsewhere in the framework */
-
-    /**
-     * Built-in physical display id: Main display.
-     * Use only with {@link SurfaceControl#getBuiltInDisplay(int)}.
-     * @hide
-     */
-    public static final int BUILT_IN_DISPLAY_ID_MAIN = 0;
-
-    /**
-     * Built-in physical display id: Attached HDMI display.
-     * Use only with {@link SurfaceControl#getBuiltInDisplay(int)}.
-     * @hide
-     */
-    public static final int BUILT_IN_DISPLAY_ID_HDMI = 1;
-
     // Display power modes.
     /**
      * Display power mode off: used while blanking the screen.
@@ -727,8 +712,10 @@
                 for (int i = 0; i < metadata.size(); ++i) {
                     metaParcel.writeInt(metadata.keyAt(i));
                     metaParcel.writeByteArray(
-                            ByteBuffer.allocate(4).putInt(metadata.valueAt(i)).array());
+                            ByteBuffer.allocate(4).order(ByteOrder.nativeOrder())
+                                    .putInt(metadata.valueAt(i)).array());
                 }
+                metaParcel.setDataPosition(0);
             }
             mNativeObject = nativeCreate(session, name, w, h, format, flags,
                     parent != null ? parent.mNativeObject : 0, metaParcel);
@@ -868,12 +855,11 @@
     }
 
     /**
-     * Free all server-side state associated with this surface and
-     * release this object's reference.  This method can only be
-     * called from the process that created the service.
+     * Release the local resources like {@link #release} but also
+     * remove the Surface from the screen.
      * @hide
      */
-    public void destroy() {
+    public void remove() {
         if (mNativeObject != 0) {
             nativeDestroy(mNativeObject);
             mNativeObject = 0;
@@ -1729,9 +1715,28 @@
     /**
      * @hide
      */
-    @UnsupportedAppUsage
-    public static IBinder getBuiltInDisplay(int builtInDisplayId) {
-        return nativeGetBuiltInDisplay(builtInDisplayId);
+    public static long[] getPhysicalDisplayIds() {
+        return nativeGetPhysicalDisplayIds();
+    }
+
+    /**
+     * @hide
+     */
+    public static IBinder getPhysicalDisplayToken(long physicalDisplayId) {
+        return nativeGetPhysicalDisplayToken(physicalDisplayId);
+    }
+
+    /**
+     * TODO(116025192): Remove this stopgap once framework is display-agnostic.
+     *
+     * @hide
+     */
+    public static IBinder getInternalDisplayToken() {
+        final long[] physicalDisplayIds = getPhysicalDisplayIds();
+        if (physicalDisplayIds.length == 0) {
+            return null;
+        }
+        return getPhysicalDisplayToken(physicalDisplayIds[0]);
     }
 
     /**
@@ -1790,8 +1795,12 @@
     public static Bitmap screenshot(Rect sourceCrop, int width, int height,
             boolean useIdentityTransform, int rotation) {
         // TODO: should take the display as a parameter
-        IBinder displayToken = SurfaceControl.getBuiltInDisplay(
-                SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN);
+        final IBinder displayToken = SurfaceControl.getInternalDisplayToken();
+        if (displayToken == null) {
+            Log.w(TAG, "Failed to take screenshot because internal display is disconnected");
+            return null;
+        }
+
         if (rotation == ROTATION_90 || rotation == ROTATION_270) {
             rotation = (rotation == ROTATION_90) ? ROTATION_270 : ROTATION_90;
         }
@@ -2194,7 +2203,7 @@
         /**
          * @hide
          */
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.O)
         public Transaction setLayerStack(SurfaceControl sc, int layerStack) {
             sc.checkNotReleased();
             nativeSetLayerStack(mNativeObject, sc.mNativeObject, layerStack);
@@ -2460,5 +2469,23 @@
             nativeMergeTransaction(mNativeObject, other.mNativeObject);
             return this;
         }
+
+        /**
+         * Equivalent to reparent with a null parent, in that it removes
+         * the SurfaceControl from the scene, but it also releases
+         * the local resources (by calling {@link SurfaceControl#release})
+         * after this method returns, {@link SurfaceControl#isValid} will return
+         * false for the argument.
+         *
+         * @param sc The surface to remove and release.
+         * @return This transaction
+         * @hide
+         */
+        @NonNull
+        public Transaction remove(@NonNull SurfaceControl sc) {
+            reparent(sc, null);
+            sc.release();
+            return this;
+        }
     }
 }
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index cd5207c..9f0800f 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -334,7 +334,7 @@
 
         updateSurface();
         if (mSurfaceControl != null) {
-            mSurfaceControl.destroy();
+            mSurfaceControl.remove();
         }
         mSurfaceControl = null;
 
@@ -502,11 +502,11 @@
 
     private void releaseSurfaces() {
         if (mSurfaceControl != null) {
-            mSurfaceControl.destroy();
+            mSurfaceControl.remove();
             mSurfaceControl = null;
         }
         if (mBackgroundControl != null) {
-            mBackgroundControl.destroy();
+            mBackgroundControl.remove();
             mBackgroundControl = null;
         }
     }
@@ -816,7 +816,7 @@
         }
 
         if (mDeferredDestroySurfaceControl != null) {
-            mDeferredDestroySurfaceControl.destroy();
+            mDeferredDestroySurfaceControl.remove();
             mDeferredDestroySurfaceControl = null;
         }
 
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 90110e6..3f2795b 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -35,6 +35,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.Size;
+import android.annotation.StyleRes;
 import android.annotation.TestApi;
 import android.annotation.UiThread;
 import android.annotation.UnsupportedAppUsage;
@@ -91,6 +92,7 @@
 import android.util.Pools.SynchronizedPool;
 import android.util.Property;
 import android.util.SparseArray;
+import android.util.SparseIntArray;
 import android.util.StateSet;
 import android.util.SuperNotCalledException;
 import android.util.TypedValue;
@@ -103,6 +105,7 @@
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityEventSource;
 import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.AccessibilityNodeIdManager;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
 import android.view.accessibility.AccessibilityNodeProvider;
@@ -820,7 +823,14 @@
      *
      * @hide
      */
-    public static boolean mDebugViewAttributes = false;
+    public static boolean sDebugViewAttributes = false;
+
+    /**
+     * When set to this application package view will save its attribute data.
+     *
+     * @hide
+     */
+    public static String sDebugViewAttributesApplicationPackage;
 
     /**
      * Used to mark a View that has no ID.
@@ -4258,47 +4268,51 @@
     /**
      * The offset, in pixels, by which the content of this view is scrolled
      * horizontally.
+     * Please use {@link View#getScrollX()} and {@link View#setScrollX(int)} instead of
+     * accessing these directly.
      * {@hide}
      */
     @ViewDebug.ExportedProperty(category = "scrolling")
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     protected int mScrollX;
     /**
      * The offset, in pixels, by which the content of this view is scrolled
      * vertically.
+     * Please use {@link View#getScrollY()} and {@link View#setScrollY(int)} instead of
+     * accessing these directly.
      * {@hide}
      */
     @ViewDebug.ExportedProperty(category = "scrolling")
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     protected int mScrollY;
 
     /**
-     * The left padding in pixels, that is the distance in pixels between the
-     * left edge of this view and the left edge of its content.
+     * The final computed left padding in pixels that is used for drawing. This is the distance in
+     * pixels between the left edge of this view and the left edge of its content.
      * {@hide}
      */
     @ViewDebug.ExportedProperty(category = "padding")
     @UnsupportedAppUsage
     protected int mPaddingLeft = 0;
     /**
-     * The right padding in pixels, that is the distance in pixels between the
-     * right edge of this view and the right edge of its content.
+     * The final computed right padding in pixels that is used for drawing. This is the distance in
+     * pixels between the right edge of this view and the right edge of its content.
      * {@hide}
      */
     @ViewDebug.ExportedProperty(category = "padding")
     @UnsupportedAppUsage
     protected int mPaddingRight = 0;
     /**
-     * The top padding in pixels, that is the distance in pixels between the
-     * top edge of this view and the top edge of its content.
+     * The final computed top padding in pixels that is used for drawing. This is the distance in
+     * pixels between the top edge of this view and the top edge of its content.
      * {@hide}
      */
     @ViewDebug.ExportedProperty(category = "padding")
     @UnsupportedAppUsage
     protected int mPaddingTop;
     /**
-     * The bottom padding in pixels, that is the distance in pixels between the
-     * bottom edge of this view and the bottom edge of its content.
+     * The final computed bottom padding in pixels that is used for drawing. This is the distance in
+     * pixels between the bottom edge of this view and the bottom edge of its content.
      * {@hide}
      */
     @ViewDebug.ExportedProperty(category = "padding")
@@ -4350,7 +4364,7 @@
     private MatchIdPredicate mMatchIdPredicate;
 
     /**
-     * Cache the paddingRight set by the user to append to the scrollbar's size.
+     * The right padding after RTL resolution, but before taking account of scroll bars.
      *
      * @hide
      */
@@ -4358,7 +4372,7 @@
     protected int mUserPaddingRight;
 
     /**
-     * Cache the paddingBottom set by the user to append to the scrollbar's size.
+     * The resolved bottom padding before taking account of scroll bars.
      *
      * @hide
      */
@@ -4366,7 +4380,7 @@
     protected int mUserPaddingBottom;
 
     /**
-     * Cache the paddingLeft set by the user to append to the scrollbar's size.
+     * The left padding after RTL resolution, but before taking account of scroll bars.
      *
      * @hide
      */
@@ -4388,14 +4402,16 @@
     int mUserPaddingEnd;
 
     /**
-     * Cache initial left padding.
+     * The left padding as set by a setter method, a background's padding, or via XML property
+     * resolution. This value is the padding before LTR resolution or taking account of scrollbars.
      *
      * @hide
      */
     int mUserPaddingLeftInitial;
 
     /**
-     * Cache initial right padding.
+     * The right padding as set by a setter method, a background's padding, or via XML property
+     * resolution. This value is the padding before LTR resolution or taking account of scrollbars.
      *
      * @hide
      */
@@ -4407,12 +4423,14 @@
     private static final int UNDEFINED_PADDING = Integer.MIN_VALUE;
 
     /**
-     * Cache if a left padding has been defined
+     * Cache if a left padding has been defined explicitly via padding, horizontal padding,
+     * or leftPadding in XML, or by setPadding(...) or setRelativePadding(...)
      */
     private boolean mLeftPaddingDefined = false;
 
     /**
-     * Cache if a right padding has been defined
+     * Cache if a right padding has been defined explicitly via padding, horizontal padding,
+     * or rightPadding in XML, or by setPadding(...) or setRelativePadding(...)
      */
     private boolean mRightPaddingDefined = false;
 
@@ -5070,6 +5088,15 @@
     @LayoutRes
     private int mSourceLayoutId = ID_NULL;
 
+    @Nullable
+    private SparseIntArray mAttributeSourceResId;
+
+    @Nullable
+    private int[] mAttributeResolutionStack;
+
+    @StyleRes
+    private int mExplicitStyle;
+
     /**
      * Cached reference to the {@link ContentCaptureSession}, is reset on {@link #invalidate()}.
      */
@@ -5245,7 +5272,11 @@
         final TypedArray a = context.obtainStyledAttributes(
                 attrs, com.android.internal.R.styleable.View, defStyleAttr, defStyleRes);
 
-        if (mDebugViewAttributes) {
+        retrieveExplicitStyle(context.getTheme(), attrs);
+        saveAttributeDataForStyleable(context, com.android.internal.R.styleable.View, attrs, a,
+                defStyleAttr, defStyleRes);
+
+        if (sDebugViewAttributes) {
             saveAttributeData(attrs, a);
         }
 
@@ -5321,7 +5352,7 @@
                 case com.android.internal.R.styleable.View_paddingVertical:
                     paddingVertical = a.getDimensionPixelSize(attr, -1);
                     break;
-                 case com.android.internal.R.styleable.View_paddingLeft:
+                case com.android.internal.R.styleable.View_paddingLeft:
                     leftPadding = a.getDimensionPixelSize(attr, -1);
                     mUserPaddingLeftInitial = leftPadding;
                     leftPaddingDefined = true;
@@ -5787,7 +5818,7 @@
 
         setOverScrollMode(overScrollMode);
 
-        // Cache start/end user padding as we cannot fully resolve padding here (we dont have yet
+        // Cache start/end user padding as we cannot fully resolve padding here (we don't have yet
         // the resolved layout direction). Those cached values will be used later during padding
         // resolution.
         mUserPaddingStart = startPadding;
@@ -5802,6 +5833,8 @@
         mLeftPaddingDefined = leftPaddingDefined;
         mRightPaddingDefined = rightPaddingDefined;
 
+        // Valid paddingHorizontal/paddingVertical beats leftPadding, rightPadding, topPadding,
+        // bottomPadding, and padding set by background.  Valid padding beats everything.
         if (padding >= 0) {
             leftPadding = padding;
             topPadding = padding;
@@ -5854,6 +5887,8 @@
             }
         }
 
+        // mPaddingTop and mPaddingBottom may have been set by setBackground(Drawable) so must pass
+        // them on if topPadding or bottomPadding are not valid.
         internalSetPadding(
                 mUserPaddingLeftInitial,
                 topPadding >= 0 ? topPadding : mPaddingTop,
@@ -5903,6 +5938,84 @@
     }
 
     /**
+     * Returns the ordered list of resource ID that are considered when resolving attribute values
+     * for this {@link View}. The list will include layout resource ID if the View is inflated from
+     * XML. It will also include a set of explicit styles if specified in XML using
+     * {@code style="..."}. Finally, it will include the default styles resolved from the theme.
+     *
+     * <p>
+     * <b>Note:</b> this method will only return actual values if the view attribute debugging
+     * is enabled in Android developer options.
+     *
+     * @return ordered list of resource ID that are considered when resolving attribute values for
+     * this {@link View}.
+     */
+    @NonNull
+    public List<Integer> getAttributeResolutionStack() {
+        ArrayList<Integer> stack = new ArrayList<>();
+        if (!sDebugViewAttributes) {
+            return stack;
+        }
+        if (mSourceLayoutId != ID_NULL) {
+            stack.add(mSourceLayoutId);
+        }
+        for (int i = 0; i < mAttributeResolutionStack.length; i++) {
+            stack.add(mAttributeResolutionStack[i]);
+        }
+        return stack;
+    }
+
+    /**
+     * Returns the mapping of attribute resource ID to source resource ID where the attribute value
+     * was set. Source resource ID can either be a layout resource ID, if the value was set in XML
+     * within the View tag, or a style resource ID, if the attribute was set in a style. The source
+     * resource value will be one of the resource IDs from {@link #getAttributeSourceResourceMap()}.
+     *
+     * <p>
+     * <b>Note:</b> this method will only return actual values if the view attribute debugging
+     * is enabled in Android developer options.
+     *
+     * @return mapping of attribute resource ID to source resource ID where the attribute value
+     * was set.
+     */
+    @NonNull
+    public Map<Integer, Integer> getAttributeSourceResourceMap() {
+        HashMap<Integer, Integer> map = new HashMap<>();
+        if (!sDebugViewAttributes) {
+            return map;
+        }
+        for (int i = 0; i < mAttributeSourceResId.size(); i++) {
+            map.put(mAttributeSourceResId.keyAt(i), mAttributeSourceResId.valueAt(i));
+        }
+        return map;
+    }
+
+    /**
+     * Returns the resource ID for the style specified using {@code style="..."} in the
+     * {@link AttributeSet}'s backing XML element or {@link Resources#ID_NULL} otherwise if not
+     * specified or otherwise not applicable.
+     * <p>
+     * Each {@link View} can have an explicit style specified in the layout file.
+     * This style is used first during the {@link View} attribute resolution, then if an attribute
+     * is not defined there the resource system looks at default style and theme as fallbacks.
+     *
+     * <p>
+     * <b>Note:</b> this method will only return actual values if the view attribute debugging
+     * is enabled in Android developer options.
+     *
+     * @return The resource ID for the style specified using {@code style="..."} in the
+     *      {@link AttributeSet}'s backing XML element or {@link Resources#ID_NULL} otherwise
+     *      if not specified or otherwise not applicable.
+     */
+    @StyleRes
+    public int getExplicitStyle() {
+        if (!sDebugViewAttributes) {
+            return ID_NULL;
+        }
+        return mExplicitStyle;
+    }
+
+    /**
      * An implementation of OnClickListener that attempts to lazily load a
      * named click handling method from a parent or ancestor context.
      */
@@ -5988,6 +6101,46 @@
         return mAttributeMap;
     }
 
+    private void retrieveExplicitStyle(@NonNull Resources.Theme theme,
+            @Nullable AttributeSet attrs) {
+        if (!sDebugViewAttributes) {
+            return;
+        }
+        mExplicitStyle = theme.getExplicitStyle(attrs);
+    }
+
+    /**
+     * Stores debugging information about attributes. This should be called in a constructor by
+     * every custom {@link View} that uses a custom styleable.
+     *  @param context Context under which this view is created.
+     * @param styleable A reference to styleable array R.styleable.Foo
+     * @param attrs AttributeSet used to construct this view.
+     * @param t Resolved {@link TypedArray} returned by a call to
+     *        {@link Resources#obtainAttributes(AttributeSet, int[])}.
+     * @param defStyleAttr Default style attribute passed into the view constructor.
+     * @param defStyleRes Default style resource passed into the view constructor.
+     */
+    public final void saveAttributeDataForStyleable(@NonNull Context context,
+            @NonNull int[] styleable, @Nullable AttributeSet attrs, @NonNull TypedArray t,
+            int defStyleAttr, int defStyleRes) {
+        if (!sDebugViewAttributes) {
+            return;
+        }
+
+        mAttributeResolutionStack = context.getTheme().getAttributeResolutionStack(
+                defStyleAttr, defStyleRes, mExplicitStyle);
+
+        if (mAttributeSourceResId == null) {
+            mAttributeSourceResId = new SparseIntArray();
+        }
+
+        final int indexCount = t.getIndexCount();
+        for (int j = 0; j < indexCount; ++j) {
+            final int index = t.getIndex(j);
+            mAttributeSourceResId.append(styleable[index], t.getSourceResourceId(index, 0));
+        }
+    }
+
     private void saveAttributeData(@Nullable AttributeSet attrs, @NonNull TypedArray t) {
         final int attrsCount = attrs == null ? 0 : attrs.getAttributeCount();
         final int indexCount = t.getIndexCount();
@@ -16183,7 +16336,7 @@
      * @return true if the View subclass handles alpha (the return value for onSetAlpha()) and
      *         the new value for the alpha property is different from the old value
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk  = Build.VERSION_CODES.P, trackingBug = 123768435)
     boolean setAlphaNoInvalidation(float alpha) {
         ensureTransformationInfo();
         if (mTransformationInfo.mAlpha != alpha) {
@@ -19029,6 +19182,7 @@
 
         jumpDrawablesToCurrentState();
 
+        AccessibilityNodeIdManager.getInstance().registerViewWithId(this, getAccessibilityViewId());
         resetSubtreeAccessibilityStateChanged();
 
         // rebuild, since Outline not maintained while View is detached
@@ -19421,6 +19575,8 @@
         if ((mViewFlags & TOOLTIP) == TOOLTIP) {
             hideTooltip();
         }
+
+        AccessibilityNodeIdManager.getInstance().unregisterViewWithId(getAccessibilityViewId());
     }
 
     private void cleanupDraw() {
@@ -23273,7 +23429,7 @@
     /**
      * @hide
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768420)
     protected void internalSetPadding(int left, int top, int right, int bottom) {
         mUserPaddingLeft = left;
         mUserPaddingRight = right;
@@ -23935,24 +24091,6 @@
     }
 
     /**
-     * Finds a view by its unuque and stable accessibility id.
-     *
-     * @param accessibilityId The searched accessibility id.
-     * @return The found view.
-     */
-    @UnsupportedAppUsage
-    final <T extends View> T findViewByAccessibilityId(int accessibilityId) {
-        if (accessibilityId < 0) {
-            return null;
-        }
-        T view = findViewByAccessibilityIdTraversal(accessibilityId);
-        if (view != null) {
-            return view.includeForAccessibility() ? view : null;
-        }
-        return null;
-    }
-
-    /**
      * Performs the traversal to find a view by its unique and stable accessibility id.
      *
      * <strong>Note:</strong>This method does not stop at the root namespace
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index 6beae37..bb29ed6 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -293,12 +293,14 @@
      */
     private static final float AMBIGUOUS_GESTURE_MULTIPLIER = 2f;
 
+    private final boolean mConstructedWithContext;
     private final int mEdgeSlop;
     private final int mFadingEdgeLength;
     private final int mMinimumFlingVelocity;
     private final int mMaximumFlingVelocity;
     private final int mScrollbarSize;
     private final int mTouchSlop;
+    private final int mMinScalingSpan;
     private final int mHoverSlop;
     private final int mMinScrollbarTouchTarget;
     private final int mDoubleTapTouchSlop;
@@ -329,6 +331,7 @@
      */
     @Deprecated
     public ViewConfiguration() {
+        mConstructedWithContext = false;
         mEdgeSlop = EDGE_SLOP;
         mFadingEdgeLength = FADING_EDGE_LENGTH;
         mMinimumFlingVelocity = MINIMUM_FLING_VELOCITY;
@@ -350,6 +353,10 @@
         mHorizontalScrollFactor = HORIZONTAL_SCROLL_FACTOR;
         mVerticalScrollFactor = VERTICAL_SCROLL_FACTOR;
         mShowMenuShortcutsWhenKeyboardPresent = false;
+
+        // Getter throws if mConstructedWithContext is false so doesn't matter what
+        // this value is.
+        mMinScalingSpan = 0;
     }
 
     /**
@@ -363,6 +370,7 @@
      * @see android.util.DisplayMetrics
      */
     private ViewConfiguration(Context context) {
+        mConstructedWithContext = true;
         final Resources res = context.getResources();
         final DisplayMetrics metrics = res.getDisplayMetrics();
         final Configuration config = res.getConfiguration();
@@ -447,6 +455,8 @@
         mShowMenuShortcutsWhenKeyboardPresent = res.getBoolean(
             com.android.internal.R.bool.config_showMenuShortcutsWhenKeyboardPresent);
 
+        mMinScalingSpan = res.getDimensionPixelSize(
+                com.android.internal.R.dimen.config_minScalingSpan);
     }
 
     /**
@@ -959,6 +969,26 @@
     }
 
     /**
+     * Retrieves the distance in pixels between touches that must be reached for a gesture to be
+     * interpreted as scaling.
+     *
+     * In general, scaling shouldn't start until this distance has been met or surpassed, and
+     * scaling should end when the distance in pixels between touches drops below this distance.
+     *
+     * @return The distance in pixels
+     * @throws IllegalStateException if this method is called on a ViewConfiguration that was
+     *         instantiated using a constructor with no Context parameter.
+     */
+    public int getScaledMinScalingSpan() {
+        if (!mConstructedWithContext) {
+            throw new IllegalStateException("Min scaling span cannot be determined when this "
+                    + "method is called on a ViewConfiguration that was instantiated using a "
+                    + "constructor with no Context parameter");
+        }
+        return mMinScalingSpan;
+    }
+
+    /**
      * @hide
      * @return Whether or not marquee should use fading edges.
      */
diff --git a/core/java/android/view/ViewPropertyAnimator.java b/core/java/android/view/ViewPropertyAnimator.java
index a0ab362..68c0d9e 100644
--- a/core/java/android/view/ViewPropertyAnimator.java
+++ b/core/java/android/view/ViewPropertyAnimator.java
@@ -1139,12 +1139,6 @@
 
             boolean hardwareAccelerated = mView.isHardwareAccelerated();
 
-            // alpha requires slightly different treatment than the other (transform) properties.
-            // The logic in setAlpha() is not simply setting mAlpha, plus the invalidation
-            // logic is dependent on how the view handles an internal call to onSetAlpha().
-            // We track what kinds of properties are set, and how alpha is handled when it is
-            // set, and perform the invalidation steps appropriately.
-            boolean alphaHandled = false;
             if (!hardwareAccelerated) {
                 mView.invalidateParentCaches();
             }
@@ -1159,11 +1153,7 @@
                 for (int i = 0; i < count; ++i) {
                     NameValuesHolder values = valueList.get(i);
                     float value = values.mFromValue + fraction * values.mDeltaValue;
-                    if (values.mNameConstant == ALPHA) {
-                        alphaHandled = mView.setAlphaNoInvalidation(value);
-                    } else {
-                        setValue(values.mNameConstant, value);
-                    }
+                    setValue(values.mNameConstant, value);
                 }
             }
             if ((propertyMask & TRANSFORM_MASK) != 0) {
@@ -1171,13 +1161,8 @@
                     mView.mPrivateFlags |= View.PFLAG_DRAWN; // force another invalidation
                 }
             }
-            // invalidate(false) in all cases except if alphaHandled gets set to true
-            // via the call to setAlphaNoInvalidation(), above
-            if (alphaHandled) {
-                mView.invalidate(true);
-            } else {
-                mView.invalidateViewProperty(false, false);
-            }
+
+            mView.invalidateViewProperty(false, false);
             if (mUpdateListener != null) {
                 mUpdateListener.onAnimationUpdate(animation);
             }
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 47528a0..1a782ee 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -95,6 +95,7 @@
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
 import android.view.accessibility.AccessibilityManager.HighTextContrastChangeListener;
+import android.view.accessibility.AccessibilityNodeIdManager;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
 import android.view.accessibility.AccessibilityNodeProvider;
@@ -1602,7 +1603,7 @@
         mSurfaceSession = null;
 
         if (mBoundsSurfaceControl != null) {
-            mBoundsSurfaceControl.destroy();
+            mBoundsSurfaceControl.remove();
             mBoundsSurface.release();
             mBoundsSurfaceControl = null;
         }
@@ -1886,7 +1887,7 @@
                 mLastWindowInsets = mInsetsController.calculateInsets(
                         mContext.getResources().getConfiguration().isScreenRound(),
                         mAttachInfo.mAlwaysConsumeNavBar, displayCutout,
-                        contentInsets, stableInsets);
+                        contentInsets, stableInsets, mWindowAttributes.softInputMode);
             } else {
                 mLastWindowInsets = new WindowInsets(contentInsets, stableInsets,
                         mContext.getResources().getConfiguration().isScreenRound(),
@@ -7954,17 +7955,14 @@
         // Intercept accessibility focus events fired by virtual nodes to keep
         // track of accessibility focus position in such nodes.
         final int eventType = event.getEventType();
+        final View source = getSourceForAccessibilityEvent(event);
         switch (eventType) {
             case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED: {
-                final long sourceNodeId = event.getSourceNodeId();
-                final int accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId(
-                        sourceNodeId);
-                View source = mView.findViewByAccessibilityId(accessibilityViewId);
                 if (source != null) {
                     AccessibilityNodeProvider provider = source.getAccessibilityNodeProvider();
                     if (provider != null) {
                         final int virtualNodeId = AccessibilityNodeInfo.getVirtualDescendantId(
-                                sourceNodeId);
+                                event.getSourceNodeId());
                         final AccessibilityNodeInfo node;
                         node = provider.createAccessibilityNodeInfo(virtualNodeId);
                         setAccessibilityFocus(source, node);
@@ -7972,15 +7970,8 @@
                 }
             } break;
             case AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED: {
-                final long sourceNodeId = event.getSourceNodeId();
-                final int accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId(
-                        sourceNodeId);
-                View source = mView.findViewByAccessibilityId(accessibilityViewId);
-                if (source != null) {
-                    AccessibilityNodeProvider provider = source.getAccessibilityNodeProvider();
-                    if (provider != null) {
-                        setAccessibilityFocus(null, null);
-                    }
+                if (source != null && source.getAccessibilityNodeProvider() != null) {
+                    setAccessibilityFocus(null, null);
                 }
             } break;
 
@@ -7993,6 +7984,13 @@
         return true;
     }
 
+    private View getSourceForAccessibilityEvent(AccessibilityEvent event) {
+        final long sourceNodeId = event.getSourceNodeId();
+        final int accessibilityViewId = AccessibilityNodeInfo.getAccessibilityViewId(
+                sourceNodeId);
+        return AccessibilityNodeIdManager.getInstance().findView(accessibilityViewId);
+    }
+
     /**
      * Updates the focused virtual view, when necessary, in response to a
      * content changed event.
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index 46aea80..e3833c0 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -520,7 +520,7 @@
         return false;
     }
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public void trimMemory(int level) {
         if (ThreadedRenderer.isAvailable()) {
             if (shouldDestroyEglContext(level)) {
diff --git a/core/java/android/view/WindowManagerPolicyConstants.java b/core/java/android/view/WindowManagerPolicyConstants.java
index 16bafe2..35ed7bf 100644
--- a/core/java/android/view/WindowManagerPolicyConstants.java
+++ b/core/java/android/view/WindowManagerPolicyConstants.java
@@ -16,6 +16,11 @@
 
 package android.view;
 
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * Constants for interfacing with WindowManagerService and WindowManagerPolicyInternal.
  * @hide
@@ -89,6 +94,35 @@
     /** Screen turned off because of timeout */
     int OFF_BECAUSE_OF_TIMEOUT = 3;
 
+    @IntDef(prefix = { "ON_BECAUSE_OF_" }, value = {
+            ON_BECAUSE_OF_USER,
+            ON_BECAUSE_OF_APPLICATION,
+            ON_BECAUSE_OF_UNKNOWN,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface OnReason{}
+
+    /** Convert the on reason to a human readable format */
+    static String onReasonToString(@OnReason int why) {
+        switch (why) {
+            case ON_BECAUSE_OF_USER:
+                return "ON_BECAUSE_OF_USER";
+            case ON_BECAUSE_OF_APPLICATION:
+                return "ON_BECAUSE_OF_APPLICATION";
+            case ON_BECAUSE_OF_UNKNOWN:
+                return "ON_BECAUSE_OF_UNKNOWN";
+            default:
+                return Integer.toString(why);
+        }
+    }
+
+    /** Screen turned on because of a user-initiated action. */
+    int ON_BECAUSE_OF_USER = 1;
+    /** Screen turned on because of an application request or event */
+    int ON_BECAUSE_OF_APPLICATION = 2;
+    /** Screen turned on for an unknown reason */
+    int ON_BECAUSE_OF_UNKNOWN = 3;
+
     int APPLICATION_LAYER = 2;
     int APPLICATION_MEDIA_SUBLAYER = -2;
     int APPLICATION_MEDIA_OVERLAY_SUBLAYER = -1;
diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java
index 6aafa34..06207a9 100644
--- a/core/java/android/view/accessibility/AccessibilityManager.java
+++ b/core/java/android/view/accessibility/AccessibilityManager.java
@@ -36,6 +36,7 @@
 import android.content.pm.ServiceInfo;
 import android.content.res.Resources;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -183,7 +184,7 @@
 
     boolean mIsTouchExplorationEnabled;
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768939)
     boolean mIsHighTextContrastEnabled;
 
     AccessibilityPolicy mAccessibilityPolicy;
diff --git a/core/java/android/view/accessibility/AccessibilityNodeIdManager.java b/core/java/android/view/accessibility/AccessibilityNodeIdManager.java
new file mode 100644
index 0000000..1ac7047
--- /dev/null
+++ b/core/java/android/view/accessibility/AccessibilityNodeIdManager.java
@@ -0,0 +1,68 @@
+/*
+ * 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.view.accessibility;
+
+import android.util.SparseArray;
+import android.view.View;
+
+/** @hide */
+public final class AccessibilityNodeIdManager {
+    private SparseArray<View> mIdsToViews = new SparseArray<>();
+    private static AccessibilityNodeIdManager sIdManager;
+
+    /**
+     * Gets singleton.
+     * @return The instance.
+     */
+    public static synchronized AccessibilityNodeIdManager getInstance() {
+        if (sIdManager == null) {
+            sIdManager = new AccessibilityNodeIdManager();
+        }
+        return sIdManager;
+    }
+
+    private AccessibilityNodeIdManager() {
+    }
+
+    /**
+     * Register view to be kept track of by the accessibility system.
+     * Must be paired with unregisterView, otherwise this will leak.
+     * @param view The view to be registered.
+     * @param id The accessibilityViewId of the view.
+     */
+    public void registerViewWithId(View view, int id) {
+        mIdsToViews.append(id, view);
+    }
+
+    /**
+     * Unregister view, accessibility won't keep track of this view after this call.
+     * @param id The id returned from registerView when the view as first associated.
+     */
+    public void unregisterViewWithId(int id) {
+        mIdsToViews.remove(id);
+    }
+
+    /**
+     * Accessibility uses this to find the view in the hierarchy.
+     * @param id The accessibility view id.
+     * @return The view.
+     */
+    public View findView(int id) {
+        final View view = mIdsToViews.get(id);
+        return view != null && view.includeForAccessibility() ? view : null;
+    }
+}
diff --git a/core/java/android/view/animation/Animation.java b/core/java/android/view/animation/Animation.java
index dfd9a2e..e095094 100644
--- a/core/java/android/view/animation/Animation.java
+++ b/core/java/android/view/animation/Animation.java
@@ -23,6 +23,7 @@
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.RectF;
+import android.os.Build;
 import android.os.Handler;
 import android.os.SystemProperties;
 import android.util.AttributeSet;
@@ -30,9 +31,6 @@
 
 import dalvik.system.CloseGuard;
 
-import java.util.ArrayList;
-import java.util.List;
-
 /**
  * Abstraction for an Animation that can be applied to Views, Surfaces, or
  * other objects. See the {@link android.view.animation animation package
@@ -187,15 +185,12 @@
     /**
      * An animation listener to be notified when the animation starts, ends or repeats.
      */
-    @UnsupportedAppUsage
+    // If you need to chain the AnimationListener, wrap the existing Animation into an AnimationSet
+    // and add your new listener to that set
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 117519981)
     private AnimationListener mListener;
 
     /**
-     * A list of animation listeners to be notified when the animation starts, ends or repeats.
-     */
-    private List<AnimationListener> mListeners;
-
-    /**
      * Desired Z order mode during animation.
      */
     private int mZAdjustment;
@@ -833,7 +828,7 @@
     }
 
     private boolean hasAnimationListener() {
-        return mListener != null || (mListeners != null && !mListeners.isEmpty());
+        return mListener != null;
     }
 
     /**
@@ -848,32 +843,6 @@
     }
 
     /**
-     * <p>Adds an animation listener to this animation. The animation listener
-     * is notified of animation events such as the end of the animation or the
-     * repetition of the animation.</p>
-     *
-     * @param listener the animation listener to be notified
-     */
-    public void addAnimationListener(AnimationListener listener) {
-        if (mListeners == null) {
-            mListeners = new ArrayList<>(1);
-        }
-        mListeners.add(listener);
-    }
-
-    /**
-     * <p>Removes an animation listener that has been added with
-     * {@link #addAnimationListener(AnimationListener)}.</p>
-     *
-     * @param listener the animation listener to be removed
-     */
-    public void removeAnimationListener(AnimationListener listener) {
-        if (mListeners != null) {
-            mListeners.remove(listener);
-        }
-    }
-
-    /**
      * Gurantees that this animation has an interpolator. Will use
      * a AccelerateDecelerateInterpolator is nothing else was specified.
      */
@@ -1003,33 +972,18 @@
         if (mListener != null) {
             mListener.onAnimationStart(this);
         }
-        if (mListeners != null && !mListeners.isEmpty()) {
-            for (AnimationListener listener : mListeners) {
-                listener.onAnimationStart(this);
-            }
-        }
     }
 
     void dispatchAnimationRepeat() {
         if (mListener != null) {
             mListener.onAnimationRepeat(this);
         }
-        if (mListeners != null && !mListeners.isEmpty()) {
-            for (AnimationListener listener : mListeners) {
-                listener.onAnimationRepeat(this);
-            }
-        }
     }
 
     void dispatchAnimationEnd() {
         if (mListener != null) {
             mListener.onAnimationEnd(this);
         }
-        if (mListeners != null && !mListeners.isEmpty()) {
-            for (AnimationListener listener : mListeners) {
-                listener.onAnimationEnd(this);
-            }
-        }
     }
 
     /**
diff --git a/core/java/android/view/autofill/AutofillId.java b/core/java/android/view/autofill/AutofillId.java
index f1c7b69..5608bb3 100644
--- a/core/java/android/view/autofill/AutofillId.java
+++ b/core/java/android/view/autofill/AutofillId.java
@@ -52,11 +52,13 @@
     }
 
     /** @hide */
+    @TestApi
     public AutofillId(int parentId, int virtualChildId) {
         this(FLAG_IS_VIRTUAL_INT, parentId, virtualChildId, NO_SESSION);
     }
 
     /** @hide */
+    @TestApi
     public AutofillId(@NonNull AutofillId parent, long virtualChildId, int sessionId) {
         this(FLAG_IS_VIRTUAL_LONG | FLAG_HAS_SESSION, parent.mViewId, virtualChildId, sessionId);
     }
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 1c96b87..83fc0173 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -346,9 +346,6 @@
     @TestApi
     public static final int FLAG_SMART_SUGGESTION_SYSTEM = 0x1;
 
-    /** @hide */ // TODO(b/123233342): remove when not used anymore
-    public static final int FLAG_SMART_SUGGESTION_LEGACY = 0x2;
-
     /** @hide */
     @IntDef(flag = true, prefix = { "FLAG_SMART_SUGGESTION_" }, value = {
             FLAG_SMART_SUGGESTION_SYSTEM
diff --git a/core/java/android/view/contentcapture/ContentCaptureEvent.java b/core/java/android/view/contentcapture/ContentCaptureEvent.java
index dfac35d..22254cd 100644
--- a/core/java/android/view/contentcapture/ContentCaptureEvent.java
+++ b/core/java/android/view/contentcapture/ContentCaptureEvent.java
@@ -138,8 +138,11 @@
 
     /**
      * Adds an autofill id to the this event, merging the single id into a list if necessary.
-     * @hide */
+     *
+     * @hide
+     */
     public ContentCaptureEvent addAutofillId(@NonNull AutofillId id) {
+        Preconditions.checkNotNull(id);
         if (mIds == null) {
             mIds = new ArrayList<>();
             if (mId == null) {
diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
index 2512b95..634443d 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -66,6 +66,25 @@
      */
     private static final int SYNC_CALLS_TIMEOUT_MS = 5000;
 
+    /**
+     * DeviceConfig property used by {@code com.android.server.SystemServer} on start to decide
+     * whether the Content Capture service should be created or not
+     *
+     * <p>By default it should *NOT* be set (or set to {@code "default"}, so the decision is based
+     * on whether the OEM provides an implementation for the service), but it can be overridden to:
+     *
+     * <ul>
+     *   <li>Provide a "kill switch" so OEMs can disable it remotely in case of emergency (when
+     *   it's set to {@code "false"}).
+     *   <li>Enable the CTS tests to be run on AOSP builds (when it's set to {@code "true"}).
+     * </ul>
+     *
+     * @hide
+     */
+    @TestApi
+    public static final String DEVICE_CONFIG_PROPERTY_SERVICE_EXPLICITLY_ENABLED =
+            "service_explicitly_enabled";
+
     private final Object mLock = new Object();
 
     @NonNull
diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java
index eb945b5..810c967 100644
--- a/core/java/android/view/contentcapture/MainContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java
@@ -303,6 +303,7 @@
                     Log.v(TAG, "Buffering VIEW_TEXT_CHANGED event, updated text="
                             + getSanitizedString(event.getText()));
                 }
+                // TODO(b/124107816): should call lastEvent.merge(event) instead
                 lastEvent.setText(event.getText());
                 addEvent = false;
             }
@@ -316,7 +317,7 @@
                     Log.v(TAG, "Buffering TYPE_VIEW_DISAPPEARED events for session "
                             + lastEvent.getSessionId());
                 }
-                lastEvent.addAutofillId(event.getId());
+                mergeViewsDisappearedEvent(lastEvent, event);
                 addEvent = false;
             }
         }
@@ -364,6 +365,30 @@
         flush(flushReason);
     }
 
+    // TODO(b/124107816): should be ContentCaptureEvent Event.merge(event) instead (which would
+    // replace the addAutofillId() method - we would also need unit tests on ContentCaptureEventTest
+    // to check these scenarios)
+    private void mergeViewsDisappearedEvent(@NonNull ContentCaptureEvent lastEvent,
+            @NonNull ContentCaptureEvent event) {
+        final List<AutofillId> ids = event.getIds();
+        final AutofillId id = event.getId();
+        if (ids != null) {
+            if (id != null) {
+                Log.w(TAG, "got TYPE_VIEW_DISAPPEARED event with both id and ids: " + event);
+            }
+            for (int i = 0; i < ids.size(); i++) {
+                lastEvent.addAutofillId(ids.get(i));
+            }
+            return;
+        }
+        if (id != null) {
+            lastEvent.addAutofillId(id);
+            return;
+        }
+        throw new IllegalArgumentException(
+                "got TYPE_VIEW_DISAPPEARED event with neither id or ids: " + event);
+    }
+
     @UiThread
     private boolean hasStarted() {
         return mState != UNKNOWN_STATE;
diff --git a/core/java/android/view/contentcapture/ViewNode.java b/core/java/android/view/contentcapture/ViewNode.java
index eef841d..8d62454 100644
--- a/core/java/android/view/contentcapture/ViewNode.java
+++ b/core/java/android/view/contentcapture/ViewNode.java
@@ -34,7 +34,6 @@
 import android.view.autofill.AutofillId;
 import android.view.autofill.AutofillValue;
 
-import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.Preconditions;
 
 //TODO(b/122484602): add javadocs / implement Parcelable / implement
@@ -589,6 +588,7 @@
     }
 
     /** @hide */
+    @TestApi
     public static void writeToParcel(@NonNull Parcel parcel, @Nullable ViewNode node, int flags) {
         if (node == null) {
             parcel.writeLong(0);
@@ -598,18 +598,20 @@
     }
 
     /** @hide */
+    @TestApi
     public static @Nullable ViewNode readFromParcel(@NonNull Parcel parcel) {
         final long nodeFlags = parcel.readLong();
-        return nodeFlags == 0 ? new ViewNode() : new ViewNode(nodeFlags, parcel);
+        return nodeFlags == 0 ? null : new ViewNode(nodeFlags, parcel);
     }
 
     /** @hide */
-    @VisibleForTesting // Must be public to be accessed from FrameworkCoreTests' apk.
+    @TestApi
     public static final class ViewStructureImpl extends ViewStructure {
 
         final ViewNode mNode = new ViewNode();
 
-        @VisibleForTesting // Must be public to be accessed from FrameworkCoreTests' apk.
+        /** @hide */
+        @TestApi
         public ViewStructureImpl(@NonNull View view) {
             mNode.mAutofillId = Preconditions.checkNotNull(view).getAutofillId();
             final ViewParent parent = view.getParent();
@@ -618,13 +620,15 @@
             }
         }
 
-        @VisibleForTesting // Must be public to be accessed from FrameworkCoreTests' apk.
+        /** @hide */
+        @TestApi
         public ViewStructureImpl(@NonNull AutofillId parentId, long virtualId, int sessionId) {
             mNode.mParentAutofillId = Preconditions.checkNotNull(parentId);
             mNode.mAutofillId = new AutofillId(parentId, virtualId, sessionId);
         }
 
-        @VisibleForTesting // Must be public to be accessed from FrameworkCoreTests' apk.
+        /** @hide */
+        @TestApi
         public ViewNode getNode() {
             return mNode;
         }
diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java
index aee4b1f..8a09788 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -339,7 +339,11 @@
 
     // For scheduling work on the main thread.  This also serves as our
     // global lock.
-    @UnsupportedAppUsage
+    // Remark on @UnsupportedAppUsage: there were context leaks on old versions
+    // of android (b/37043700), so developers used this field to perform manual clean up.
+    // Leaks were fixed, hacks were backported to AppCompatActivity,
+    // so an access to the field is closed.
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     final H mH;
 
     // Our generic input connection if the current target does not have its own.
@@ -375,13 +379,15 @@
      * This is the view that should currently be served by an input method,
      * regardless of the state of setting that up.
      */
-    @UnsupportedAppUsage
+    // See comment to mH field in regard to @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     View mServedView;
     /**
      * This is then next view that will be served by the input method, when
      * we get around to updating things.
      */
-    @UnsupportedAppUsage
+    // See comment to mH field in regard to @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     View mNextServedView;
     /**
      * This is set when we are in the process of connecting, to determine
diff --git a/core/java/android/view/textclassifier/ConversationAction.java b/core/java/android/view/textclassifier/ConversationAction.java
index 1a6e5d8..ae6a645 100644
--- a/core/java/android/view/textclassifier/ConversationAction.java
+++ b/core/java/android/view/textclassifier/ConversationAction.java
@@ -92,6 +92,9 @@
      */
     public static final String TYPE_SHARE_LOCATION = "share_location";
 
+    /** @hide **/
+    public static final String TYPE_ADD_CONTACT = "add_contact";
+
     public static final Creator<ConversationAction> CREATOR =
             new Creator<ConversationAction>() {
                 @Override
diff --git a/core/java/android/view/textclassifier/ExtrasUtils.java b/core/java/android/view/textclassifier/ExtrasUtils.java
index 602455c..b0e7ad5 100644
--- a/core/java/android/view/textclassifier/ExtrasUtils.java
+++ b/core/java/android/view/textclassifier/ExtrasUtils.java
@@ -85,15 +85,16 @@
     }
 
     /**
-     * Returns the first "translate" action found in the {@code classification} object.
+     * Returns the first action found in the {@code classification} object with an intent
+     * action string, {@code intentAction}.
      */
     @Nullable
-    public static RemoteAction findTranslateAction(TextClassification classification) {
+    public static RemoteAction findAction(TextClassification classification, String intentAction) {
         final ArrayList<Intent> actionIntents = getActionsIntents(classification);
         if (actionIntents != null) {
             final int size = actionIntents.size();
             for (int i = 0; i < size; i++) {
-                if (Intent.ACTION_TRANSLATE.equals(actionIntents.get(i).getAction())) {
+                if (intentAction.equals(actionIntents.get(i).getAction())) {
                     return classification.getActions().get(i);
                 }
             }
@@ -102,6 +103,14 @@
     }
 
     /**
+     * Returns the first "translate" action found in the {@code classification} object.
+     */
+    @Nullable
+    public static RemoteAction findTranslateAction(TextClassification classification) {
+        return findAction(classification, Intent.ACTION_TRANSLATE);
+    }
+
+    /**
      * Returns the entity type contained in the {@code extra}.
      */
     @Nullable
diff --git a/core/java/android/view/textclassifier/LegacyIntentFactory.java b/core/java/android/view/textclassifier/LegacyIntentFactory.java
index b6e5b3e2..2d0d032 100644
--- a/core/java/android/view/textclassifier/LegacyIntentFactory.java
+++ b/core/java/android/view/textclassifier/LegacyIntentFactory.java
@@ -182,7 +182,8 @@
         actions.add(new LabeledIntent(
                 context.getString(com.android.internal.R.string.browse),
                 context.getString(com.android.internal.R.string.browse_desc),
-                new Intent(Intent.ACTION_VIEW, Uri.parse(text))
+                new Intent(Intent.ACTION_VIEW)
+                        .setDataAndNormalize(Uri.parse(text))
                         .putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName()),
                 LabeledIntent.DEFAULT_REQUEST_CODE));
         return actions;
diff --git a/core/java/android/view/textclassifier/TemplateIntentFactory.java b/core/java/android/view/textclassifier/TemplateIntentFactory.java
index 5278843..95f88c7 100644
--- a/core/java/android/view/textclassifier/TemplateIntentFactory.java
+++ b/core/java/android/view/textclassifier/TemplateIntentFactory.java
@@ -49,20 +49,18 @@
         }
         final List<TextClassifierImpl.LabeledIntent> labeledIntents = new ArrayList<>();
         for (RemoteActionTemplate remoteActionTemplate : remoteActionTemplates) {
-            Intent intent = createIntent(remoteActionTemplate);
-            if (intent == null) {
+            if (!isValidTemplate(remoteActionTemplate)) {
+                Log.w(TAG, "Invalid RemoteActionTemplate skipped.");
                 continue;
             }
-            TextClassifierImpl.LabeledIntent
-                    labeledIntent = new TextClassifierImpl.LabeledIntent(
-                    remoteActionTemplate.title,
-                    remoteActionTemplate.description,
-                    intent,
-                    remoteActionTemplate.requestCode == null
-                            ? TextClassifierImpl.LabeledIntent.DEFAULT_REQUEST_CODE
-                            : remoteActionTemplate.requestCode
-            );
-            labeledIntents.add(labeledIntent);
+            labeledIntents.add(
+                    new TextClassifierImpl.LabeledIntent(
+                            remoteActionTemplate.title,
+                            remoteActionTemplate.description,
+                            createIntent(remoteActionTemplate),
+                            remoteActionTemplate.requestCode == null
+                                    ? TextClassifierImpl.LabeledIntent.DEFAULT_REQUEST_CODE
+                                    : remoteActionTemplate.requestCode));
         }
         labeledIntents.forEach(
                 action -> action.getIntent()
@@ -70,29 +68,43 @@
         return labeledIntents;
     }
 
-    @Nullable
-    private static Intent createIntent(RemoteActionTemplate remoteActionTemplate) {
-        Intent intent = new Intent();
+    private static boolean isValidTemplate(@Nullable RemoteActionTemplate remoteActionTemplate) {
+        if (remoteActionTemplate == null) {
+            Log.w(TAG, "Invalid RemoteActionTemplate: is null");
+            return false;
+        }
+        if (TextUtils.isEmpty(remoteActionTemplate.title)) {
+            Log.w(TAG, "Invalid RemoteActionTemplate: title is null");
+            return false;
+        }
+        if (TextUtils.isEmpty(remoteActionTemplate.description)) {
+            Log.w(TAG, "Invalid RemoteActionTemplate: description is null");
+            return false;
+        }
         if (!TextUtils.isEmpty(remoteActionTemplate.packageName)) {
-            Log.w(TAG, "A RemoteActionTemplate is skipped as package name is set.");
-            return null;
+            Log.w(TAG, "Invalid RemoteActionTemplate: package name is set");
+            return false;
         }
-        if (!TextUtils.isEmpty(remoteActionTemplate.action)) {
-            intent.setAction(remoteActionTemplate.action);
+        if (TextUtils.isEmpty(remoteActionTemplate.action)) {
+            Log.w(TAG, "Invalid RemoteActionTemplate: intent action not set");
+            return false;
         }
-        Uri data = null;
-        if (!TextUtils.isEmpty(remoteActionTemplate.data)) {
-            data = Uri.parse(remoteActionTemplate.data);
-        }
-        if (data != null || !TextUtils.isEmpty(remoteActionTemplate.type)) {
-            intent.setDataAndType(data, remoteActionTemplate.type);
-        }
-        if (remoteActionTemplate.flags != null) {
-            intent.setFlags(remoteActionTemplate.flags);
-        }
+        return true;
+    }
+
+    private static Intent createIntent(RemoteActionTemplate remoteActionTemplate) {
+        final Intent intent = new Intent(remoteActionTemplate.action);
+        final Uri uri = TextUtils.isEmpty(remoteActionTemplate.data)
+                ? null : Uri.parse(remoteActionTemplate.data).normalizeScheme();
+        final String type = TextUtils.isEmpty(remoteActionTemplate.type)
+                ? null : Intent.normalizeMimeType(remoteActionTemplate.type);
+        intent.setDataAndType(uri, type);
+        intent.setFlags(remoteActionTemplate.flags == null ? 0 : remoteActionTemplate.flags);
         if (remoteActionTemplate.category != null) {
             for (String category : remoteActionTemplate.category) {
-                intent.addCategory(category);
+                if (category != null) {
+                    intent.addCategory(category);
+                }
             }
         }
         intent.putExtras(createExtras(remoteActionTemplate.extras));
@@ -105,6 +117,9 @@
         }
         Bundle bundle = new Bundle();
         for (NamedVariant namedVariant : namedVariants) {
+            if (namedVariant == null) {
+                continue;
+            }
             switch (namedVariant.getType()) {
                 case NamedVariant.TYPE_INT:
                     bundle.putInt(namedVariant.getName(), namedVariant.getInt());
diff --git a/core/java/android/view/textclassifier/TextClassificationConstants.java b/core/java/android/view/textclassifier/TextClassificationConstants.java
index ee9e04e..2ef8d04 100644
--- a/core/java/android/view/textclassifier/TextClassificationConstants.java
+++ b/core/java/android/view/textclassifier/TextClassificationConstants.java
@@ -131,6 +131,7 @@
                     .add(ConversationAction.TYPE_TRACK_FLIGHT)
                     .add(ConversationAction.TYPE_VIEW_CALENDAR)
                     .add(ConversationAction.TYPE_VIEW_MAP)
+                    .add(ConversationAction.TYPE_ADD_CONTACT)
                     .toString();
     /**
      * < 0  : Not set. Use value from LangId model.
diff --git a/core/java/android/webkit/OWNERS b/core/java/android/webkit/OWNERS
index 00e540a..b33da57 100644
--- a/core/java/android/webkit/OWNERS
+++ b/core/java/android/webkit/OWNERS
@@ -1,3 +1,4 @@
 changwan@google.com
+ntfschr@google.com
 tobiasjs@google.com
 torne@google.com
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index 6039350..2171fc5 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -61,6 +61,7 @@
 import android.view.autofill.AutofillValue;
 import android.view.inputmethod.EditorInfo;
 import android.view.inputmethod.InputConnection;
+import android.view.inspector.InspectableProperty;
 import android.view.textclassifier.TextClassifier;
 import android.widget.AbsoluteLayout;
 
@@ -1239,6 +1240,7 @@
      *
      * @return the URL for the current page
      */
+    @InspectableProperty(hasAttributeId = false)
     @ViewDebug.ExportedProperty(category = "webview")
     public String getUrl() {
         checkThread();
@@ -1254,6 +1256,7 @@
      *
      * @return the URL that was originally requested for the current page
      */
+    @InspectableProperty(hasAttributeId = false)
     @ViewDebug.ExportedProperty(category = "webview")
     public String getOriginalUrl() {
         checkThread();
@@ -1266,6 +1269,7 @@
      *
      * @return the title for the current page
      */
+    @InspectableProperty(hasAttributeId = false)
     @ViewDebug.ExportedProperty(category = "webview")
     public String getTitle() {
         checkThread();
@@ -1278,6 +1282,7 @@
      *
      * @return the favicon for the current page
      */
+    @InspectableProperty(hasAttributeId = false)
     public Bitmap getFavicon() {
         checkThread();
         return mProvider.getFavicon();
@@ -1300,6 +1305,7 @@
      *
      * @return the progress for the current page between 0 and 100
      */
+    @InspectableProperty(hasAttributeId = false)
     public int getProgress() {
         checkThread();
         return mProvider.getProgress();
@@ -1310,6 +1316,7 @@
      *
      * @return the height of the HTML content
      */
+    @InspectableProperty(hasAttributeId = false)
     @ViewDebug.ExportedProperty(category = "webview")
     public int getContentHeight() {
         checkThread();
@@ -2276,6 +2283,11 @@
      *
      * @return the requested renderer priority policy.
      */
+    @InspectableProperty(hasAttributeId = false, enumMapping = {
+            @InspectableProperty.EnumMap(name = "waived", value = RENDERER_PRIORITY_WAIVED),
+            @InspectableProperty.EnumMap(name = "bound", value = RENDERER_PRIORITY_BOUND),
+            @InspectableProperty.EnumMap(name = "important", value = RENDERER_PRIORITY_IMPORTANT)
+    })
     @RendererPriority
     public int getRendererRequestedPriority() {
         return mProvider.getRendererRequestedPriority();
@@ -2288,6 +2300,7 @@
      * @return whether this WebView requests a priority of
      * {@link #RENDERER_PRIORITY_WAIVED} when not visible.
      */
+    @InspectableProperty(hasAttributeId = false)
     public boolean getRendererPriorityWaivedWhenNotVisible() {
         return mProvider.getRendererPriorityWaivedWhenNotVisible();
     }
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 4dd7d3a..9d7a482 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -338,7 +338,7 @@
      * The data set used to store unused views that should be reused during the next layout
      * to avoid creating new ones
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769398)
     final RecycleBin mRecycler = new RecycleBin();
 
     /**
@@ -421,7 +421,7 @@
      * One of TOUCH_MODE_REST, TOUCH_MODE_DOWN, TOUCH_MODE_TAP, TOUCH_MODE_SCROLL, or
      * TOUCH_MODE_DONE_WAITING
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769413)
     int mTouchMode = TOUCH_MODE_REST;
 
     /**
@@ -442,8 +442,10 @@
 
     /**
      * Handles one frame of a fling
+     *
+     * To interrupt a fling early you should use smoothScrollBy(0,0) instead
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     private FlingRunnable mFlingRunnable;
 
     /**
@@ -483,7 +485,7 @@
     /**
      * Optional callback to notify client when scroll position has changed
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769353)
     private OnScrollListener mOnScrollListener;
 
     /**
@@ -632,7 +634,7 @@
     /**
      * Helper object that renders and controls the fast scroll thumb.
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768941)
     private FastScroller mFastScroll;
 
     /**
@@ -698,7 +700,7 @@
     /**
      * Maximum distance to overfling during edge effects
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769379)
     int mOverflingDistance;
 
     // These two EdgeGlows are always set and used together.
@@ -706,15 +708,23 @@
 
     /**
      * Tracks the state of the top edge glow.
+     *
+     * Even though this field is practically final, we cannot make it final because there are apps
+     * setting it via reflection and they need to keep working until they target Q.
      */
-    @UnsupportedAppUsage
-    private EdgeEffect mEdgeGlowTop;
+    @NonNull
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769408)
+    private EdgeEffect mEdgeGlowTop = new EdgeEffect(mContext);
 
     /**
      * Tracks the state of the bottom edge glow.
+     *
+     * Even though this field is practically final, we cannot make it final because there are apps
+     * setting it via reflection and they need to keep working until they target Q.
      */
-    @UnsupportedAppUsage
-    private EdgeEffect mEdgeGlowBottom;
+    @NonNull
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768444)
+    private EdgeEffect mEdgeGlowBottom = new EdgeEffect(mContext);
 
     /**
      * An estimate of how many pixels are between the top of the list and
@@ -921,21 +931,6 @@
         mDensityScale = getContext().getResources().getDisplayMetrics().density;
     }
 
-    @Override
-    public void setOverScrollMode(int mode) {
-        if (mode != OVER_SCROLL_NEVER) {
-            if (mEdgeGlowTop == null) {
-                Context context = getContext();
-                mEdgeGlowTop = new EdgeEffect(context);
-                mEdgeGlowBottom = new EdgeEffect(context);
-            }
-        } else {
-            mEdgeGlowTop = null;
-            mEdgeGlowBottom = null;
-        }
-        super.setOverScrollMode(mode);
-    }
-
     /**
      * {@inheritDoc}
      */
@@ -1611,15 +1606,6 @@
         return false;
     }
 
-    /** @hide */
-    @Override
-    public View findViewByAccessibilityIdTraversal(int accessibilityId) {
-        if (accessibilityId == getAccessibilityViewId()) {
-            return this;
-        }
-        return super.findViewByAccessibilityIdTraversal(accessibilityId);
-    }
-
     /**
      * Indicates whether the children's drawing cache is used during a scroll.
      * By default, the drawing cache is enabled but this will consume more memory.
@@ -3779,7 +3765,7 @@
     }
 
     private void invalidateTopGlow() {
-        if (mEdgeGlowTop == null) {
+        if (!shouldDisplayEdgeEffects()) {
             return;
         }
         final boolean clipToPadding = getClipToPadding();
@@ -3790,7 +3776,7 @@
     }
 
     private void invalidateBottomGlow() {
-        if (mEdgeGlowBottom == null) {
+        if (!shouldDisplayEdgeEffects()) {
             return;
         }
         final boolean clipToPadding = getClipToPadding();
@@ -4215,7 +4201,7 @@
 
         setPressed(false);
 
-        if (mEdgeGlowTop != null) {
+        if (shouldDisplayEdgeEffects()) {
             mEdgeGlowTop.onRelease();
             mEdgeGlowBottom.onRelease();
         }
@@ -4240,6 +4226,10 @@
         }
     }
 
+    private boolean shouldDisplayEdgeEffects() {
+        return getOverScrollMode() != OVER_SCROLL_NEVER;
+    }
+
     private void onTouchCancel() {
         switch (mTouchMode) {
         case TOUCH_MODE_OVERSCROLL:
@@ -4265,7 +4255,7 @@
             recycleVelocityTracker();
         }
 
-        if (mEdgeGlowTop != null) {
+        if (shouldDisplayEdgeEffects()) {
             mEdgeGlowTop.onRelease();
             mEdgeGlowBottom.onRelease();
         }
@@ -4386,7 +4376,7 @@
     @Override
     public void draw(Canvas canvas) {
         super.draw(canvas);
-        if (mEdgeGlowTop != null) {
+        if (shouldDisplayEdgeEffects()) {
             final int scrollY = mScrollY;
             final boolean clipToPadding = getClipToPadding();
             final int width;
@@ -4623,7 +4613,7 @@
      *
      * @param newState The new scroll state.
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769710)
     void reportScrollStateChange(int newState) {
         if (newState != mLastScrollState) {
             if (mOnScrollListener != null) {
@@ -4688,7 +4678,8 @@
             mScroller = new OverScroller(getContext());
         }
 
-        @UnsupportedAppUsage
+        // Use AbsListView#fling(int) instead
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
         void start(int initialVelocity) {
             int initialY = initialVelocity < 0 ? Integer.MAX_VALUE : 0;
             mLastFlingY = initialY;
@@ -4766,7 +4757,8 @@
             postOnAnimation(this);
         }
 
-        @UnsupportedAppUsage
+        // To interrupt a fling early you should use smoothScrollBy(0,0) instead
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
         void endFling() {
             mTouchMode = TOUCH_MODE_REST;
 
@@ -5164,7 +5156,7 @@
      * @param incrementalDeltaY Change in deltaY from the previous event.
      * @return true if we're already at the beginning/end of the list and have nothing to do.
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124051739)
     boolean trackMotionScroll(int deltaY, int incrementalDeltaY) {
         final int childCount = getChildCount();
         if (childCount == 0) {
@@ -6376,7 +6368,7 @@
     }
 
     private void finishGlows() {
-        if (mEdgeGlowTop != null) {
+        if (shouldDisplayEdgeEffects()) {
             mEdgeGlowTop.finish();
             mEdgeGlowBottom.finish();
         }
@@ -6483,6 +6475,76 @@
     }
 
     /**
+     * Sets the edge effect color for both top and bottom edge effects.
+     *
+     * @param color The color for the edge effects.
+     * @see #setTopEdgeEffectColor(int)
+     * @see #setBottomEdgeEffectColor(int)
+     * @see #getTopEdgeEffectColor()
+     * @see #getBottomEdgeEffectColor()
+     */
+    public void setEdgeEffectColor(@ColorInt int color) {
+        setTopEdgeEffectColor(color);
+        setBottomEdgeEffectColor(color);
+    }
+
+    /**
+     * Sets the bottom edge effect color.
+     *
+     * @param color The color for the bottom edge effect.
+     * @see #setTopEdgeEffectColor(int)
+     * @see #setEdgeEffectColor(int)
+     * @see #getTopEdgeEffectColor()
+     * @see #getBottomEdgeEffectColor()
+     */
+    public void setBottomEdgeEffectColor(@ColorInt int color) {
+        mEdgeGlowBottom.setColor(color);
+        invalidateBottomGlow();
+    }
+
+    /**
+     * Sets the top edge effect color.
+     *
+     * @param color The color for the top edge effect.
+     * @see #setBottomEdgeEffectColor(int)
+     * @see #setEdgeEffectColor(int)
+     * @see #getTopEdgeEffectColor()
+     * @see #getBottomEdgeEffectColor()
+     */
+    public void setTopEdgeEffectColor(@ColorInt int color) {
+        mEdgeGlowTop.setColor(color);
+        invalidateTopGlow();
+    }
+
+    /**
+     * Returns the top edge effect color.
+     *
+     * @return The top edge effect color.
+     * @see #setEdgeEffectColor(int)
+     * @see #setTopEdgeEffectColor(int)
+     * @see #setBottomEdgeEffectColor(int)
+     * @see #getBottomEdgeEffectColor()
+     */
+    @ColorInt
+    public int getTopEdgeEffectColor() {
+        return mEdgeGlowTop.getColor();
+    }
+
+    /**
+     * Returns the bottom edge effect color.
+     *
+     * @return The bottom edge effect color.
+     * @see #setEdgeEffectColor(int)
+     * @see #setTopEdgeEffectColor(int)
+     * @see #setBottomEdgeEffectColor(int)
+     * @see #getTopEdgeEffectColor()
+     */
+    @ColorInt
+    public int getBottomEdgeEffectColor() {
+        return mEdgeGlowBottom.getColor();
+    }
+
+    /**
      * Sets the recycler listener to be notified whenever a View is set aside in
      * the recycler for later reuse. This listener can be used to free resources
      * associated to the View.
diff --git a/core/java/android/widget/AdapterView.java b/core/java/android/widget/AdapterView.java
index ddff858..c55f7d6 100644
--- a/core/java/android/widget/AdapterView.java
+++ b/core/java/android/widget/AdapterView.java
@@ -21,6 +21,7 @@
 import android.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.database.DataSetObserver;
+import android.os.Build;
 import android.os.Parcelable;
 import android.os.SystemClock;
 import android.util.AttributeSet;
@@ -152,7 +153,7 @@
     /**
      * True if the data has changed since the last layout
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123768524)
     boolean mDataChanged;
 
     /**
diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java
index 9bc055e..7ed7aa2 100644
--- a/core/java/android/widget/AutoCompleteTextView.java
+++ b/core/java/android/widget/AutoCompleteTextView.java
@@ -126,7 +126,7 @@
     private boolean mDropDownDismissedOnCompletion = true;
 
     private int mLastKeyCode = KeyEvent.KEYCODE_UNKNOWN;
-    private boolean mOpenBefore;
+    private MyWatcher mAutoCompleteTextWatcher;
 
     private Validator mValidator = null;
 
@@ -302,7 +302,8 @@
 
         setFocusable(true);
 
-        addTextChangedListener(new MyWatcher());
+        mAutoCompleteTextWatcher = new MyWatcher();
+        addTextChangedListener(mAutoCompleteTextWatcher);
 
         mPassThroughClickListener = new PassThroughClickListener();
         super.setOnClickListener(mPassThroughClickListener);
@@ -872,45 +873,66 @@
         return getText().length() >= mThreshold;
     }
 
-    /**
-     * This is used to watch for edits to the text view.  Note that we call
-     * to methods on the auto complete text view class so that we can access
-     * private vars without going through thunks.
-     */
+
+
+    /** This is used to watch for edits to the text view. */
     private class MyWatcher implements TextWatcher {
-        public void afterTextChanged(Editable s) {
-            doAfterTextChanged();
-        }
+        private boolean mOpenBefore;
+
         public void beforeTextChanged(CharSequence s, int start, int count, int after) {
-            doBeforeTextChanged();
+            if (mBlockCompletion) return;
+
+            // when text is changed, inserted or deleted, we attempt to show
+            // the drop down
+            mOpenBefore = isPopupShowing();
+            if (DEBUG) Log.v(TAG, "before text changed: open=" + mOpenBefore);
         }
+
+        public void afterTextChanged(Editable s) {
+            if (mBlockCompletion) return;
+
+            // if the list was open before the keystroke, but closed afterwards,
+            // then something in the keystroke processing (an input filter perhaps)
+            // called performCompletion() and we shouldn't do any more processing.
+            if (DEBUG) {
+                Log.v(TAG, "after text changed: openBefore=" + mOpenBefore
+                        + " open=" + isPopupShowing());
+            }
+
+            if (mOpenBefore && !isPopupShowing()) return;
+
+            refreshAutoCompleteResults();
+        }
+
         public void onTextChanged(CharSequence s, int start, int before, int count) {
         }
     }
 
-    @UnsupportedAppUsage
+    /**
+     * This function is deprecated. Please use {@link #refreshAutoCompleteResults} instead.
+     * Note: Remove {@link #mAutoCompleteTextWatcher} after removing this function.
+     */
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     void doBeforeTextChanged() {
-        if (mBlockCompletion) return;
-
-        // when text is changed, inserted or deleted, we attempt to show
-        // the drop down
-        mOpenBefore = isPopupShowing();
-        if (DEBUG) Log.v(TAG, "before text changed: open=" + mOpenBefore);
+        mAutoCompleteTextWatcher.beforeTextChanged(null, 0, 0, 0);
     }
 
-    @UnsupportedAppUsage
+    /**
+     * This function is deprecated. Please use {@link #refreshAutoCompleteResults} instead.
+     * Note: Remove {@link #mAutoCompleteTextWatcher} after removing this function.
+     */
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     void doAfterTextChanged() {
-        if (mBlockCompletion) return;
+        mAutoCompleteTextWatcher.afterTextChanged(null);
+    }
 
-        // if the list was open before the keystroke, but closed afterwards,
-        // then something in the keystroke processing (an input filter perhaps)
-        // called performCompletion() and we shouldn't do any more processing.
-        if (DEBUG) Log.v(TAG, "after text changed: openBefore=" + mOpenBefore
-                + " open=" + isPopupShowing());
-        if (mOpenBefore && !isPopupShowing()) {
-            return;
-        }
-
+    /**
+     * Refreshes the auto complete results. You usually shouldn't have to manually refresh the
+     * AutoCompleteResults as this is done automatically whenever the text changes. However if the
+     * results are not available and have to be fetched, you can call this function after fetching
+     * the results.
+     */
+    public final void refreshAutoCompleteResults() {
         // the drop down is shown only when a minimum number of characters
         // was typed in the text view
         if (enoughToFilter()) {
diff --git a/core/java/android/widget/EdgeEffect.java b/core/java/android/widget/EdgeEffect.java
index 7e42862..fa0af78 100644
--- a/core/java/android/widget/EdgeEffect.java
+++ b/core/java/android/widget/EdgeEffect.java
@@ -17,14 +17,15 @@
 package android.widget;
 
 import android.annotation.ColorInt;
+import android.annotation.Nullable;
 import android.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.TypedArray;
+import android.graphics.BlendMode;
 import android.graphics.Canvas;
 import android.graphics.Paint;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffXfermode;
 import android.graphics.Rect;
+import android.os.Build;
 import android.view.animation.AnimationUtils;
 import android.view.animation.DecelerateInterpolator;
 import android.view.animation.Interpolator;
@@ -48,6 +49,12 @@
  * {@link #draw(Canvas)} method.</p>
  */
 public class EdgeEffect {
+
+    /**
+     * The default blend mode used by {@link EdgeEffect}.
+     */
+    public static final BlendMode DEFAULT_BLEND_MODE = BlendMode.SRC_ATOP;
+
     @SuppressWarnings("UnusedDeclaration")
     private static final String TAG = "EdgeEffect";
 
@@ -108,7 +115,7 @@
     private float mPullDistance;
 
     private final Rect mBounds = new Rect();
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769450)
     private final Paint mPaint = new Paint();
     private float mRadius;
     private float mBaseGlowScale;
@@ -128,7 +135,7 @@
         a.recycle();
         mPaint.setColor((themeColor & 0xffffff) | 0x33000000);
         mPaint.setStyle(Paint.Style.FILL);
-        mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_ATOP));
+        mPaint.setBlendMode(DEFAULT_BLEND_MODE);
         mInterpolator = new DecelerateInterpolator();
     }
 
@@ -302,6 +309,22 @@
     }
 
     /**
+     * Set or clear the blend mode. A blend mode defines how source pixels
+     * (generated by a drawing command) are composited with the destination pixels
+     * (content of the render target).
+     * <p />
+     * Pass null to clear any previous blend mode.
+     * <p />
+     *
+     * @see BlendMode
+     *
+     * @param blendmode May be null. The blend mode to be installed in the paint
+     */
+    public void setBlendMode(@Nullable BlendMode blendmode) {
+        mPaint.setBlendMode(blendmode);
+    }
+
+    /**
      * Return the color of this edge effect in argb.
      * @return The color of this edge effect in argb
      */
@@ -310,6 +333,20 @@
         return mPaint.getColor();
     }
 
+
+    /**
+     * Returns the blend mode. A blend mode defines how source pixels
+     * (generated by a drawing command) are composited with the destination pixels
+     * (content of the render target).
+     * <p />
+     *
+     * @return BlendMode
+     */
+    @Nullable
+    public BlendMode getBlendMode() {
+        return mPaint.getBlendMode();
+    }
+
     /**
      * Draw into the provided canvas. Assumes that the canvas has been rotated
      * accordingly and the size has been set. The effect will be drawn the full
diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java
index bf65ec0..bbbe369 100644
--- a/core/java/android/widget/GridView.java
+++ b/core/java/android/widget/GridView.java
@@ -123,7 +123,7 @@
     private int mColumnWidth;
     @UnsupportedAppUsage
     private int mRequestedColumnWidth;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769395)
     private int mRequestedNumColumns;
 
     private View mReferenceView = null;
diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java
index e9c31db..800b19c 100644
--- a/core/java/android/widget/ImageView.java
+++ b/core/java/android/widget/ImageView.java
@@ -138,7 +138,7 @@
     private int mDrawableWidth;
     @UnsupportedAppUsage
     private int mDrawableHeight;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124051687)
     private Matrix mDrawMatrix = null;
 
     // Avoid allocations...
diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java
index f9564b4..25e5dd3 100644
--- a/core/java/android/widget/ListPopupWindow.java
+++ b/core/java/android/widget/ListPopupWindow.java
@@ -471,11 +471,24 @@
      * Specifies the anchor-relative bounds of the popup's transition
      * epicenter.
      *
-     * @param bounds anchor-relative bounds
-     * @hide
+     * @param bounds anchor-relative bounds, or {@code null} to use default epicenter
+     *
+     * @see #getEpicenterBounds()
      */
-    public void setEpicenterBounds(Rect bounds) {
-        mEpicenterBounds = bounds;
+    public void setEpicenterBounds(@Nullable Rect bounds) {
+        mEpicenterBounds = bounds != null ? new Rect(bounds) : null;
+    }
+
+    /**
+     * Returns bounds which are used as a popup's epicenter
+     * of the enter and exit transitions.
+     *
+     * @return bounds relative to anchor view, or {@code null} if not set
+     * @see #setEpicenterBounds(Rect)
+     */
+    @Nullable
+    public Rect getEpicenterBounds() {
+        return mEpicenterBounds != null ? new Rect(mEpicenterBounds) : null;
     }
 
     /**
diff --git a/core/java/android/widget/Magnifier.java b/core/java/android/widget/Magnifier.java
index d5b1a3d..249f499 100644
--- a/core/java/android/widget/Magnifier.java
+++ b/core/java/android/widget/Magnifier.java
@@ -1013,7 +1013,7 @@
             }
             synchronized (mLock) {
                 mRenderer.destroy();
-                mSurfaceControl.destroy();
+                mSurfaceControl.remove();
                 mSurfaceSession.kill();
                 mHandler.removeCallbacks(mMagnifierUpdater);
                 if (mBitmap != null) {
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 705a371..2798296 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -264,7 +264,7 @@
     private WeakReference<View> mAnchorRoot;
     private boolean mIsAnchorRootAttached;
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     private final OnScrollChangedListener mOnScrollChangedListener = this::alignToAnchor;
 
     private final View.OnLayoutChangeListener mOnLayoutChangeListener =
@@ -476,23 +476,40 @@
     }
 
     /**
-     * Sets the bounds used as the epicenter of the enter and exit transitions.
-     * <p>
-     * Transitions use a point or Rect, referred to as the epicenter, to orient
+     * <p>Returns bounds which are used as a center of the enter and exit transitions.<p/>
+     *
+     * <p>Transitions use Rect, referred to as the epicenter, to orient
      * the direction of travel. For popup windows, the anchor view bounds are
-     * used as the default epicenter.
-     * <p>
-     * See {@link Transition#setEpicenterCallback(EpicenterCallback)} for more
-     * information about how transition epicenters.
+     * used as the default epicenter.</p>
+     *
+     * <p>See {@link Transition#setEpicenterCallback(EpicenterCallback)} for more
+     * information about how transition epicenters work.</p>
+     *
+     * @return bounds relative to anchor view, or {@code null} if not set
+     * @see #setEpicenterBounds(Rect)
+     */
+    @Nullable
+    public Rect getEpicenterBounds() {
+        return mEpicenterBounds != null ? new Rect(mEpicenterBounds) : null;
+    }
+
+    /**
+     * <p>Sets the bounds used as the epicenter of the enter and exit transitions.</p>
+     *
+     * <p>Transitions use Rect, referred to as the epicenter, to orient
+     * the direction of travel. For popup windows, the anchor view bounds are
+     * used as the default epicenter.</p>
+     *
+     * <p>See {@link Transition#setEpicenterCallback(EpicenterCallback)} for more
+     * information about how transition epicenters work.</p>
      *
      * @param bounds the epicenter bounds relative to the anchor view, or
      *               {@code null} to use the default epicenter
-     * @see #getTransitionEpicenter()
-     * @hide
+     *
+     * @see #getEpicenterBounds()
      */
-    @UnsupportedAppUsage
-    public void setEpicenterBounds(Rect bounds) {
-        mEpicenterBounds = bounds;
+    public void setEpicenterBounds(@Nullable Rect bounds) {
+        mEpicenterBounds = bounds != null ? new Rect(bounds) : null;
     }
 
     private Transition getTransition(int resId) {
@@ -865,12 +882,28 @@
     }
 
     /**
-     * Clip this popup window to the screen, but not to the containing window.
+     * <p>Indicates whether this popup will be clipped to the screen and not to the
+     * containing window<p/>
      *
-     * @param enabled True to clip to the screen.
-     * @hide
+     * @return true if popup will be clipped to the screen instead of the window, false otherwise
+     *
+     * @see #setClipToScreenEnabled(boolean)
      */
-    @UnsupportedAppUsage
+    public boolean isClipToScreenEnabled() {
+        return mClipToScreen;
+    }
+
+    /**
+     * <p>Clip this popup window to the screen, but not to the containing window.</p>
+     *
+     * <p>If the popup is showing, calling this method will take effect only
+     * the next time the popup is shown or through a manual call to one of
+     * the {@link #update()} methods.</p>
+     *
+     * @param enabled true to clip to the screen.
+     *
+     * @see #isClipToScreenEnabled()
+     */
     public void setClipToScreenEnabled(boolean enabled) {
         mClipToScreen = enabled;
     }
@@ -927,7 +960,8 @@
      * for positioning.</p>
      *
      * @return true if the window will always be positioned in screen coordinates.
-     * @hide
+     *
+     * @see #setLayoutInScreenEnabled(boolean)
      */
     public boolean isLayoutInScreenEnabled() {
         return mLayoutInScreen;
@@ -939,9 +973,9 @@
      * This will cause the popup to be positioned in absolute screen coordinates.</p>
      *
      * @param enabled true if the popup should always be positioned in screen coordinates
-     * @hide
+     *
+     * @see #isLayoutInScreenEnabled()
      */
-    @UnsupportedAppUsage
     public void setLayoutInScreenEnabled(boolean enabled) {
         mLayoutInScreen = enabled;
     }
@@ -1021,11 +1055,30 @@
     }
 
     /**
-     * Set whether this window is touch modal or if outside touches will be sent to
-     * other windows behind it.
-     * @hide
+     * <p>Indicates whether outside touches will be sent to this window
+     * or other windows behind it<p/>
+     *
+     * @return true if touches will be sent to this window, false otherwise
+     *
+     * @see #setTouchModal(boolean)
      */
-    @UnsupportedAppUsage
+    public boolean isTouchModal() {
+        return !mNotTouchModal;
+    }
+
+    /**
+     * <p>Set whether this window is touch modal or if outside touches will be sent to
+     * other windows behind it.<p/>
+     *
+     * <p>If the popup is showing, calling this method will take effect only
+     * the next time the popup is shown or through a manual call to one of
+     * the {@link #update()} methods.</p>
+     *
+     * @param touchModal true to sent all outside touches to this window,
+     * false to other windows behind it
+     *
+     * @see #isTouchModal()
+     */
     public void setTouchModal(boolean touchModal) {
         mNotTouchModal = !touchModal;
     }
@@ -1454,7 +1507,7 @@
      *
      * @param p the layout parameters of the popup's content view
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     private void invokePopup(WindowManager.LayoutParams p) {
         if (mContext != null) {
             p.packageName = mContext.getPackageName();
@@ -2060,6 +2113,8 @@
      *     <li>{@link #setInputMethodMode(int)}</li>
      *     <li>{@link #setTouchable(boolean)}</li>
      *     <li>{@link #setAnimationStyle(int)}</li>
+     *     <li>{@link #setTouchModal(boolean)} (boolean)}</li>
+     *     <li>{@link #setClipToScreenEnabled(boolean)}</li>
      * </ul>
      */
     public void update() {
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index b6002681..30df5b5 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -20,6 +20,7 @@
 import android.annotation.InterpolatorRes;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.Px;
 import android.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.ColorStateList;
@@ -170,12 +171,24 @@
     /** Duration of smooth progress animations. */
     private static final int PROGRESS_ANIM_DURATION = 80;
 
-    @UnsupportedAppUsage
+    /**
+     * Outside the framework, please use {@link ProgressBar#getMinWidth()} and
+     * {@link ProgressBar#setMinWidth(int)} instead of accessing these directly.
+     */
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     int mMinWidth;
     int mMaxWidth;
-    @UnsupportedAppUsage
+    /**
+     * Outside the framework, please use {@link ProgressBar#getMinHeight()} and
+     * {@link ProgressBar#setMinHeight(int)} instead of accessing these directly.
+     */
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     int mMinHeight;
-    @UnsupportedAppUsage
+    /**
+     * Outside the framework, please use {@link ProgressBar#getMaxHeight()} ()} and
+     * {@link ProgressBar#setMaxHeight(int)} (int)} instead of accessing these directly.
+     */
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     int mMaxHeight;
 
     private int mProgress;
@@ -198,7 +211,12 @@
 
     private Drawable mIndeterminateDrawable;
     private Drawable mProgressDrawable;
-    @UnsupportedAppUsage
+    /**
+     * Outside the framework, instead of accessing this directly, please use
+     * {@link #getCurrentDrawable()}, {@link #setProgressDrawable(Drawable)},
+     * {@link #setIndeterminateDrawable(Drawable)} and their tiled versions.
+     */
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     private Drawable mCurrentDrawable;
     private ProgressTintInfo mProgressTintInfo;
 
@@ -393,6 +411,74 @@
     }
 
     /**
+     * Sets the minimum width the progress bar can have.
+     * @param minWidth the minimum width to be set, in pixels
+     * @attr ref android.R.styleable#ProgressBar_minWidth
+     */
+    public void setMinWidth(@Px int minWidth) {
+        mMinWidth = minWidth;
+        requestLayout();
+    }
+
+    /**
+     * @return the minimum width the progress bar can have, in pixels
+     */
+    @Px public int getMinWidth() {
+        return mMinWidth;
+    }
+
+    /**
+     * Sets the maximum width the progress bar can have.
+     * @param maxWidth the maximum width to be set, in pixels
+     * @attr ref android.R.styleable#ProgressBar_maxWidth
+     */
+    public void setMaxWidth(@Px int maxWidth) {
+        mMaxWidth = maxWidth;
+        requestLayout();
+    }
+
+    /**
+     * @return the maximum width the progress bar can have, in pixels
+     */
+    @Px public int getMaxWidth() {
+        return mMaxWidth;
+    }
+
+    /**
+     * Sets the minimum height the progress bar can have.
+     * @param minHeight the minimum height to be set, in pixels
+     * @attr ref android.R.styleable#ProgressBar_minHeight
+     */
+    public void setMinHeight(@Px int minHeight) {
+        mMinHeight = minHeight;
+        requestLayout();
+    }
+
+    /**
+     * @return the minimum height the progress bar can have, in pixels
+     */
+    @Px public int getMinHeight() {
+        return mMinHeight;
+    }
+
+    /**
+     * Sets the maximum height the progress bar can have.
+     * @param maxHeight the maximum height to be set, in pixels
+     * @attr ref android.R.styleable#ProgressBar_maxHeight
+     */
+    public void setMaxHeight(@Px int maxHeight) {
+        mMaxHeight = maxHeight;
+        requestLayout();
+    }
+
+    /**
+     * @return the maximum height the progress bar can have, in pixels
+     */
+    @Px public int getMaxHeight() {
+        return mMaxHeight;
+    }
+
+    /**
      * Returns {@code true} if the target drawable needs to be tileified.
      *
      * @param dr the drawable to check
@@ -1217,9 +1303,14 @@
     }
 
     /**
-     * @return The drawable currently used to draw the progress bar
+     * Returns the drawable currently used to draw the progress bar. This will be
+     * either {@link #getProgressDrawable()} or {@link #getIndeterminateDrawable()}
+     * depending on whether the progress bar is in determinate or indeterminate mode.
+     *
+     * @return the drawable currently used to draw the progress bar
      */
-    Drawable getCurrentDrawable() {
+    @Nullable
+    public Drawable getCurrentDrawable() {
         return mCurrentDrawable;
     }
 
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index fc4e9ec..c360903 100644
--- a/core/java/android/widget/ScrollView.java
+++ b/core/java/android/widget/ScrollView.java
@@ -111,7 +111,7 @@
      * layout is dirty. This prevents the scroll from being wrong if the child has not been
      * laid out before requesting focus.
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 123769715)
     private View mChildToScrollTo = null;
 
     /**
@@ -141,13 +141,13 @@
     private boolean mSmoothScrollingEnabled = true;
 
     private int mTouchSlop;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 124051125)
     private int mMinimumVelocity;
     private int mMaximumVelocity;
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = VERSION_CODES.P, trackingBug = 124050903)
     private int mOverscrollDistance;
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(maxTargetSdk = VERSION_CODES.P, trackingBug = 124050903)
     private int mOverflingDistance;
 
     private float mVerticalScrollFactor;
@@ -1384,16 +1384,20 @@
      *
      * @param child the View to scroll to
      */
-    private void scrollToChild(View child) {
-        child.getDrawingRect(mTempRect);
+    public void scrollToDescendant(View child) {
+        if (!mIsLayoutDirty) {
+            child.getDrawingRect(mTempRect);
 
-        /* Offset from child's local coordinates to ScrollView coordinates */
-        offsetDescendantRectToMyCoords(child, mTempRect);
+            /* Offset from child's local coordinates to ScrollView coordinates */
+            offsetDescendantRectToMyCoords(child, mTempRect);
 
-        int scrollDelta = computeScrollDeltaToGetChildRectOnScreen(mTempRect);
+            int scrollDelta = computeScrollDeltaToGetChildRectOnScreen(mTempRect);
 
-        if (scrollDelta != 0) {
-            scrollBy(0, scrollDelta);
+            if (scrollDelta != 0) {
+                scrollBy(0, scrollDelta);
+            }
+        } else {
+            mChildToScrollTo = child;
         }
     }
 
@@ -1488,7 +1492,7 @@
     public void requestChildFocus(View child, View focused) {
         if (focused != null && focused.getRevealOnFocusHint()) {
             if (!mIsLayoutDirty) {
-                scrollToChild(focused);
+                scrollToDescendant(focused);
             } else {
                 // The child may not be laid out yet, we can't compute the scroll yet
                 mChildToScrollTo = focused;
@@ -1569,7 +1573,7 @@
         mIsLayoutDirty = false;
         // Give a child focus if it needs it
         if (mChildToScrollTo != null && isViewDescendantOf(mChildToScrollTo, this)) {
-            scrollToChild(mChildToScrollTo);
+            scrollToDescendant(mChildToScrollTo);
         }
         mChildToScrollTo = null;
 
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 8626c68..d876001 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -435,8 +435,13 @@
     private ColorStateList mHintTextColor;
     private ColorStateList mLinkTextColor;
     @ViewDebug.ExportedProperty(category = "text")
-    @UnsupportedAppUsage
+
+    /**
+     * {@link #setTextColor(int)} or {@link #getCurrentTextColor()} should be used instead.
+     */
+    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     private int mCurTextColor;
+
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
     private int mCurHintTextColor;
     private boolean mFreezesText;
@@ -707,7 +712,7 @@
     @UnsupportedAppUsage
     private ChangeWatcher mChangeWatcher;
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(trackingBug = 123769451)
     private ArrayList<TextWatcher> mListeners;
 
     // display attributes
@@ -1050,6 +1055,8 @@
         int inputType = EditorInfo.TYPE_NULL;
         a = theme.obtainStyledAttributes(
                     attrs, com.android.internal.R.styleable.TextView, defStyleAttr, defStyleRes);
+        saveAttributeDataForStyleable(context, com.android.internal.R.styleable.TextView, attrs, a,
+                defStyleAttr, defStyleRes);
         int firstBaselineToTopHeight = -1;
         int lastBaselineToBottomHeight = -1;
         int lineHeight = -1;
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index ee96ae9..119a015 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -54,6 +54,7 @@
 import android.graphics.Path;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Icon;
+import android.metrics.LogMaker;
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Bundle;
@@ -186,9 +187,12 @@
     private @interface ContentPreviewType {
     }
 
-    private static final int CONTENT_PREVIEW_IMAGE = 0;
-    private static final int CONTENT_PREVIEW_FILE = 1;
-    private static final int CONTENT_PREVIEW_TEXT = 2;
+    // Starting at 1 since 0 is considered "undefined" for some of the database transformations
+    // of tron logs.
+    private static final int CONTENT_PREVIEW_IMAGE = 1;
+    private static final int CONTENT_PREVIEW_FILE = 2;
+    private static final int CONTENT_PREVIEW_TEXT = 3;
+    protected MetricsLogger mMetricsLogger;
 
     private final Handler mChooserHandler = new Handler() {
         @Override
@@ -413,11 +417,12 @@
             }
         });
 
-        MetricsLogger.action(this, MetricsEvent.ACTION_ACTIVITY_CHOOSER_SHOWN);
-
         mChooserShownTime = System.currentTimeMillis();
         final long systemCost = mChooserShownTime - intentReceivedTime;
-        MetricsLogger.histogram(null, "system_cost_for_smart_sharing", (int) systemCost);
+
+        getMetricsLogger().write(new LogMaker(MetricsEvent.ACTION_ACTIVITY_CHOOSER_SHOWN)
+                .addTaggedData(MetricsEvent.FIELD_SHARESHEET_MIMETYPE, target.getType())
+                .addTaggedData(MetricsEvent.FIELD_TIME_TO_APP_TARGETS, systemCost));
 
         if (USE_PREDICTION_MANAGER_FOR_DIRECT_TARGETS) {
             final IntentFilter filter = getTargetIntentFilter();
@@ -470,6 +475,9 @@
         }
 
         int previewType = findPreferredContentPreview(targetIntent, getContentResolver());
+
+        getMetricsLogger().write(new LogMaker(MetricsEvent.ACTION_SHARE_WITH_PREVIEW)
+                .setSubtype(previewType));
         displayContentPreview(previewType, targetIntent);
     }
 
@@ -1180,6 +1188,13 @@
         }
     }
 
+    protected MetricsLogger getMetricsLogger() {
+        if (mMetricsLogger == null) {
+            mMetricsLogger = new MetricsLogger();
+        }
+        return mMetricsLogger;
+    }
+
     public class ChooserListController extends ResolverListController {
         public ChooserListController(Context context,
                 PackageManager pm,
@@ -1726,6 +1741,8 @@
             if (show != mShowServiceTargets) {
                 mShowServiceTargets = show;
                 notifyDataSetChanged();
+                getMetricsLogger().write(
+                        new LogMaker(MetricsEvent.ACTION_ACTIVITY_CHOOSER_SHOWN_DIRECT_TARGET));
             }
         }
 
@@ -1884,8 +1901,6 @@
             }
 
             if (startType == ChooserListAdapter.TARGET_SERVICE) {
-                holder.row.setBackgroundColor(
-                        getColor(R.color.chooser_service_row_background_color));
                 int nextStartType = mChooserListAdapter.getPositionTargetType(
                         getFirstRowPosition(rowPosition + 1));
                 int serviceSpacing = holder.row.getContext().getResources()
diff --git a/core/java/com/android/internal/colorextraction/ColorExtractor.java b/core/java/com/android/internal/colorextraction/ColorExtractor.java
index c171fa6..258d081 100644
--- a/core/java/com/android/internal/colorextraction/ColorExtractor.java
+++ b/core/java/com/android/internal/colorextraction/ColorExtractor.java
@@ -22,7 +22,6 @@
 import android.app.WallpaperManager;
 import android.content.Context;
 import android.os.Trace;
-import android.os.UserHandle;
 import android.util.Log;
 import android.util.SparseArray;
 
@@ -32,7 +31,6 @@
 
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
-import java.util.Iterator;
 
 /**
  * Class to process wallpaper colors and generate a tonal palette based on them.
@@ -222,6 +220,7 @@
     public static class GradientColors {
         private int mMainColor;
         private int mSecondaryColor;
+        private int[] mColorPalette;
         private boolean mSupportsDarkText;
 
         public void setMainColor(int mainColor) {
@@ -232,6 +231,10 @@
             mSecondaryColor = secondaryColor;
         }
 
+        public void setColorPalette(int[] colorPalette) {
+            mColorPalette = colorPalette;
+        }
+
         public void setSupportsDarkText(boolean supportsDarkText) {
             mSupportsDarkText = supportsDarkText;
         }
@@ -239,6 +242,7 @@
         public void set(GradientColors other) {
             mMainColor = other.mMainColor;
             mSecondaryColor = other.mSecondaryColor;
+            mColorPalette = other.mColorPalette;
             mSupportsDarkText = other.mSupportsDarkText;
         }
 
@@ -250,6 +254,10 @@
             return mSecondaryColor;
         }
 
+        public int[] getColorPalette() {
+            return mColorPalette;
+        }
+
         public boolean supportsDarkText() {
             return mSupportsDarkText;
         }
@@ -283,4 +291,4 @@
     public interface OnColorsChangedListener {
         void onColorsChanged(ColorExtractor colorExtractor, int which);
     }
-}
\ No newline at end of file
+}
diff --git a/core/java/com/android/internal/colorextraction/types/Tonal.java b/core/java/com/android/internal/colorextraction/types/Tonal.java
index 3fd88db..d6a8934 100644
--- a/core/java/com/android/internal/colorextraction/types/Tonal.java
+++ b/core/java/com/android/internal/colorextraction/types/Tonal.java
@@ -173,6 +173,7 @@
                 Float.NEGATIVE_INFINITY, Float.POSITIVE_INFINITY);
         float[] s = fit(palette.s, hsl[1], fitIndex, 0.0f, 1.0f);
         float[] l = fit(palette.l, hsl[2], fitIndex, 0.0f, 1.0f);
+        int[] colorPalette = getColorPalette(h, s, l);
 
         if (DEBUG) {
             StringBuilder builder = new StringBuilder("Tonal Palette - index: " + fitIndex +
@@ -209,6 +210,7 @@
         // Normal colors:
         outColorsNormal.setMainColor(mainColor);
         outColorsNormal.setSecondaryColor(mainColor);
+        outColorsNormal.setColorPalette(colorPalette);
 
         // Dark colors:
         // Stops at 4th color, only lighter if dark text is supported
@@ -222,6 +224,7 @@
         mainColor = getColorInt(primaryIndex, h, s, l);
         outColorsDark.setMainColor(mainColor);
         outColorsDark.setSecondaryColor(mainColor);
+        outColorsDark.setColorPalette(colorPalette);
 
         // Extra Dark:
         // Stay close to dark colors until dark text is supported
@@ -235,6 +238,7 @@
         mainColor = getColorInt(primaryIndex, h, s, l);
         outColorsExtraDark.setMainColor(mainColor);
         outColorsExtraDark.setSecondaryColor(mainColor);
+        outColorsExtraDark.setColorPalette(colorPalette);
 
         outColorsNormal.setSupportsDarkText(supportsDarkText);
         outColorsDark.setSupportsDarkText(supportsDarkText);
@@ -262,16 +266,19 @@
      * @param inWallpaperColors Colors to read.
      * @param outGradientColors Destination.
      */
-    public static void applyFallback(@Nullable WallpaperColors inWallpaperColors,
+    public void applyFallback(@Nullable WallpaperColors inWallpaperColors,
             @NonNull GradientColors outGradientColors) {
         boolean light = inWallpaperColors != null
                 && (inWallpaperColors.getColorHints() & WallpaperColors.HINT_SUPPORTS_DARK_TEXT)
                 != 0;
         final int color = light ? MAIN_COLOR_LIGHT : MAIN_COLOR_DARK;
+        final float[] hsl = new float[3];
+        ColorUtils.colorToHSL(color, hsl);
 
         outGradientColors.setMainColor(color);
         outGradientColors.setSecondaryColor(color);
         outGradientColors.setSupportsDarkText(light);
+        outGradientColors.setColorPalette(getColorPalette(findTonalPalette(hsl[0], hsl[1])));
     }
 
     private int getColorInt(int fitIndex, float[] h, float[] s, float[] l) {
@@ -281,6 +288,19 @@
         return ColorUtils.HSLToColor(mTmpHSL);
     }
 
+    private int[] getColorPalette(float[] h, float[] s, float[] l) {
+        int[] colorPalette = new int[h.length];
+        for (int i = 0; i < colorPalette.length; i++) {
+            colorPalette[i] = getColorInt(i, h, s, l);
+        }
+        return colorPalette;
+    }
+
+    private int[] getColorPalette(TonalPalette palette) {
+        return getColorPalette(palette.h, palette.s, palette.l);
+    }
+
+
     /**
      * Checks if a given color exists in the blacklist
      * @param hsl float array with 3 components (H 0..360, S 0..1 and L 0..1)
@@ -598,4 +618,4 @@
             return numbers;
         }
     }
-}
\ No newline at end of file
+}
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 650a194..52e1748 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -6117,8 +6117,6 @@
         for (int i=0; i<N; i++) {
             final int uid = mapUid(ws.get(i));
             noteFullWifiLockAcquiredLocked(uid);
-            StatsLog.write_non_chained(StatsLog.WIFI_LOCK_STATE_CHANGED, ws.get(i), ws.getName(i),
-                    StatsLog.WIFI_LOCK_STATE_CHANGED__STATE__ON);
         }
 
         final List<WorkChain> workChains = ws.getWorkChains();
@@ -6127,9 +6125,6 @@
                 final WorkChain workChain = workChains.get(i);
                 final int uid = mapUid(workChain.getAttributionUid());
                 noteFullWifiLockAcquiredLocked(uid);
-                StatsLog.write(StatsLog.WIFI_LOCK_STATE_CHANGED,
-                        workChain.getUids(), workChain.getTags(),
-                        StatsLog.WIFI_LOCK_STATE_CHANGED__STATE__ON);
             }
         }
     }
@@ -6139,8 +6134,6 @@
         for (int i=0; i<N; i++) {
             final int uid = mapUid(ws.get(i));
             noteFullWifiLockReleasedLocked(uid);
-            StatsLog.write_non_chained(StatsLog.WIFI_LOCK_STATE_CHANGED, ws.get(i), ws.getName(i),
-                    StatsLog.WIFI_LOCK_STATE_CHANGED__STATE__OFF);
         }
 
         final List<WorkChain> workChains = ws.getWorkChains();
@@ -6149,9 +6142,6 @@
                 final WorkChain workChain = workChains.get(i);
                 final int uid = mapUid(workChain.getAttributionUid());
                 noteFullWifiLockReleasedLocked(uid);
-                StatsLog.write(StatsLog.WIFI_LOCK_STATE_CHANGED,
-                        workChain.getUids(), workChain.getTags(),
-                        StatsLog.WIFI_LOCK_STATE_CHANGED__STATE__OFF);
             }
         }
     }
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index b881aef..40d7868 100644
--- a/core/java/com/android/internal/os/Zygote.java
+++ b/core/java/com/android/internal/os/Zygote.java
@@ -99,6 +99,11 @@
      */
     public static final int PROFILE_FROM_SHELL = 1 << 15;
 
+    /*
+     * Enable using the ART app image startup cache
+     */
+    public static final int USE_APP_IMAGE_STARTUP_CACHE = 1 << 16;
+
     /** No external storage should be mounted. */
     public static final int MOUNT_EXTERNAL_NONE = IVold.REMOUNT_MODE_NONE;
     /** Default external storage should be mounted. */
@@ -249,14 +254,14 @@
     public static int forkAndSpecialize(int uid, int gid, int[] gids, int runtimeFlags,
             int[][] rlimits, int mountExternal, String seInfo, String niceName, int[] fdsToClose,
             int[] fdsToIgnore, boolean startChildZygote, String instructionSet, String appDataDir,
-            String packageName, String[] packagesForUID, String[] visibleVolIDs) {
+            String packageName, String[] packagesForUID, String[] visibleVolIDs, String sandboxId) {
         ZygoteHooks.preFork();
         // Resets nice priority for zygote process.
         resetNicePriority();
         int pid = nativeForkAndSpecialize(
                 uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo, niceName, fdsToClose,
                 fdsToIgnore, startChildZygote, instructionSet, appDataDir, packageName,
-                packagesForUID, visibleVolIDs);
+                packagesForUID, visibleVolIDs, sandboxId);
         // Enable tracing as soon as possible for the child process.
         if (pid == 0) {
             Trace.setTracingEnabled(true, runtimeFlags);
@@ -271,7 +276,8 @@
     private static native int nativeForkAndSpecialize(int uid, int gid, int[] gids,
             int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName,
             int[] fdsToClose, int[] fdsToIgnore, boolean startChildZygote, String instructionSet,
-            String appDataDir, String packageName, String[] packagesForUID, String[] visibleVolIDs);
+            String appDataDir, String packageName, String[] packagesForUID, String[] visibleVolIDs,
+            String sandboxId);
 
     /**
      * Specialize a Blastula instance.  The current VM must have been started
@@ -297,11 +303,11 @@
     public static void specializeBlastula(int uid, int gid, int[] gids, int runtimeFlags,
             int[][] rlimits, int mountExternal, String seInfo, String niceName,
             boolean startChildZygote, String instructionSet, String appDataDir, String packageName,
-            String[] packagesForUID, String[] visibleVolIDs) {
+            String[] packagesForUID, String[] visibleVolIDs, String sandboxId) {
 
         nativeSpecializeBlastula(uid, gid, gids, runtimeFlags, rlimits, mountExternal, seInfo,
                                  niceName, startChildZygote, instructionSet, appDataDir,
-                                 packageName, packagesForUID, visibleVolIDs);
+                                 packageName, packagesForUID, visibleVolIDs, sandboxId);
 
         // Enable tracing as soon as possible for the child process.
         Trace.setTracingEnabled(true, runtimeFlags);
@@ -321,7 +327,7 @@
     private static native void nativeSpecializeBlastula(int uid, int gid, int[] gids,
             int runtimeFlags, int[][] rlimits, int mountExternal, String seInfo, String niceName,
             boolean startChildZygote, String instructionSet, String appDataDir, String packageName,
-            String[] packagesForUID, String[] visibleVolIDs);
+            String[] packagesForUID, String[] visibleVolIDs, String sandboxId);
 
     /**
      * Called to do any initialization before starting an application.
@@ -633,7 +639,7 @@
                            args.mRuntimeFlags, rlimits, args.mMountExternal,
                            args.mSeInfo, args.mNiceName, args.mStartChildZygote,
                            args.mInstructionSet, args.mAppDataDir, args.mPackageName,
-                           args.mPackagesForUid, args.mVisibleVolIds);
+                           args.mPackagesForUid, args.mVisibleVolIds, args.mSandboxId);
 
         if (args.mNiceName != null) {
             Process.setArgV0(args.mNiceName);
diff --git a/core/java/com/android/internal/os/ZygoteArguments.java b/core/java/com/android/internal/os/ZygoteArguments.java
index 24a08ca..e6bcd37 100644
--- a/core/java/com/android/internal/os/ZygoteArguments.java
+++ b/core/java/com/android/internal/os/ZygoteArguments.java
@@ -119,6 +119,9 @@
     /** from --visible-vols */
     String[] mVisibleVolIds;
 
+    /** from --sandbox-id */
+    String mSandboxId;
+
     /**
      * Any args after and including the first non-option arg (or after a '--')
      */
@@ -385,6 +388,11 @@
                 mPackagesForUid = arg.substring(arg.indexOf('=') + 1).split(",");
             } else if (arg.startsWith("--visible-vols=")) {
                 mVisibleVolIds = arg.substring(arg.indexOf('=') + 1).split(",");
+            } else if (arg.startsWith("--sandbox-id=")) {
+                if (mSandboxId != null) {
+                    throw new IllegalArgumentException("Duplicate arg specified");
+                }
+                mSandboxId = arg.substring(arg.indexOf('=') + 1);
             } else {
                 break;
             }
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 9ba56b8..9cf7e27 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -258,7 +258,7 @@
                 parsedArgs.mRuntimeFlags, rlimits, parsedArgs.mMountExternal, parsedArgs.mSeInfo,
                 parsedArgs.mNiceName, fdsToClose, fdsToIgnore, parsedArgs.mStartChildZygote,
                 parsedArgs.mInstructionSet, parsedArgs.mAppDataDir, parsedArgs.mPackageName,
-                parsedArgs.mPackagesForUid, parsedArgs.mVisibleVolIds);
+                parsedArgs.mPackagesForUid, parsedArgs.mVisibleVolIds, parsedArgs.mSandboxId);
 
         try {
             if (pid == 0) {
@@ -334,9 +334,14 @@
         }
     }
 
-    private class HiddenApiUsageLogger implements VMRuntime.HiddenApiUsageLogger {
+    private static class HiddenApiUsageLogger implements VMRuntime.HiddenApiUsageLogger {
 
         private final MetricsLogger mMetricsLogger = new MetricsLogger();
+        private static HiddenApiUsageLogger sInstance = new HiddenApiUsageLogger();
+
+        public static HiddenApiUsageLogger getInstance() {
+            return HiddenApiUsageLogger.sInstance;
+        }
 
         public void hiddenApiUsed(String packageName, String signature,
                 int accessMethod, boolean accessDenied) {
@@ -370,7 +375,7 @@
     private void handleHiddenApiAccessLogSampleRate(int samplingRate) {
         try {
             ZygoteInit.setHiddenApiAccessLogSampleRate(samplingRate);
-            ZygoteInit.setHiddenApiUsageLogger(new HiddenApiUsageLogger());
+            ZygoteInit.setHiddenApiUsageLogger(HiddenApiUsageLogger.getInstance());
             mSocketOutStream.writeInt(0);
         } catch (IOException ioe) {
             throw new IllegalStateException("Error writing to command socket", ioe);
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 9f23797..e132abd 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -41,6 +41,7 @@
 import android.system.StructCapUserData;
 import android.system.StructCapUserHeader;
 import android.text.Hyphenator;
+import android.text.TextUtils;
 import android.util.EventLog;
 import android.util.Log;
 import android.util.Slog;
@@ -84,6 +85,8 @@
 
     private static final String PROPERTY_DISABLE_OPENGL_PRELOADING = "ro.zygote.disable_gl_preload";
     private static final String PROPERTY_GFX_DRIVER = "ro.gfx.driver.0";
+    private static final String PROPERTY_USE_APP_IMAGE_STARTUP_CACHE =
+            "persist.device_config.runtime_native.use_app_image_startup_cache";
 
     private static final int LOG_BOOT_PROGRESS_PRELOAD_START = 3020;
     private static final int LOG_BOOT_PROGRESS_PRELOAD_END = 3030;
@@ -705,6 +708,13 @@
                 parsedArgs.mRuntimeFlags |= Zygote.PROFILE_SYSTEM_SERVER;
             }
 
+            String use_app_image_cache = SystemProperties.get(
+                    PROPERTY_USE_APP_IMAGE_STARTUP_CACHE, "");
+            // Property defaults to true currently.
+            if (!TextUtils.isEmpty(use_app_image_cache) && !use_app_image_cache.equals("false")) {
+                parsedArgs.mRuntimeFlags |= Zygote.USE_APP_IMAGE_STARTUP_CACHE;
+            }
+
             /* Request to fork the system server process */
             pid = Zygote.forkSystemServer(
                     parsedArgs.mUid, parsedArgs.mGid,
diff --git a/core/java/com/android/internal/util/ArrayUtils.java b/core/java/com/android/internal/util/ArrayUtils.java
index 397df56..b04ebec 100644
--- a/core/java/com/android/internal/util/ArrayUtils.java
+++ b/core/java/com/android/internal/util/ArrayUtils.java
@@ -691,6 +691,15 @@
         return result;
     }
 
+    public static boolean startsWith(byte[] cur, byte[] val) {
+        if (cur == null || val == null) return false;
+        if (cur.length < val.length) return false;
+        for (int i = 0; i < val.length; i++) {
+            if (cur[i] != val[i]) return false;
+        }
+        return true;
+    }
+
     /**
      * Returns the first element from the array for which
      * condition {@code predicate} is true, or null if there is no such element
diff --git a/core/java/com/android/internal/widget/ResolverDrawerLayout.java b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
index b7e656b..ee8637d8 100644
--- a/core/java/com/android/internal/widget/ResolverDrawerLayout.java
+++ b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
@@ -17,15 +17,12 @@
 
 package com.android.internal.widget;
 
-import com.android.internal.R;
-
 import android.content.Context;
 import android.content.res.TypedArray;
 import android.graphics.Canvas;
-import android.graphics.Color;
 import android.graphics.Rect;
-import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
+import android.metrics.LogMaker;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -45,8 +42,13 @@
 import android.widget.AbsListView;
 import android.widget.OverScroller;
 
+import com.android.internal.R;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
 public class ResolverDrawerLayout extends ViewGroup {
     private static final String TAG = "ResolverDrawerLayout";
+    private MetricsLogger mMetricsLogger;
 
     /**
      * Max width of the whole drawer layout
@@ -496,6 +498,9 @@
             final boolean isCollapsedNew = newPos != 0;
             if (isCollapsedOld != isCollapsedNew) {
                 onCollapsedChanged(isCollapsedNew);
+                getMetricsLogger().write(
+                        new LogMaker(MetricsEvent.ACTION_SHARESHEET_COLLAPSED_CHANGED)
+                        .setSubtype(isCollapsedNew ? 1 : 0));
             }
             postInvalidateOnAnimation();
             return dy;
@@ -1037,4 +1042,11 @@
             dispatchOnDismissed();
         }
     }
+
+    private MetricsLogger getMetricsLogger() {
+        if (mMetricsLogger == null) {
+            mMetricsLogger = new MetricsLogger();
+        }
+        return mMetricsLogger;
+    }
 }
diff --git a/core/java/com/android/server/backup/AccountSyncSettingsBackupHelper.java b/core/java/com/android/server/backup/AccountSyncSettingsBackupHelper.java
index 1b40492..b4610bd 100644
--- a/core/java/com/android/server/backup/AccountSyncSettingsBackupHelper.java
+++ b/core/java/com/android/server/backup/AccountSyncSettingsBackupHelper.java
@@ -26,6 +26,7 @@
 import android.content.SyncAdapterType;
 import android.os.Environment;
 import android.os.ParcelFileDescriptor;
+import android.os.UserHandle;
 import android.util.Log;
 
 import org.json.JSONArray;
@@ -48,6 +49,7 @@
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 /**
  * Helper for backing up account sync settings (whether or not a service should be synced). The
@@ -76,15 +78,17 @@
     private static final String KEY_AUTHORITY_NAME = "name";
     private static final String KEY_AUTHORITY_SYNC_STATE = "syncState";
     private static final String KEY_AUTHORITY_SYNC_ENABLED = "syncEnabled";
-    private static final String STASH_FILE = Environment.getDataDirectory()
-            + "/backup/unadded_account_syncsettings.json";
+    private static final String STASH_FILE = "/backup/unadded_account_syncsettings.json";
 
     private Context mContext;
     private AccountManager mAccountManager;
+    private final int mUserId;
 
-    public AccountSyncSettingsBackupHelper(Context context) {
+    public AccountSyncSettingsBackupHelper(Context context, int userId) {
         mContext = context;
         mAccountManager = AccountManager.get(mContext);
+
+        mUserId = userId;
     }
 
     /**
@@ -94,7 +98,7 @@
     public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput output,
             ParcelFileDescriptor newState) {
         try {
-            JSONObject dataJSON = serializeAccountSyncSettingsToJSON();
+            JSONObject dataJSON = serializeAccountSyncSettingsToJSON(mUserId);
 
             if (DEBUG) {
                 Log.d(TAG, "Account sync settings JSON: " + dataJSON);
@@ -123,10 +127,9 @@
     /**
      * Fetch and serialize Account and authority information as a JSON Array.
      */
-    private JSONObject serializeAccountSyncSettingsToJSON() throws JSONException {
-        Account[] accounts = mAccountManager.getAccounts();
-        SyncAdapterType[] syncAdapters = ContentResolver.getSyncAdapterTypesAsUser(
-                mContext.getUserId());
+    private JSONObject serializeAccountSyncSettingsToJSON(int userId) throws JSONException {
+        Account[] accounts = mAccountManager.getAccountsAsUser(userId);
+        SyncAdapterType[] syncAdapters = ContentResolver.getSyncAdapterTypesAsUser(userId);
 
         // Create a map of Account types to authorities. Later this will make it easier for us to
         // generate our JSON.
@@ -146,7 +149,8 @@
         // Generate JSON.
         JSONObject backupJSON = new JSONObject();
         backupJSON.put(KEY_VERSION, JSON_FORMAT_VERSION);
-        backupJSON.put(KEY_MASTER_SYNC_ENABLED, ContentResolver.getMasterSyncAutomatically());
+        backupJSON.put(KEY_MASTER_SYNC_ENABLED, ContentResolver.getMasterSyncAutomaticallyAsUser(
+                userId));
 
         JSONArray accountJSONArray = new JSONArray();
         for (Account account : accounts) {
@@ -165,8 +169,9 @@
             // Add authorities for this Account type and check whether or not sync is enabled.
             JSONArray authoritiesJSONArray = new JSONArray();
             for (String authority : authorities) {
-                int syncState = ContentResolver.getIsSyncable(account, authority);
-                boolean syncEnabled = ContentResolver.getSyncAutomatically(account, authority);
+                int syncState = ContentResolver.getIsSyncableAsUser(account, authority, userId);
+                boolean syncEnabled = ContentResolver.getSyncAutomaticallyAsUser(account, authority,
+                        userId);
 
                 JSONObject authorityJSON = new JSONObject();
                 authorityJSON.put(KEY_AUTHORITY_NAME, authority);
@@ -254,17 +259,18 @@
             boolean masterSyncEnabled = dataJSON.getBoolean(KEY_MASTER_SYNC_ENABLED);
             JSONArray accountJSONArray = dataJSON.getJSONArray(KEY_ACCOUNTS);
 
-            boolean currentMasterSyncEnabled = ContentResolver.getMasterSyncAutomatically();
+            boolean currentMasterSyncEnabled = ContentResolver.getMasterSyncAutomaticallyAsUser(
+                    mUserId);
             if (currentMasterSyncEnabled) {
                 // Disable master sync to prevent any syncs from running.
-                ContentResolver.setMasterSyncAutomatically(false);
+                ContentResolver.setMasterSyncAutomaticallyAsUser(false, mUserId);
             }
 
             try {
-                restoreFromJsonArray(accountJSONArray);
+                restoreFromJsonArray(accountJSONArray, mUserId);
             } finally {
                 // Set the master sync preference to the value from the backup set.
-                ContentResolver.setMasterSyncAutomatically(masterSyncEnabled);
+                ContentResolver.setMasterSyncAutomaticallyAsUser(masterSyncEnabled, mUserId);
             }
             Log.i(TAG, "Restore successful.");
         } catch (IOException | JSONException e) {
@@ -272,9 +278,9 @@
         }
     }
 
-    private void restoreFromJsonArray(JSONArray accountJSONArray)
+    private void restoreFromJsonArray(JSONArray accountJSONArray, int userId)
             throws JSONException {
-        HashSet<Account> currentAccounts = getAccounts();
+        Set<Account> currentAccounts = getAccounts(userId);
         JSONArray unaddedAccountsJSONArray = new JSONArray();
         for (int i = 0; i < accountJSONArray.length(); i++) {
             JSONObject accountJSON = (JSONObject) accountJSONArray.get(i);
@@ -292,14 +298,14 @@
             // yet won't be restored.
             if (currentAccounts.contains(account)) {
                 if (DEBUG) Log.i(TAG, "Restoring Sync Settings for" + accountName);
-                restoreExistingAccountSyncSettingsFromJSON(accountJSON);
+                restoreExistingAccountSyncSettingsFromJSON(accountJSON, userId);
             } else {
                 unaddedAccountsJSONArray.put(accountJSON);
             }
         }
 
         if (unaddedAccountsJSONArray.length() > 0) {
-            try (FileOutputStream fOutput = new FileOutputStream(STASH_FILE)) {
+            try (FileOutputStream fOutput = new FileOutputStream(getStashFile(userId))) {
                 String jsonString = unaddedAccountsJSONArray.toString();
                 DataOutputStream out = new DataOutputStream(fOutput);
                 out.writeUTF(jsonString);
@@ -308,18 +314,20 @@
                 Log.e(TAG, "unable to write the sync settings to the stash file", ioe);
             }
         } else {
-            File stashFile = new File(STASH_FILE);
-            if (stashFile.exists()) stashFile.delete();
+            File stashFile = getStashFile(userId);
+            if (stashFile.exists()) {
+                stashFile.delete();
+            }
         }
     }
 
     /**
      * Restore SyncSettings for all existing accounts from a stashed backup-set
      */
-    private void accountAddedInternal() {
+    private void accountAddedInternal(int userId) {
         String jsonString;
 
-        try (FileInputStream fIn = new FileInputStream(new File(STASH_FILE))) {
+        try (FileInputStream fIn = new FileInputStream(getStashFile(userId))) {
             DataInputStream in = new DataInputStream(fIn);
             jsonString = in.readUTF();
         } catch (FileNotFoundException fnfe) {
@@ -333,7 +341,7 @@
 
         try {
             JSONArray unaddedAccountsJSONArray = new JSONArray(jsonString);
-            restoreFromJsonArray(unaddedAccountsJSONArray);
+            restoreFromJsonArray(unaddedAccountsJSONArray, userId);
         } catch (JSONException jse) {
             // Malformed jsonString
             Log.e(TAG, "there was an error with the stashed sync settings", jse);
@@ -343,9 +351,10 @@
     /**
      * Restore SyncSettings for all existing accounts from a stashed backup-set
      */
-    public static void accountAdded(Context context) {
-        AccountSyncSettingsBackupHelper helper = new AccountSyncSettingsBackupHelper(context);
-        helper.accountAddedInternal();
+    public static void accountAdded(Context context, int userId) {
+        AccountSyncSettingsBackupHelper helper = new AccountSyncSettingsBackupHelper(context,
+                userId);
+        helper.accountAddedInternal(userId);
     }
 
     /**
@@ -353,9 +362,9 @@
      *
      * @return Accounts in a HashSet.
      */
-    private HashSet<Account> getAccounts() {
-        Account[] accounts = mAccountManager.getAccounts();
-        HashSet<Account> accountHashSet = new HashSet<Account>();
+    private Set<Account> getAccounts(int userId) {
+        Account[] accounts = mAccountManager.getAccountsAsUser(userId);
+        Set<Account> accountHashSet = new HashSet<Account>();
         for (Account account : accounts) {
             accountHashSet.add(account);
         }
@@ -391,7 +400,7 @@
      * initialization sync, while an adapter that the user had off will be off until the user
      * enables it on this device at which point it will get an initialization sync.
      */
-    private void restoreExistingAccountSyncSettingsFromJSON(JSONObject accountJSON)
+    private void restoreExistingAccountSyncSettingsFromJSON(JSONObject accountJSON, int userId)
             throws JSONException {
         // Restore authorities.
         JSONArray authorities = accountJSON.getJSONArray(KEY_ACCOUNT_AUTHORITIES);
@@ -406,14 +415,15 @@
             int wasSyncable = authority.getInt(KEY_AUTHORITY_SYNC_STATE);
 
             ContentResolver.setSyncAutomaticallyAsUser(
-                    account, authorityName, wasSyncEnabled, 0 /* user Id */);
+                    account, authorityName, wasSyncEnabled, userId);
 
             if (!wasSyncEnabled) {
-                ContentResolver.setIsSyncable(
+                ContentResolver.setIsSyncableAsUser(
                         account,
                         authorityName,
                         wasSyncable == 0 ?
-                                0 /* not syncable */ : 2 /* syncable but needs initialization */);
+                                0 /* not syncable */ : 2 /* syncable but needs initialization */,
+                        userId);
             }
         }
     }
@@ -422,4 +432,10 @@
     public void writeNewStateDescription(ParcelFileDescriptor newState) {
 
     }
-}
\ No newline at end of file
+
+    private static File getStashFile(int userId) {
+        File baseDir = userId == UserHandle.USER_SYSTEM ? Environment.getDataDirectory()
+                : Environment.getDataSystemCeDirectory(userId);
+        return new File(baseDir, STASH_FILE);
+    }
+}
diff --git a/core/java/com/android/server/backup/SystemBackupAgent.java b/core/java/com/android/server/backup/SystemBackupAgent.java
index 70798d0..35e8f56 100644
--- a/core/java/com/android/server/backup/SystemBackupAgent.java
+++ b/core/java/com/android/server/backup/SystemBackupAgent.java
@@ -81,7 +81,7 @@
     private static final String WALLPAPER_IMAGE_KEY = WallpaperBackupHelper.WALLPAPER_IMAGE_KEY;
 
     private static final Set<String> sEligibleForMultiUser = Sets.newArraySet(
-            PERMISSION_HELPER, NOTIFICATION_HELPER);
+            PERMISSION_HELPER, NOTIFICATION_HELPER, SYNC_SETTINGS_HELPER);
 
     private int mUserId = UserHandle.USER_SYSTEM;
 
@@ -91,7 +91,7 @@
 
         mUserId = user.getIdentifier();
 
-        addHelper(SYNC_SETTINGS_HELPER, new AccountSyncSettingsBackupHelper(this));
+        addHelper(SYNC_SETTINGS_HELPER, new AccountSyncSettingsBackupHelper(this, mUserId));
         addHelper(PREFERRED_HELPER, new PreferredActivityBackupHelper());
         addHelper(NOTIFICATION_HELPER, new NotificationBackupHelper(mUserId));
         addHelper(PERMISSION_HELPER, new PermissionBackupHelper(mUserId));
diff --git a/core/jni/android_opengl_EGL15.cpp b/core/jni/android_opengl_EGL15.cpp
index b52f137..2abd950 100644
--- a/core/jni/android_opengl_EGL15.cpp
+++ b/core/jni/android_opengl_EGL15.cpp
@@ -194,6 +194,7 @@
     if (obj == NULL){
         jniThrowException(_env, "java/lang/IllegalArgumentException",
                           "Object is set to null.");
+        return nullptr;
     }
 
     jlong handle = _env->CallLongMethod(obj, mid);
@@ -254,6 +255,7 @@
     }
     if (_exception) {
         jniThrowException(_env, _exceptionType, _exceptionMessage);
+        return nullptr;
     }
     return toEGLHandle(_env, eglsyncClass, eglsyncConstructor, _returnValue);
 }
@@ -335,6 +337,7 @@
     }
     if (_exception) {
         jniThrowException(_env, _exceptionType, _exceptionMessage);
+        return false;
     }
     return (jboolean)_returnValue;
 }
@@ -381,6 +384,7 @@
     }
     if (_exception) {
         jniThrowException(_env, _exceptionType, _exceptionMessage);
+        return nullptr;
     }
     return toEGLHandle(_env, egldisplayClass, egldisplayConstructor, _returnValue);
 }
@@ -448,6 +452,7 @@
     }
     if (_exception) {
         jniThrowException(_env, _exceptionType, _exceptionMessage);
+        return nullptr;
     }
     return toEGLHandle(_env, eglsurfaceClass, eglsurfaceConstructor, _returnValue);
 }
@@ -456,8 +461,11 @@
 static jobject
 android_eglCreatePlatformPixmapSurface
   (JNIEnv *_env, jobject _this, jobject dpy, jobject config, jobject native_pixmap_buf, jlongArray attrib_list_ref, jint offset) {
-    jniThrowException(_env, "java/lang/UnsupportedOperationException",
-        "eglCreatePlatformPixmapSurface");
+    if ((true)) {
+        jniThrowException(_env, "java/lang/UnsupportedOperationException",
+            "eglCreatePlatformPixmapSurface");
+        return nullptr;
+    }
     return toEGLHandle(_env, eglsurfaceClass, eglsurfaceConstructor, (EGLSurface) 0);
 }
 
@@ -523,6 +531,7 @@
     }
     if (_exception) {
         jniThrowException(_env, _exceptionType, _exceptionMessage);
+        return nullptr;
     }
     return toEGLHandle(_env, eglimageClass, eglimageConstructor, _returnValue);
 }
diff --git a/core/jni/android_os_GraphicsEnvironment.cpp b/core/jni/android_os_GraphicsEnvironment.cpp
index 06625b3..e2e66ce 100644
--- a/core/jni/android_os_GraphicsEnvironment.cpp
+++ b/core/jni/android_os_GraphicsEnvironment.cpp
@@ -32,6 +32,17 @@
     android::GraphicsEnv::getInstance().setDriverPath(pathChars.c_str());
 }
 
+void setGpuStats_native(JNIEnv* env, jobject clazz, jstring driverPackageName,
+                        jstring driverVersionName, jlong driverVersionCode,
+                        jstring appPackageName) {
+    ScopedUtfChars driverPackageNameChars(env, driverPackageName);
+    ScopedUtfChars driverVersionNameChars(env, driverVersionName);
+    ScopedUtfChars appPackageNameChars(env, appPackageName);
+    android::GraphicsEnv::getInstance().setGpuStats(driverPackageNameChars.c_str(),
+                                                    driverVersionNameChars.c_str(),
+                                                    driverVersionCode, appPackageNameChars.c_str());
+}
+
 void setAngleInfo_native(JNIEnv* env, jobject clazz, jstring path, jstring appName, jstring devOptIn,
                          jobject rulesFd, jlong rulesOffset, jlong rulesLength) {
     ScopedUtfChars pathChars(env, path);
@@ -68,6 +79,7 @@
 const JNINativeMethod g_methods[] = {
     { "getCanLoadSystemLibraries", "()I", reinterpret_cast<void*>(getCanLoadSystemLibraries_native) },
     { "setDriverPath", "(Ljava/lang/String;)V", reinterpret_cast<void*>(setDriverPath) },
+    { "setGpuStats", "(Ljava/lang/String;Ljava/lang/String;JLjava/lang/String;)V", reinterpret_cast<void*>(setGpuStats_native) },
     { "setAngleInfo", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/io/FileDescriptor;JJ)V", reinterpret_cast<void*>(setAngleInfo_native) },
     { "setLayerPaths", "(Ljava/lang/ClassLoader;Ljava/lang/String;)V", reinterpret_cast<void*>(setLayerPaths_native) },
     { "setDebugLayers", "(Ljava/lang/String;)V", reinterpret_cast<void*>(setDebugLayers_native) },
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index 4101c04..a212f47 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -104,6 +104,12 @@
   jfieldID mScreenHeightDpOffset;
 } gConfigurationOffsets;
 
+static struct arraymap_offsets_t {
+  jclass classObject;
+  jmethodID constructor;
+  jmethodID put;
+} gArrayMapOffsets;
+
 jclass g_stringClass = nullptr;
 
 // ----------------------------------------------------------------------------
@@ -326,6 +332,50 @@
   return *AssetManagerForNdkAssetManager(reinterpret_cast<AAssetManager*>(ptr));
 }
 
+static jobject NativeGetOverlayableMap(JNIEnv* env, jclass /*clazz*/, jlong ptr,
+                                        jstring package_name) {
+  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+  const ScopedUtfChars package_name_utf8(env, package_name);
+  CHECK(package_name_utf8.c_str() != nullptr);
+  const std::string std_package_name(package_name_utf8.c_str());
+  const std::unordered_map<std::string, std::string>* map = nullptr;
+
+  assetmanager->ForEachPackage([&](const std::string& this_package_name, uint8_t package_id) {
+    if (this_package_name == std_package_name) {
+      map = assetmanager->GetOverlayableMapForPackage(package_id);
+    }
+  });
+
+  if (map == nullptr) {
+    return nullptr;
+  }
+
+  jobject array_map = env->NewObject(gArrayMapOffsets.classObject, gArrayMapOffsets.constructor);
+  if (array_map == nullptr) {
+    return nullptr;
+  }
+
+  for (const auto& iter : *map) {
+    jstring name = env->NewStringUTF(iter.first.c_str());
+    if (env->ExceptionCheck()) {
+      return nullptr;
+    }
+
+    jstring actor = env->NewStringUTF(iter.second.c_str());
+    if (env->ExceptionCheck()) {
+      env->DeleteLocalRef(name);
+      return nullptr;
+    }
+
+    env->CallObjectMethod(array_map, gArrayMapOffsets.put, name, actor);
+
+    env->DeleteLocalRef(name);
+    env->DeleteLocalRef(actor);
+  }
+
+  return array_map;
+}
+
 static jobject ReturnParcelFileDescriptor(JNIEnv* env, std::unique_ptr<Asset> asset,
                                           jlongArray out_offsets) {
   off64_t start_offset, length;
@@ -1105,6 +1155,46 @@
   return array;
 }
 
+static jintArray NativeAttributeResolutionStack(
+    JNIEnv* env, jclass /*clazz*/, jlong ptr,
+    jlong theme_ptr, jint xml_style_res,
+    jint def_style_attr, jint def_style_resid) {
+
+  ScopedLock<AssetManager2> assetmanager(AssetManagerFromLong(ptr));
+  Theme* theme = reinterpret_cast<Theme*>(theme_ptr);
+  CHECK(theme->GetAssetManager() == &(*assetmanager));
+  (void) assetmanager;
+
+  // Load default style from attribute, if specified...
+  uint32_t def_style_flags = 0u;
+  if (def_style_attr != 0) {
+    Res_value value;
+    if (theme->GetAttribute(def_style_attr, &value, &def_style_flags) != kInvalidCookie) {
+      if (value.dataType == Res_value::TYPE_REFERENCE) {
+        def_style_resid = value.data;
+      }
+    }
+  }
+
+  auto style_stack = assetmanager->GetBagResIdStack(xml_style_res);
+  auto def_style_stack = assetmanager->GetBagResIdStack(def_style_resid);
+
+  jintArray array = env->NewIntArray(style_stack.size() + def_style_stack.size());
+  if (env->ExceptionCheck()) {
+    return nullptr;
+  }
+
+  for (uint32_t i = 0; i < style_stack.size(); i++) {
+    jint attr_resid = style_stack[i];
+    env->SetIntArrayRegion(array, i, 1, &attr_resid);
+  }
+  for (uint32_t i = 0; i < def_style_stack.size(); i++) {
+    jint attr_resid = def_style_stack[i];
+    env->SetIntArrayRegion(array, style_stack.size() + i, 1, &attr_resid);
+  }
+  return array;
+}
+
 static void NativeApplyStyle(JNIEnv* env, jclass /*clazz*/, jlong ptr, jlong theme_ptr,
                              jint def_style_attr, jint def_style_resid, jlong xml_parser_ptr,
                              jintArray java_attrs, jlong out_values_ptr, jlong out_indices_ptr) {
@@ -1456,6 +1546,7 @@
      (void*)NativeGetSizeConfigurations},
 
     // Style attribute related methods.
+    {"nativeAttributeResolutionStack", "(JJIII)[I", (void*)NativeAttributeResolutionStack},
     {"nativeApplyStyle", "(JJIIJ[IJJ)V", (void*)NativeApplyStyle},
     {"nativeResolveAttrs", "(JJII[I[I[I[I)Z", (void*)NativeResolveAttrs},
     {"nativeRetrieveAttributes", "(JJ[I[I[I)Z", (void*)NativeRetrieveAttributes},
@@ -1483,6 +1574,8 @@
     {"nativeVerifySystemIdmaps", "()V", (void*)NativeVerifySystemIdmaps},
     {"nativeCreateIdmapsForStaticOverlaysTargetingAndroid", "()[Ljava/lang/String;",
      (void*)NativeCreateIdmapsForStaticOverlaysTargetingAndroid},
+    {"nativeGetOverlayableMap", "(JLjava/lang/String;)Ljava/util/Map;",
+     (void*)NativeGetOverlayableMap},
 
     // Global management/debug methods.
     {"getGlobalAssetCount", "()I", (void*)NativeGetGlobalAssetCount},
@@ -1534,6 +1627,14 @@
   gConfigurationOffsets.mScreenHeightDpOffset =
       GetFieldIDOrDie(env, configurationClass, "screenHeightDp", "I");
 
+  jclass arrayMapClass = FindClassOrDie(env, "android/util/ArrayMap");
+  gArrayMapOffsets.classObject = MakeGlobalRefOrDie(env, arrayMapClass);
+  gArrayMapOffsets.constructor =
+      GetMethodIDOrDie(env, gArrayMapOffsets.classObject, "<init>", "()V");
+  gArrayMapOffsets.put =
+      GetMethodIDOrDie(env, gArrayMapOffsets.classObject, "put",
+                       "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
+
   return RegisterMethodsOrDie(env, "android/content/res/AssetManager", gAssetManagerMethods,
                               NELEM(gAssetManagerMethods));
 }
diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp
index c1b5aae..191472d 100644
--- a/core/jni/android_view_DisplayEventReceiver.cpp
+++ b/core/jni/android_view_DisplayEventReceiver.cpp
@@ -59,8 +59,8 @@
     sp<MessageQueue> mMessageQueue;
     DisplayEventReceiver mReceiver;
 
-    virtual void dispatchVsync(nsecs_t timestamp, int32_t id, uint32_t count);
-    virtual void dispatchHotplug(nsecs_t timestamp, int32_t id, bool connected);
+    void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count) override;
+    void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId, bool connected) override;
 };
 
 
@@ -84,28 +84,30 @@
     DisplayEventDispatcher::dispose();
 }
 
-void NativeDisplayEventReceiver::dispatchVsync(nsecs_t timestamp, int32_t id, uint32_t count) {
+void NativeDisplayEventReceiver::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId,
+                                               uint32_t count) {
     JNIEnv* env = AndroidRuntime::getJNIEnv();
 
     ScopedLocalRef<jobject> receiverObj(env, jniGetReferent(env, mReceiverWeakGlobal));
     if (receiverObj.get()) {
         ALOGV("receiver %p ~ Invoking vsync handler.", this);
         env->CallVoidMethod(receiverObj.get(),
-                gDisplayEventReceiverClassInfo.dispatchVsync, timestamp, id, count);
+                gDisplayEventReceiverClassInfo.dispatchVsync, timestamp, displayId, count);
         ALOGV("receiver %p ~ Returned from vsync handler.", this);
     }
 
     mMessageQueue->raiseAndClearException(env, "dispatchVsync");
 }
 
-void NativeDisplayEventReceiver::dispatchHotplug(nsecs_t timestamp, int32_t id, bool connected) {
+void NativeDisplayEventReceiver::dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId,
+                                                 bool connected) {
     JNIEnv* env = AndroidRuntime::getJNIEnv();
 
     ScopedLocalRef<jobject> receiverObj(env, jniGetReferent(env, mReceiverWeakGlobal));
     if (receiverObj.get()) {
         ALOGV("receiver %p ~ Invoking hotplug handler.", this);
         env->CallVoidMethod(receiverObj.get(),
-                gDisplayEventReceiverClassInfo.dispatchHotplug, timestamp, id, connected);
+                gDisplayEventReceiverClassInfo.dispatchHotplug, timestamp, displayId, connected);
         ALOGV("receiver %p ~ Returned from hotplug handler.", this);
     }
 
@@ -175,9 +177,9 @@
     gDisplayEventReceiverClassInfo.clazz = MakeGlobalRefOrDie(env, clazz);
 
     gDisplayEventReceiverClassInfo.dispatchVsync = GetMethodIDOrDie(env,
-            gDisplayEventReceiverClassInfo.clazz, "dispatchVsync", "(JII)V");
+            gDisplayEventReceiverClassInfo.clazz, "dispatchVsync", "(JJI)V");
     gDisplayEventReceiverClassInfo.dispatchHotplug = GetMethodIDOrDie(env,
-            gDisplayEventReceiverClassInfo.clazz, "dispatchHotplug", "(JIZ)V");
+            gDisplayEventReceiverClassInfo.clazz, "dispatchHotplug", "(JJZ)V");
 
     return res;
 }
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index 67a56ae..464f249 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -58,6 +58,8 @@
 
 namespace android {
 
+using ui::Dataspace;
+
 static const char* const OutOfResourcesException =
     "android/view/Surface$OutOfResourcesException";
 
@@ -132,6 +134,7 @@
         case PublicFormat::JPEG:
         case PublicFormat::DEPTH_POINT_CLOUD:
         case PublicFormat::DEPTH_JPEG:
+        case PublicFormat::HEIC:
             return HAL_PIXEL_FORMAT_BLOB;
         case PublicFormat::DEPTH16:
             return HAL_PIXEL_FORMAT_Y16;
@@ -146,32 +149,44 @@
 
 android_dataspace android_view_Surface_mapPublicFormatToHalDataspace(
         PublicFormat f) {
+    Dataspace dataspace;
     switch(f) {
         case PublicFormat::JPEG:
-            return HAL_DATASPACE_V0_JFIF;
+            dataspace = Dataspace::V0_JFIF;
+            break;
         case PublicFormat::DEPTH_POINT_CLOUD:
         case PublicFormat::DEPTH16:
         case PublicFormat::RAW_DEPTH:
-            return HAL_DATASPACE_DEPTH;
+            dataspace = Dataspace::DEPTH;
+            break;
         case PublicFormat::RAW_SENSOR:
         case PublicFormat::RAW_PRIVATE:
         case PublicFormat::RAW10:
         case PublicFormat::RAW12:
-            return HAL_DATASPACE_ARBITRARY;
+            dataspace = Dataspace::ARBITRARY;
+            break;
         case PublicFormat::YUV_420_888:
         case PublicFormat::NV21:
         case PublicFormat::YV12:
-            return HAL_DATASPACE_V0_JFIF;
+            dataspace = Dataspace::V0_JFIF;
+            break;
         case PublicFormat::DEPTH_JPEG:
-            return static_cast<android_dataspace> (HAL_DATASPACE_DYNAMIC_DEPTH);
+            dataspace = Dataspace::DYNAMIC_DEPTH;
+            break;
+        case PublicFormat::HEIC:
+            dataspace = Dataspace::HEIF;
+            break;
         default:
             // Most formats map to UNKNOWN
-            return HAL_DATASPACE_UNKNOWN;
+            dataspace = Dataspace::UNKNOWN;
+            break;
     }
+    return static_cast<android_dataspace>(dataspace);
 }
 
 PublicFormat android_view_Surface_mapHalFormatDataspaceToPublicFormat(
         int format, android_dataspace dataSpace) {
+    Dataspace ds = static_cast<Dataspace>(dataSpace);
     switch(format) {
         case HAL_PIXEL_FORMAT_RGBA_8888:
         case HAL_PIXEL_FORMAT_RGBX_8888:
@@ -187,8 +202,8 @@
             // Enums overlap in both name and value
             return static_cast<PublicFormat>(format);
         case HAL_PIXEL_FORMAT_RAW16:
-            switch (dataSpace) {
-                case HAL_DATASPACE_DEPTH:
+            switch (ds) {
+                case Dataspace::DEPTH:
                   return PublicFormat::RAW_DEPTH;
                 default:
                   return PublicFormat::RAW_SENSOR;
@@ -210,8 +225,8 @@
             return PublicFormat::PRIVATE;
         case HAL_PIXEL_FORMAT_Y16:
             // Dataspace-dependent
-            switch (dataSpace) {
-                case HAL_DATASPACE_DEPTH:
+            switch (ds) {
+                case Dataspace::DEPTH:
                     return PublicFormat::DEPTH16;
                 default:
                     // Assume non-depth Y16 is just Y16.
@@ -220,11 +235,13 @@
             break;
         case HAL_PIXEL_FORMAT_BLOB:
             // Dataspace-dependent
-            switch (dataSpace) {
-                case HAL_DATASPACE_DEPTH:
+            switch (ds) {
+                case Dataspace::DEPTH:
                     return PublicFormat::DEPTH_POINT_CLOUD;
-                case HAL_DATASPACE_V0_JFIF:
+                case Dataspace::V0_JFIF:
                     return PublicFormat::JPEG;
+                case Dataspace::HEIF:
+                    return PublicFormat::HEIC;
                 default:
                     if (dataSpace == static_cast<android_dataspace>(HAL_DATASPACE_DYNAMIC_DEPTH)) {
                         return PublicFormat::DEPTH_JPEG;
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index fad2fe0..6b8d8b1 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -178,12 +178,13 @@
 
 static void nativeRelease(JNIEnv* env, jclass clazz, jlong nativeObject) {
     sp<SurfaceControl> ctrl(reinterpret_cast<SurfaceControl *>(nativeObject));
+    ctrl->release();
     ctrl->decStrong((void *)nativeCreate);
 }
 
 static void nativeDestroy(JNIEnv* env, jclass clazz, jlong nativeObject) {
     sp<SurfaceControl> ctrl(reinterpret_cast<SurfaceControl *>(nativeObject));
-    ctrl->clear();
+    ctrl->destroy();
     ctrl->decStrong((void *)nativeCreate);
 }
 
@@ -483,8 +484,29 @@
     transaction->setLayerStack(ctrl, layerStack);
 }
 
-static jobject nativeGetBuiltInDisplay(JNIEnv* env, jclass clazz, jint id) {
-    sp<IBinder> token(SurfaceComposerClient::getBuiltInDisplay(id));
+static jlongArray nativeGetPhysicalDisplayIds(JNIEnv* env, jclass clazz) {
+    const auto displayIds = SurfaceComposerClient::getPhysicalDisplayIds();
+    jlongArray array = env->NewLongArray(displayIds.size());
+    if (array == nullptr) {
+        jniThrowException(env, "java/lang/OutOfMemoryError", nullptr);
+        return nullptr;
+    }
+
+    if (displayIds.empty()) {
+        return array;
+    }
+
+    jlong* values = env->GetLongArrayElements(array, 0);
+    for (size_t i = 0; i < displayIds.size(); ++i) {
+        values[i] = static_cast<jlong>(displayIds[i]);
+    }
+
+    env->ReleaseLongArrayElements(array, values, 0);
+    return array;
+}
+
+static jobject nativeGetPhysicalDisplayToken(JNIEnv* env, jclass clazz, jlong physicalDisplayId) {
+    sp<IBinder> token = SurfaceComposerClient::getPhysicalDisplayToken(physicalDisplayId);
     return javaObjectForIBinder(env, token);
 }
 
@@ -1145,8 +1167,10 @@
             (void*)nativeSetCornerRadius },
     {"nativeSetLayerStack", "(JJI)V",
             (void*)nativeSetLayerStack },
-    {"nativeGetBuiltInDisplay", "(I)Landroid/os/IBinder;",
-            (void*)nativeGetBuiltInDisplay },
+    {"nativeGetPhysicalDisplayIds", "()[J",
+            (void*)nativeGetPhysicalDisplayIds },
+    {"nativeGetPhysicalDisplayToken", "(J)Landroid/os/IBinder;",
+            (void*)nativeGetPhysicalDisplayToken },
     {"nativeCreateDisplay", "(Ljava/lang/String;Z)Landroid/os/IBinder;",
             (void*)nativeCreateDisplay },
     {"nativeDestroyDisplay", "(Landroid/os/IBinder;)V",
@@ -1314,4 +1338,4 @@
     return err;
 }
 
-};
+} // namespace android
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 2c058cd..8c73630 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -1202,12 +1202,12 @@
 
 static JavaVM* mJvm = nullptr;
 
-static void attachRenderThreadToJvm() {
+static void attachRenderThreadToJvm(const char* name) {
     LOG_ALWAYS_FATAL_IF(!mJvm, "No jvm but we set the hook??");
 
     JavaVMAttachArgs args;
     args.version = JNI_VERSION_1_4;
-    args.name = NULL;
+    args.name = name;
     args.group = NULL;
     JNIEnv* env;
     mJvm->AttachCurrentThreadAsDaemon(&env, (void*) &args);
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 5a65028..d04db92 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -598,55 +598,80 @@
     return 0;
 }
 
+static void CreateDir(const std::string& dir,
+                      mode_t mode, uid_t uid, gid_t gid,
+                      fail_fn_t fail_fn) {
+    if (TEMP_FAILURE_RETRY(access(dir.c_str(), F_OK)) == 0) {
+        return;
+    } else if (errno != ENOENT) {
+        fail_fn(CREATE_ERROR("Failed to stat %s: %s", dir.c_str(), strerror(errno)));
+    }
+    if (fs_prepare_dir(dir.c_str(), mode, uid, gid) != 0) {
+        fail_fn(CREATE_ERROR("fs_prepare_dir failed on %s: %s",
+                dir.c_str(), strerror(errno)));
+    }
+}
+
 static void CreatePkgSandbox(uid_t uid, const std::string& package_name, fail_fn_t fail_fn) {
     // Create /mnt/user/0/package/<package-name>
     userid_t user_id = multiuser_get_user_id(uid);
     std::string pkg_sandbox_dir = StringPrintf("/mnt/user/%d", user_id);
-    if (fs_prepare_dir(pkg_sandbox_dir.c_str(), 0751, AID_ROOT, AID_ROOT) != 0) {
-        fail_fn(CREATE_ERROR("fs_prepare_dir failed on %s", pkg_sandbox_dir.c_str()));
-    }
+    CreateDir(pkg_sandbox_dir, 0751, AID_ROOT, AID_ROOT, fail_fn);
 
     StringAppendF(&pkg_sandbox_dir, "/package");
-    if (fs_prepare_dir(pkg_sandbox_dir.c_str(), 0700, AID_ROOT, AID_ROOT) != 0) {
-        fail_fn(CREATE_ERROR("fs_prepare_dir failed on %s", pkg_sandbox_dir.c_str()));
-    }
+    CreateDir(pkg_sandbox_dir, 0700, AID_ROOT, AID_ROOT, fail_fn);
 
     StringAppendF(&pkg_sandbox_dir, "/%s", package_name.c_str());
-    if (fs_prepare_dir(pkg_sandbox_dir.c_str(), 0755, uid, uid) != 0) {
-        fail_fn(CREATE_ERROR("fs_prepare_dir failed on %s", pkg_sandbox_dir.c_str()));
-    }
+    CreateDir(pkg_sandbox_dir, 0700, AID_ROOT, AID_ROOT, fail_fn);
 }
 
 static void BindMount(const std::string& sourceDir, const std::string& targetDir,
                       fail_fn_t fail_fn) {
     if (TEMP_FAILURE_RETRY(mount(sourceDir.c_str(), targetDir.c_str(), nullptr,
-                                 MS_BIND | MS_REC, nullptr)) == -1) {
+                                 MS_BIND, nullptr)) == -1) {
         fail_fn(CREATE_ERROR("Failed to mount %s to %s: %s",
                              sourceDir.c_str(), targetDir.c_str(), strerror(errno)));
     }
-
-    if (TEMP_FAILURE_RETRY(mount(nullptr, targetDir.c_str(), nullptr,
-                                 MS_SLAVE | MS_REC, nullptr)) == -1) {
-        fail_fn(CREATE_ERROR("Failed to set MS_SLAVE for %s", targetDir.c_str()));
-    }
 }
 
 static void MountPkgSpecificDir(const std::string& mntSourceRoot,
                                 const std::string& mntTargetRoot,
                                 const std::string& packageName,
+                                uid_t uid,
                                 const char* dirName,
                                 fail_fn_t fail_fn) {
     std::string mntSourceDir = StringPrintf("%s/Android/%s/%s",
             mntSourceRoot.c_str(), dirName, packageName.c_str());
+    CreateDir(mntSourceDir, 0755, uid, uid, fail_fn);
+
     std::string mntTargetDir = StringPrintf("%s/Android/%s/%s",
             mntTargetRoot.c_str(), dirName, packageName.c_str());
+    CreateDir(mntTargetDir, 0755, uid, uid, fail_fn);
 
     BindMount(mntSourceDir, mntTargetDir, fail_fn);
 }
 
+
+static void createPkgSpecificDirRoots(const std::string& parentDir,
+                                      bool createSandbox,
+                                      mode_t mode, uid_t uid, gid_t gid,
+                                      fail_fn_t fail_fn) {
+    std::string androidDir = StringPrintf("%s/Android", parentDir.c_str());
+    CreateDir(androidDir, mode, uid, gid, fail_fn);
+    std::vector<std::string> dirs = {"data", "media", "obb"};
+    if (createSandbox) {
+        dirs.push_back("sandbox");
+    }
+    for (auto& dir : dirs) {
+        std::string path = StringPrintf("%s/%s", androidDir.c_str(), dir.c_str());
+        CreateDir(path, mode, uid, gid, fail_fn);
+    }
+}
+
 static void PreparePkgSpecificDirs(const std::vector<std::string>& packageNames,
                                    const std::vector<std::string>& volumeLabels,
-                                   bool mountAllObbs, userid_t userId, fail_fn_t fail_fn) {
+                                   bool mountAllObbs, const std::string& sandboxId,
+                                   userid_t userId, uid_t uid, fail_fn_t fail_fn) {
     for (auto& label : volumeLabels) {
         std::string mntSource = StringPrintf("/mnt/runtime/write/%s", label.c_str());
         std::string mntTarget = StringPrintf("/storage/%s", label.c_str());
@@ -655,11 +680,26 @@
             StringAppendF(&mntTarget, "/%d", userId);
         }
 
+        if (TEMP_FAILURE_RETRY(access(mntSource.c_str(), F_OK)) < 0) {
+            ALOGE("Can't access %s: %s", mntSource.c_str(), strerror(errno));
+            continue;
+        }
+
+        // Create /mnt/runtime/write/emulated/0/Android/{data,media,obb,sandbox}
+        createPkgSpecificDirRoots(mntSource, true, 0700, AID_ROOT, AID_ROOT, fail_fn);
+
+        std::string sandboxSource = StringPrintf("%s/Android/sandbox/%s",
+            mntSource.c_str(), sandboxId.c_str());
+        CreateDir(sandboxSource, 0755, uid, uid, fail_fn);
+        BindMount(sandboxSource, mntTarget, fail_fn);
+
+        // Create /storage/emulated/0/Android/{data,media,obb}
+        createPkgSpecificDirRoots(mntTarget, false, 0755, uid, uid, fail_fn);
         for (auto& package : packageNames) {
-            MountPkgSpecificDir(mntSource, mntTarget, package, "data", fail_fn);
-            MountPkgSpecificDir(mntSource, mntTarget, package, "media", fail_fn);
+            MountPkgSpecificDir(mntSource, mntTarget, package, uid, "data", fail_fn);
+            MountPkgSpecificDir(mntSource, mntTarget, package, uid, "media", fail_fn);
             if (!mountAllObbs) {
-                MountPkgSpecificDir(mntSource, mntTarget, package, "obb", fail_fn);
+                MountPkgSpecificDir(mntSource, mntTarget, package, uid, "obb", fail_fn);
             }
         }
 
@@ -676,7 +716,8 @@
 static void MountEmulatedStorage(uid_t uid, jint mount_mode,
         bool force_mount_namespace, const std::string& package_name,
         const std::vector<std::string>& packages_for_uid,
-        const std::vector<std::string>& visible_vol_ids, fail_fn_t fail_fn) {
+        const std::vector<std::string>& visible_vol_ids, const std::string& sandbox_id,
+        fail_fn_t fail_fn) {
     // See storage config details at http://source.android.com/tech/storage/
 
     String8 storageSource;
@@ -727,7 +768,7 @@
                                      strerror(errno)));
             }
         } else {
-            if (package_name.empty()) {
+            if (package_name.empty() || sandbox_id.empty()) {
                 return;
             }
 
@@ -773,7 +814,7 @@
             // care of by vold later.
             if (sandboxAlreadyCreated) {
                 PreparePkgSpecificDirs(packages_for_uid, visible_vol_ids,
-                    mount_mode == MOUNT_EXTERNAL_INSTALLER, user_id, fail_fn);
+                    mount_mode == MOUNT_EXTERNAL_INSTALLER, sandbox_id, user_id, uid, fail_fn);
             }
         }
     } else {
@@ -1110,7 +1151,7 @@
                              bool is_child_zygote, jstring managed_instruction_set,
                              jstring managed_app_data_dir, jstring managed_package_name,
                              jobjectArray managed_pacakges_for_uid,
-                             jobjectArray managed_visible_vol_ids) {
+                             jobjectArray managed_visible_vol_ids, jstring managed_sandbox_id) {
   const char* process_name = is_system_server ? "system_server" : "zygote";
   auto fail_fn = std::bind(ZygoteFailure, env, process_name, managed_nice_name, _1);
   auto extract_fn = std::bind(ExtractJString, env, process_name, managed_nice_name, _1);
@@ -1120,6 +1161,7 @@
   auto instruction_set = extract_fn(managed_instruction_set);
   auto app_data_dir = extract_fn(managed_app_data_dir);
   auto package_name = extract_fn(managed_package_name);
+  auto sandbox_id = extract_fn(managed_sandbox_id);
 
   // Keep capabilities across UID change, unless we're staying root.
   if (uid != 0) {
@@ -1162,7 +1204,7 @@
       value_or(std::vector<std::string>());
 
   MountEmulatedStorage(uid, mount_external, use_native_bridge, package_name.value(),
-                       packages_for_uid, visible_vol_ids, fail_fn);
+                       packages_for_uid, visible_vol_ids, sandbox_id.value_or(""), fail_fn);
 
   // If this zygote isn't root, it won't be able to create a process group,
   // since the directory is owned by root.
@@ -1462,7 +1504,7 @@
         jint mount_external, jstring se_info, jstring nice_name,
         jintArray managed_fds_to_close, jintArray managed_fds_to_ignore, jboolean is_child_zygote,
         jstring instruction_set, jstring app_data_dir, jstring package_name,
-        jobjectArray packages_for_uid, jobjectArray visible_vol_ids) {
+        jobjectArray packages_for_uid, jobjectArray visible_vol_ids, jstring sandbox_id) {
     jlong capabilities = CalculateCapabilities(env, uid, gid, gids, is_child_zygote);
 
     if (UNLIKELY(managed_fds_to_close == nullptr)) {
@@ -1494,7 +1536,7 @@
                        capabilities, capabilities,
                        mount_external, se_info, nice_name, false,
                        is_child_zygote == JNI_TRUE, instruction_set, app_data_dir,
-                       package_name, packages_for_uid, visible_vol_ids);
+                       package_name, packages_for_uid, visible_vol_ids, sandbox_id);
     }
     return pid;
 }
@@ -1520,7 +1562,7 @@
       SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits,
                        permitted_capabilities, effective_capabilities,
                        MOUNT_EXTERNAL_DEFAULT, nullptr, nullptr, true,
-                       false, nullptr, nullptr, nullptr, nullptr, nullptr);
+                       false, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr);
   } else if (pid > 0) {
       // The zygote process checks whether the child process has died or not.
       ALOGI("System server process %d has been created", pid);
@@ -1674,14 +1716,15 @@
     jint runtime_flags, jobjectArray rlimits,
     jint mount_external, jstring se_info, jstring nice_name,
     jboolean is_child_zygote, jstring instruction_set, jstring app_data_dir,
-    jstring package_name, jobjectArray packages_for_uid, jobjectArray visible_vol_ids) {
+    jstring package_name, jobjectArray packages_for_uid, jobjectArray visible_vol_ids,
+    jstring sandbox_id) {
   jlong capabilities = CalculateCapabilities(env, uid, gid, gids, is_child_zygote);
 
   SpecializeCommon(env, uid, gid, gids, runtime_flags, rlimits,
                    capabilities, capabilities,
                    mount_external, se_info, nice_name, false,
                    is_child_zygote == JNI_TRUE, instruction_set, app_data_dir,
-                   package_name, packages_for_uid, visible_vol_ids);
+                   package_name, packages_for_uid, visible_vol_ids, sandbox_id);
 }
 
 /**
@@ -1772,7 +1815,7 @@
     { "nativeSecurityInit", "()V",
       (void *) com_android_internal_os_Zygote_nativeSecurityInit },
     { "nativeForkAndSpecialize",
-      "(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)I",
+      "(II[II[[IILjava/lang/String;Ljava/lang/String;[I[IZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)I",
       (void *) com_android_internal_os_Zygote_nativeForkAndSpecialize },
     { "nativeForkSystemServer", "(II[II[[IJJ)I",
       (void *) com_android_internal_os_Zygote_nativeForkSystemServer },
@@ -1787,7 +1830,7 @@
     { "nativeForkBlastula", "(II[I)I",
       (void *) com_android_internal_os_Zygote_nativeForkBlastula },
     { "nativeSpecializeBlastula",
-      "(II[II[[IILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)V",
+      "(II[II[[IILjava/lang/String;Ljava/lang/String;ZLjava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)V",
       (void *) com_android_internal_os_Zygote_nativeSpecializeBlastula },
     { "nativeGetSocketFDs", "(Z)V",
       (void *) com_android_internal_os_Zygote_nativeGetSocketFDs },
diff --git a/core/jni/include/android_runtime/android_view_Surface.h b/core/jni/include/android_runtime/android_view_Surface.h
index 984e942..3f7c00c 100644
--- a/core/jni/include/android_runtime/android_view_Surface.h
+++ b/core/jni/include/android_runtime/android_view_Surface.h
@@ -55,10 +55,11 @@
     DEPTH_POINT_CLOUD = 0x101,
     RAW_DEPTH         = 0x1002, // @hide
     YV12              = 0x32315659,
-    Y8                = 0x20203859, // @hide
+    Y8                = 0x20203859,
     Y16               = 0x20363159, // @hide
     DEPTH16           = 0x44363159,
     DEPTH_JPEG        = 0x69656963,
+    HEIC              = 0x48454946,
 };
 
 /* Gets the underlying ANativeWindow for a Surface. */
diff --git a/core/jni/runtime_native_boot-flags-test.sh b/core/jni/runtime_native_boot-flags-test.sh
new file mode 100755
index 0000000..66e18bb
--- /dev/null
+++ b/core/jni/runtime_native_boot-flags-test.sh
@@ -0,0 +1,244 @@
+#!/bin/bash
+
+# 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.
+#
+
+# Test Android Runtime (Boot) device configuration flags (living in namespace
+# `runtime_native_boot`).
+
+me=$(basename $0)
+
+# Namespace containing the tested flag.
+namespace=runtime_native_boot
+# Default set of checked zygote processes.
+zygotes=
+
+# Status of whole test script.
+exit_status=0
+
+function say {
+  echo "$me: $*"
+}
+
+function banner {
+  local separator=$(echo "$@" | sed s/./=/g )
+  say "$separator"
+  say "$@"
+  say "$separator"
+}
+
+function fail {
+  say "FAILED: $@"
+  exit_status=1
+}
+
+function reboot_and_wait_for_device {
+  say "Rebooting device..."
+  adb reboot
+  adb wait-for-device >/dev/null
+  # Wait until the device has finished booting. Give the device 60 iterations
+  # (~60 seconds) to try and finish booting before declaring defeat.
+  local niters=60
+  for i in $(seq $niters); do
+    [[ $(adb shell getprop sys.boot_completed) -eq 1 ]] && return 0
+    sleep 1
+  done
+  fail "Device did not finish booting before timeout (~$niters seconds)"
+}
+
+# check_device_config_flag CONTEXT FLAG VALUE
+# -------------------------------------------
+# Check that the device configuration flag FLAG is set to VALUE. Use CONTEXT in
+# logging.
+function check_device_config_flag {
+  local context=$1
+  local flag=$2
+  local value=$3
+
+  say "[$context] Check that the device configuration flag is set..."
+  local flag_value=$(adb shell device_config get "$namespace" "$flag")
+  [[ "$flag_value" = "$value" ]] \
+    || fail "Device configuration flag \`$flag\` set to \`$flag_value\` (expected \`$value\`)"
+}
+
+# check_no_device_config_flag CONTEXT FLAG
+# ----------------------------------------
+# Check that the device configuration flag FLAG is not set. Use CONTEXT in
+# logging.
+function check_no_device_config_flag {
+  local context=$1
+  local flag=$2
+
+  say "[$context] Check that the device configuration flag is not set..."
+  local flag_value=$(adb shell device_config get "$namespace" "$flag")
+  [[ "$flag_value" = null ]] \
+    || fail "Device configuration flag \`$flag\` set to \`$flag_value\` (expected `null`)"
+}
+
+# get_system_property PROP
+# ------------------------
+# Get system property PROP associated with a device configuration flag.
+function get_system_property {
+  local prop=$1
+
+  # Note that we need to be root to read that system property.
+  adb root >/dev/null
+  local prop_value=$(adb shell getprop "$prop")
+  adb unroot >/dev/null
+  echo "$prop_value"
+}
+
+# check_system_property CONTEXT PROP VALUE
+# ----------------------------------------
+# Check that the system property PROP associated with a device configuration
+# flag is set to VALUE. Use CONTEXT in logging.
+function check_system_property {
+  local context=$1
+  local prop=$2
+  local value=$3
+
+  say "[$context] Check that the persistent system property is set..."
+  local prop_value=$(get_system_property "$prop")
+  [[ "$prop_value" = "$value" ]] \
+    || fail "System property \`$prop\` set to \`$prop_value\` (expected \`$value\`)"
+}
+
+# check_no_system_property CONTEXT PROP
+# -------------------------------------
+# Check that the system property PROP associated with a device configuration
+# flag is not set. Use CONTEXT in logging.
+function check_no_system_property {
+  local context=$1
+  local prop=$2
+
+  say "[$context] Check that the persistent system property is not set..."
+  local prop_value=$(get_system_property "$prop")
+  [[ -z "$prop_value" ]] \
+    || fail "System property \`$prop\` set to \`$prop_value\` (expected unset property)"
+}
+
+# find_zygote_runtime_option ZYGOTE RUNTIME_OPTION
+# ------------------------------------------------
+# Return whether ZYGOTE is passed RUNTIME_OPTION.
+function find_zygote_runtime_option {
+  local zygote=$1
+  local runtime_option=$2
+
+  adb logcat -d -s "$zygote" | grep -q -e "option\[[0-9]\+\]=$runtime_option"
+}
+
+# check_zygote_gc_runtime_option CONTEXT VALUE
+# --------------------------------------------
+# Check that all zygote processes are passed device configuration flag VALUE as
+# GC runtime option. Use CONTEXT in logging.
+function check_zygote_gc_runtime_option {
+  local context=$1
+  local value=$2
+
+  say \
+    "[$context] Check that all zygote processes are passed the flag value as a GC runtime option..."
+  local runtime_option="-Xgc:$value"
+  for zygote in $zygotes; do
+    find_zygote_runtime_option "$zygote" "$runtime_option"\
+      || fail "Found no \`$runtime_option\` among runtime options passed to \`$zygote\`"
+  done
+}
+
+# check_no_zygote_gc_runtime_option CONTEXT VALUE
+# -----------------------------------------------
+# Check that no zygote process is passed device configuration flag VALUE as GC
+# runtime option.  Use CONTEXT in logging.
+function check_no_zygote_gc_runtime_option {
+  local context=$1
+  local value=$2
+
+  say "[$context] Check no zygote process is passed the flag value as a GC runtime option..."
+  local runtime_option="-Xgc:$value"
+  for zygote in $zygotes; do
+    find_zygote_runtime_option "$zygote" "$runtime_option"\
+      && fail "Found \`$runtime_option\` among runtime options passed to \`$zygote\`"
+  done
+}
+
+# test_android_runtime_flag FLAG VALUE
+# ------------------------------------
+# Test device configuration FLAG with VALUE.
+function test_android_runtime_flag {
+  local flag=$1
+  local value=$2
+
+  # Persistent system property (set after a reboot) associated with the device
+  # configuration flag.
+  local prop="persist.device_config.$namespace.$flag"
+
+  banner "Testing \`$flag\` value \`$value\`."
+
+  say "Setting device configuration flag..."
+  adb shell device_config put "$namespace" "$flag" "$value"
+  # Give some time to the device to digest this change before rebooting.
+  sleep 3
+
+  # Check that both the device configuration flag and the associated system
+  # property are set, but that the zygote hasn't had the flag passed to it as a
+  # GC runtime option (as we haven't rebooted yet).
+  local context="Flag set, before reboot"
+  check_device_config_flag "$context" "$flag" "$value"
+  check_system_property "$context" "$prop" "$value"
+  check_no_zygote_gc_runtime_option "$context" "$value"
+
+  # Reboot device for the flag value to take effect.
+  reboot_and_wait_for_device
+  context="Flag set, after 1st reboot"
+  check_device_config_flag "$context" "$flag" "$value"
+  check_system_property "$context" "$prop" "$value"
+  check_zygote_gc_runtime_option "$context" "$value"
+
+  # Reboot device a second time and check that the state has persisted.
+  reboot_and_wait_for_device
+  context="Flag set, after 2nd reboot"
+  check_device_config_flag "$context" "$flag" "$value"
+  check_system_property "$context" "$prop" "$value"
+  check_zygote_gc_runtime_option "$context" "$value"
+
+  say "Unsetting device configuration flag..."
+  adb shell device_config delete "$namespace" "$flag" >/dev/null
+  # Give some time to the device to digest this change before rebooting.
+  sleep 3
+
+  # Reboot and check that the device is back to its default state.
+  reboot_and_wait_for_device
+  context="Flag unset, after 3rd reboot"
+  check_no_device_config_flag "$context" "$flag"
+  check_no_system_property "$context" "$prop"
+  check_no_zygote_gc_runtime_option "$context" "$value"
+}
+
+# Enumerate Zygote processes.
+case $(adb shell getprop ro.zygote) in
+  (zygote32) zygotes="zygote";;
+  (zygote64) zygotes="zygote64";;
+  (zygote32_64|zygote64_32) zygotes="zygote zygote64";;
+esac
+
+# Test "gctype" flag values.
+test_android_runtime_flag gctype nogenerational_cc
+test_android_runtime_flag gctype generational_cc
+
+if [[ "$exit_status" -eq 0 ]]; then
+  banner "All tests passed."
+else
+  banner "Test(s) failed."
+fi
+exit $exit_status
diff --git a/core/proto/android/bluetooth/enums.proto b/core/proto/android/bluetooth/enums.proto
index 5b5c9c2..b4f3d1e 100644
--- a/core/proto/android/bluetooth/enums.proto
+++ b/core/proto/android/bluetooth/enums.proto
@@ -132,3 +132,9 @@
     // This socket is closed
     SOCKET_CONNECTION_STATE_DISCONNECTED = 5;
 }
+
+enum SocketRoleEnum {
+    SOCKET_ROLE_UNKNOWN = 0;
+    SOCKET_ROLE_LISTEN = 1;
+    SOCKET_ROLE_CONNECTION = 2;
+}
diff --git a/core/proto/android/hardware/biometrics/enums.proto b/core/proto/android/hardware/biometrics/enums.proto
index 91f2acb..973e3e6 100644
--- a/core/proto/android/hardware/biometrics/enums.proto
+++ b/core/proto/android/hardware/biometrics/enums.proto
@@ -43,4 +43,16 @@
     ACTION_AUTHENTICATE = 2;
     ACTION_ENUMERATE = 3;
     ACTION_REMOVE = 4;
+}
+
+enum IssueEnum {
+    ISSUE_UNKNOWN = 0;
+    // When a biometric HAL has crashed.
+    ISSUE_HAL_DEATH = 1;
+    // When Android Framework has a template that doesn't exist in the HAL. The framework
+    // is expected to remove its template to stay in sync with the HAL.
+    ISSUE_UNKNOWN_TEMPLATE_ENROLLED_FRAMEWORK = 2;
+    // When the HAL has a template that doesn't exist in Android Framework. The framework
+    // is expected to notify the HAL to remove this template to stay in sync with the framework.
+    ISSUE_UNKNOWN_TEMPLATE_ENROLLED_HAL = 3;
 }
\ No newline at end of file
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index a160451..d577653 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -259,6 +259,8 @@
         optional SettingProto app = 1;
         // Whether views are allowed to save their attribute data.
         optional SettingProto view_attributes = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        // Which application package is allowed to save view attribute data.
+        optional SettingProto view_attributes_application_package = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
     }
     optional Debug debug = 37;
 
diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto
index f3733fd..6360a5f 100644
--- a/core/proto/android/providers/settings/secure.proto
+++ b/core/proto/android/providers/settings/secure.proto
@@ -321,6 +321,7 @@
         optional SettingProto badging = 4 [ (android.privacy).dest = DEST_AUTOMATIC ];
         optional SettingProto show_note_about_notification_hiding = 5 [ (android.privacy).dest = DEST_AUTOMATIC ];
         optional SettingProto in_call_notification_enabled = 6 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto bubbles = 7 [ (android.privacy).dest = DEST_AUTOMATIC ];
     }
     optional Notification notification = 41;
 
diff --git a/core/proto/android/wifi/enums.proto b/core/proto/android/wifi/enums.proto
new file mode 100644
index 0000000..315c579
--- /dev/null
+++ b/core/proto/android/wifi/enums.proto
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+syntax = "proto2";
+package android.net.wifi;
+
+option java_outer_classname = "WifiProtoEnums";
+option java_multiple_files = true;
+
+/**
+ * Wifi Lock modes, primarily used in
+ * frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiLockManager.java.
+ */
+enum WifiModeEnum {
+    /**
+     * Deprecated.
+     * Wi-Fi will be kept active, and will behave normally.
+     */
+    WIFI_MODE_FULL = 1 [deprecated=true];
+
+    /**
+     * Deprecated.
+     * Wi-Fi will be kept active, but the only operation that will be supported is initiation of
+     * scans, and the subsequent reporting of scan results.
+     */
+    WIFI_MODE_SCAN_ONLY = 2 [deprecated=true];
+
+    /**
+     * Wi-Fi will not go to power save.
+     */
+    WIFI_MODE_FULL_HIGH_PERF = 3;
+
+    /**
+     * Wi-Fi will operate with a priority to achieve low latency.
+     */
+    WIFI_MODE_FULL_LOW_LATENCY = 4;
+}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index c7b528c..34ec92e 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -662,8 +662,7 @@
         android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_readContacts"
         android:description="@string/permdesc_readContacts"
-        android:protectionLevel="dangerous"
-        android:usageInfoRequired="true" />
+        android:protectionLevel="dangerous" />
 
     <!-- Allows an application to write the user's contacts data.
          <p>Protection level: dangerous
@@ -694,8 +693,7 @@
         android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_readCalendar"
         android:description="@string/permdesc_readCalendar"
-        android:protectionLevel="dangerous"
-        android:usageInfoRequired="true" />
+        android:protectionLevel="dangerous" />
 
     <!-- Allows an application to write the user's calendar data.
          <p>Protection level: dangerous
@@ -736,8 +734,7 @@
         android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_receiveSms"
         android:description="@string/permdesc_receiveSms"
-        android:protectionLevel="dangerous"
-        android:usageInfoRequired="true" />
+        android:protectionLevel="dangerous" />
 
     <!-- Allows an application to read SMS messages.
          <p>Protection level: dangerous
@@ -746,8 +743,7 @@
         android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_readSms"
         android:description="@string/permdesc_readSms"
-        android:protectionLevel="dangerous"
-        android:usageInfoRequired="true" />
+        android:protectionLevel="dangerous" />
 
     <!-- Allows an application to receive WAP push messages.
          <p>Protection level: dangerous
@@ -756,8 +752,7 @@
         android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_receiveWapPush"
         android:description="@string/permdesc_receiveWapPush"
-        android:protectionLevel="dangerous"
-        android:usageInfoRequired="true" />
+        android:protectionLevel="dangerous" />
 
     <!-- Allows an application to monitor incoming MMS messages.
         <p>Protection level: dangerous
@@ -766,8 +761,7 @@
         android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_receiveMms"
         android:description="@string/permdesc_receiveMms"
-        android:protectionLevel="dangerous"
-        android:usageInfoRequired="true" />
+        android:protectionLevel="dangerous" />
 
     <!-- @SystemApi @TestApi Allows an application to read previously received cell broadcast
          messages and to register a content observer to get notifications when
@@ -785,8 +779,7 @@
         android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_readCellBroadcasts"
         android:description="@string/permdesc_readCellBroadcasts"
-        android:protectionLevel="dangerous"
-        android:usageInfoRequired="true" />
+        android:protectionLevel="dangerous" />
 
     <!-- ====================================================================== -->
     <!-- Permissions for accessing external storage                             -->
@@ -867,8 +860,7 @@
         android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_audioRead"
         android:description="@string/permdesc_audioRead"
-        android:protectionLevel="dangerous"
-        android:usageInfoRequired="true" />
+        android:protectionLevel="dangerous" />
 
     <!-- Runtime permission controlling access to the user's shared visual media
          collection, including images and videos. -->
@@ -884,16 +876,14 @@
         android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_imagesRead"
         android:description="@string/permdesc_imagesRead"
-        android:protectionLevel="dangerous"
-        android:usageInfoRequired="true" />
+        android:protectionLevel="dangerous" />
 
     <!-- Allows an application to read the user's shared video collection. -->
     <permission android:name="android.permission.READ_MEDIA_VIDEO"
         android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_videoRead"
         android:description="@string/permdesc_videoRead"
-        android:protectionLevel="dangerous"
-        android:usageInfoRequired="true" />
+        android:protectionLevel="dangerous" />
 
     <!-- Allows an application to access any geographic locations persisted in the
          user's shared collection. -->
@@ -901,8 +891,7 @@
         android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_mediaLocation"
         android:description="@string/permdesc_mediaLocation"
-        android:protectionLevel="dangerous"
-        android:usageInfoRequired="true" />
+        android:protectionLevel="dangerous" />
 
     <!-- @hide @SystemApi @TestApi
          Allows an application to modify OBB files visible to other apps. -->
@@ -934,8 +923,7 @@
         android:label="@string/permlab_accessFineLocation"
         android:description="@string/permdesc_accessFineLocation"
         android:backgroundPermission="android.permission.ACCESS_BACKGROUND_LOCATION"
-        android:protectionLevel="dangerous|instant"
-        android:usageInfoRequired="true" />
+        android:protectionLevel="dangerous|instant" />
 
     <!-- Allows an app to access approximate location.
          Alternatively, you might want {@link #ACCESS_FINE_LOCATION}.
@@ -946,8 +934,7 @@
         android:label="@string/permlab_accessCoarseLocation"
         android:description="@string/permdesc_accessCoarseLocation"
         android:backgroundPermission="android.permission.ACCESS_BACKGROUND_LOCATION"
-        android:protectionLevel="dangerous|instant"
-        android:usageInfoRequired="true" />
+        android:protectionLevel="dangerous|instant" />
 
     <!-- Allows an app to access location in the background.  If you
          are requesting this, you should also request {@link #ACCESS_FINE_LOCATION}.
@@ -959,8 +946,7 @@
         android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_accessBackgroundLocation"
         android:description="@string/permdesc_accessBackgroundLocation"
-        android:protectionLevel="dangerous|instant"
-        android:usageInfoRequired="true" />
+        android:protectionLevel="dangerous|instant" />
 
     <!-- ====================================================================== -->
     <!-- Permissions for accessing the call log                                 -->
@@ -1001,8 +987,7 @@
         android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_readCallLog"
         android:description="@string/permdesc_readCallLog"
-        android:protectionLevel="dangerous"
-        android:usageInfoRequired="true" />
+        android:protectionLevel="dangerous" />
 
     <!-- Allows an application to write (but not read) the user's
          call log data.
@@ -1032,8 +1017,7 @@
         android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_processOutgoingCalls"
         android:description="@string/permdesc_processOutgoingCalls"
-        android:protectionLevel="dangerous"
-        android:usageInfoRequired="true" />
+        android:protectionLevel="dangerous" />
 
     <!-- ====================================================================== -->
     <!-- Permissions for accessing the device telephony                         -->
@@ -1065,8 +1049,7 @@
         android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_readPhoneState"
         android:description="@string/permdesc_readPhoneState"
-        android:protectionLevel="dangerous"
-        android:usageInfoRequired="true" />
+        android:protectionLevel="dangerous" />
 
     <!-- Allows read access to the device's phone number(s). This is a subset of the capabilities
          granted by {@link #READ_PHONE_STATE} but is exposed to instant applications.
@@ -1075,8 +1058,7 @@
         android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_readPhoneNumbers"
         android:description="@string/permdesc_readPhoneNumbers"
-        android:protectionLevel="dangerous|instant"
-        android:usageInfoRequired="true" />
+        android:protectionLevel="dangerous|instant" />
 
     <!-- Allows an application to initiate a phone call without going through
         the Dialer user interface for the user to confirm the call.
@@ -1178,8 +1160,7 @@
         android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_recordAudio"
         android:description="@string/permdesc_recordAudio"
-        android:protectionLevel="dangerous|instant"
-        android:usageInfoRequired="true" />
+        android:protectionLevel="dangerous|instant" />
 
     <!-- ====================================================================== -->
     <!-- Permissions for activity recognition                        -->
@@ -1202,8 +1183,7 @@
         android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_activityRecognition"
         android:description="@string/permdesc_activityRecognition"
-        android:protectionLevel="dangerous|instant"
-        android:usageInfoRequired="true" />
+        android:protectionLevel="dangerous|instant" />
 
     <!-- ====================================================================== -->
     <!-- Permissions for accessing the UCE Service                              -->
@@ -1252,8 +1232,7 @@
         android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_camera"
         android:description="@string/permdesc_camera"
-        android:protectionLevel="dangerous|instant"
-        android:usageInfoRequired="true" />
+        android:protectionLevel="dangerous|instant" />
 
 
     <!-- ====================================================================== -->
@@ -1277,8 +1256,7 @@
         android:permissionGroup="android.permission-group.UNDEFINED"
         android:label="@string/permlab_bodySensors"
         android:description="@string/permdesc_bodySensors"
-        android:protectionLevel="dangerous"
-        android:usageInfoRequired="true" />
+        android:protectionLevel="dangerous" />
 
     <!-- Allows an app to use fingerprint hardware.
          <p>Protection level: normal
@@ -1780,8 +1758,7 @@
         android:permissionGroup="android.permission-group.UNDEFINED"
         android:protectionLevel="dangerous"
         android:description="@string/permdesc_getAccounts"
-        android:label="@string/permlab_getAccounts"
-        android:usageInfoRequired="true" />
+        android:label="@string/permlab_getAccounts" />
     <uses-permission android:name="android.permission.GET_ACCOUNTS"/>
 
     <!-- Allows applications to call into AccountAuthenticators.
@@ -2290,7 +2267,7 @@
     <!-- Allows an application to start activities from background
          @hide -->
     <permission android:name="android.permission.START_ACTIVITIES_FROM_BACKGROUND"
-        android:protectionLevel="signature|privileged|vendorPrivileged|oem" />
+        android:protectionLevel="signature|privileged|vendorPrivileged|oem|verifier" />
 
     <!-- @SystemApi Must be required by activities that handle the intent action
          {@link Intent#ACTION_SEND_SHOW_SUSPENDED_APP_DETAILS}. This is for use by apps that
@@ -4411,8 +4388,8 @@
     <permission android:name="android.permission.MONITOR_DEFAULT_SMS_PACKAGE"
         android:protectionLevel="signature|privileged" />
 
-    <!-- A subclass of {@link android.app.SmsAppService} must be protected with this permission. -->
-    <permission android:name="android.permission.BIND_SMS_APP_SERVICE"
+    <!-- A subclass of {@link android.service.carrier.CarrierMessagingClientService} must be protected with this permission. -->
+    <permission android:name="android.permission.BIND_CARRIER_MESSAGING_CLIENT_SERVICE"
         android:protectionLevel="signature" />
 
     <!-- @hide Permission that allows configuring appops.
diff --git a/core/res/res/drawable/bottomsheet_background.xml b/core/res/res/drawable/bottomsheet_background.xml
new file mode 100644
index 0000000..bc32ba6
--- /dev/null
+++ b/core/res/res/drawable/bottomsheet_background.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 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.
+-->
+
+<shape android:shape="rectangle" xmlns:android="http://schemas.android.com/apk/res/android">
+    <corners
+        android:topLeftRadius="?attr/dialogCornerRadius"
+        android:topRightRadius="?attr/dialogCornerRadius" />
+    <solid android:color="?attr/colorBackgroundFloating" />
+</shape>
diff --git a/core/res/res/drawable/ic_action_open.xml b/core/res/res/drawable/ic_action_open.xml
new file mode 100644
index 0000000..3d3d36e
--- /dev/null
+++ b/core/res/res/drawable/ic_action_open.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2019 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24.0"
+    android:viewportHeight="24.0">
+  <path
+      android:fillColor="#FF737373"
+      android:pathData="M19 19H5V5h7V3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2v-7h-2v7zM14 3v2h3.59l-9.83 9.83 1.41 1.41L19 6.41V10h2V3h-7z"/>
+</vector>
\ No newline at end of file
diff --git a/core/res/res/drawable/ic_drag_handle.xml b/core/res/res/drawable/ic_drag_handle.xml
new file mode 100644
index 0000000..67ab84d
--- /dev/null
+++ b/core/res/res/drawable/ic_drag_handle.xml
@@ -0,0 +1,23 @@
+<!--
+    Copyright (C) 2016 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:pathData="M20.0,9.0L4.0,9.0l0.0,2.0l16.0,0.0L20.0,9.0zM4.0,15.0l16.0,0.0l0.0,-2.0L4.0,13.0l0.0,2.0z"/>
+</vector>
\ No newline at end of file
diff --git a/core/res/res/layout/chooser_grid.xml b/core/res/res/layout/chooser_grid.xml
index f784661..14a5310 100644
--- a/core/res/res/layout/chooser_grid.xml
+++ b/core/res/res/layout/chooser_grid.xml
@@ -25,11 +25,24 @@
     android:maxCollapsedHeightSmall="56dp"
     android:id="@id/contentPanel">
 
+
     <RelativeLayout
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_alwaysShow="true"
-        android:background="?attr/colorBackgroundFloating">
+        android:background="@drawable/bottomsheet_background">
+
+        <ImageView
+            android:id="@+id/drag"
+            android:layout_width="48dp"
+            android:layout_height="wrap_content"
+            android:src="@drawable/ic_drag_handle"
+            android:clickable="true"
+            android:paddingTop="@dimen/chooser_edge_margin_normal"
+            android:tint="?android:attr/textColorSecondary"
+            android:layout_centerHorizontal="true"
+            android:layout_alignParentTop="true" />
+
         <TextView android:id="@+id/profile_button"
                   android:layout_width="wrap_content"
                   android:layout_height="48dp"
@@ -41,7 +54,7 @@
                   android:textAppearance="?attr/textAppearanceButton"
                   android:textColor="?attr/colorAccent"
                   android:gravity="center_vertical"
-                  android:layout_alignParentTop="true"
+                  android:layout_below="@id/drag"
                   android:layout_alignParentRight="true"
                   android:singleLine="true"/>
 
@@ -207,7 +220,6 @@
         android:clipToPadding="false"
         android:scrollbarStyle="outsideOverlay"
         android:background="?attr/colorBackgroundFloating"
-        android:elevation="8dp"
         android:listSelector="@color/transparent"
         android:divider="@null"
         android:scrollIndicators="top"
@@ -219,7 +231,7 @@
               android:layout_alwaysShow="true"
               android:background="?attr/colorBackgroundFloating"
               android:text="@string/noApplications"
-              android:padding="32dp"
+              android:padding="@dimen/chooser_edge_margin_normal"
               android:gravity="center"
               android:visibility="gone"/>
 
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index fa3a549..46e14b4 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -2426,6 +2426,8 @@
         </attr>
 
         <attr name="__removed3" />
+        <attr name="__removed4" />
+        <attr name="__removed5" />
 
         <!-- Describes the content of a view so that a autofill service can fill in the appropriate
              data. Multiple hints can be combined in a comma separated list or an array of strings
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 759fc12..53cae63 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -164,6 +164,15 @@
          provider.-->
     <attr name="grantUriPermissions" format="boolean" />
 
+    <!-- If true, the system will always create URI permission grants
+         in the cases where {@link android.content.Intent#FLAG_GRANT_READ_URI_PERMISSION}
+         or {@link android.content.Intent#FLAG_GRANT_WRITE_URI_PERMISSION} would apply.
+         This is useful for a content provider that dynamically enforces permissions
+         on calls in to the provider, instead of through the manifest: the system
+         needs to know that it should always apply permission grants, even if it
+         looks like the target of the grant would already have access to the URI. -->
+    <attr name="forceUriPermissions" format="boolean" />
+
     <!-- Characterizes the potential risk implied in a permission and
          indicates the procedure the system should follow when determining
          whether to grant the permission to an application requesting it. {@link
@@ -1680,10 +1689,6 @@
         <attr name="request" />
         <attr name="protectionLevel" />
         <attr name="permissionFlags" />
-        <!-- If {@code true} applications that target Q <em>must</em> specify the permission usage
-             attributes in their {@code uses-permission} elements or the permission will not be
-             granted. -->
-        <attr name="usageInfoRequired" format="boolean" />
     </declare-styleable>
 
     <!-- The <code>permission-group</code> tag declares a logical grouping of
@@ -1783,81 +1788,6 @@
         requested.  If it does support the feature, it will be as if the manifest didn't
         request it at all. -->
         <attr name="requiredNotFeature" format="string" />
-
-        <!-- Specify if the app uploads data, or derived data, guarded by this permission.
-
-             If the permission is defined with {@link android.R.attr#usageInfoRequired}
-             {@code true} this <em>must</em> be specified by apps that target Android Q or the
-             permission will not be granted, it will be as if the manifest didn't request it at all.
-        -->
-        <attr name="dataSentOffDevice">
-          <!-- The application may send data, or derived data, guarded by this permission off of the
-               device. -->
-          <enum name="yes" value="1" />
-          <!-- The application may send data, or derived data, guarded by this permission off of the
-               device, however it will only do so when explicitly triggered by a user action. -->
-          <enum name="userTriggered" value="2" />
-          <!-- The application does not send data, or derived data, guarded by this permission off
-               of the device. -->
-          <enum name="no" value="3" />
-        </attr>
-
-        <!-- Specify if the application or its related off-device services provide data,
-             or derived data, guarded by this permission to third parties outside of the developer's
-             organization that do not qualify as data processors.
-
-             If the permission is defined with {@link android.R.attr#usageInfoRequired}
-             {@code true} this <em>must</em> be specified by apps that target Android Q or the
-             permission will not be granted, it will be as if the manifest didn't request it at all.
-             -->
-        <attr name="dataSharedWithThirdParty">
-          <!-- The application or its services may provide data, or derived data, guarded by this
-               permission to third party organizations. -->
-          <enum name="yes" value="1" />
-          <!-- The application or its services may provide data, or derived data, guarded by this
-               permission to third party organizations, however it will only do so when explicitly
-               triggered by a user action. -->
-          <enum name="userTriggered" value="2" />
-          <!-- The application or its services does not provide data, or derived data, guarded by
-               this permission to third party organizations. -->
-          <enum name="no" value="3" />
-        </attr>
-
-        <!-- Specify if the application or its related off-device services use data,
-             or derived data, guarded by this permission for monetization purposes.
-
-             For example, if the data is sold to another party or used for targeting advertisements
-             this must be set to {@code yes}.
-
-             If the permission is defined with {@link android.R.attr#usageInfoRequired}
-             {@code true} this <em>must</em> be specified by apps that target Android Q or the
-             permission will not be granted, it will be as if the manifest didn't request it at all.
-             -->
-        <attr name="dataUsedForMonetization">
-          <!-- The application or its services may use data, or derived data, guarded by this
-               permission for monetization purposes. -->
-          <enum name="yes" value="1" />
-          <!-- The application or its services may use data, or derived data, guarded by this
-               permission for monetization purposes, however it will only do so when explicity
-               triggered by a user action. -->
-          <enum name="userTriggered" value="2" />
-          <!--  The application or its services does not use data, or derived data, guarded by
-                this permission for monetization purposes. -->
-          <enum name="no" value="3" />
-        </attr>
-
-        <!-- Specify how long the application or its related off-device services store
-             data, or derived data, guarded by this permission.
-
-             This can be one of "notRetained", "userSelected", "unlimited", or a number
-             representing the number of weeks the data is retained.
-
-             If the permission is defined with {@link android.R.attr#usageInfoRequired}
-             {@code true} this <em>must</em> be specified by apps that target Android Q or the
-             permission will not be granted, it will be as if the manifest didn't request it at all.
-             -->
-        <attr name="dataRetentionTime" format="string" />
-
     </declare-styleable>
 
     <!-- The <code>uses-configuration</code> tag specifies
@@ -2199,6 +2129,7 @@
         <attr name="readPermission" />
         <attr name="writePermission" />
         <attr name="grantUriPermissions" />
+        <attr name="forceUriPermissions" />
         <attr name="permission" />
         <attr name="multiprocess" />
         <attr name="initOrder" />
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 16c0744..02fae4a 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -199,8 +199,6 @@
     <color name="Red_700">#ffc53929</color>
     <color name="Red_800">#ffb93221</color>
 
-    <color name="chooser_service_row_background_color">#fff5f5f5</color>
-
     <!-- Status bar color for semi transparent mode. -->
     <color name="system_bar_background_semi_transparent">#66000000</color> <!-- 40% black -->
 
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 9e34441..130f629 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -963,7 +963,7 @@
     <bool name="config_nightDisplayAvailable">@bool/config_setColorTransformAccelerated</bool>
 
     <!-- Default mode to control how Night display is automatically activated.
-         One of the following values (see ColorDisplayController.java):
+         One of the following values (see ColorDisplayManager.java):
              0 - AUTO_MODE_DISABLED
              1 - AUTO_MODE_CUSTOM_TIME
              2 - AUTO_MODE_TWILIGHT
@@ -1052,7 +1052,7 @@
     </string-array>
 
 
-    <!-- Indicate available ColorDisplayController.COLOR_MODE_xxx. -->
+    <!-- Indicate available ColorDisplayManager.COLOR_MODE_xxx. -->
     <integer-array name="config_availableColorModes">
         <!-- Example:
         <item>0</item>
@@ -1594,7 +1594,7 @@
     <integer-array name="config_screenBrighteningThresholds">
         <item>100</item>
     </integer-array>
- 
+
     <!-- Array of hysteresis constraint values for darkening, represented as tenths of a
          percent. The length of this array is assumed to be one greater than
          config_screenThresholdLevels. The darkening threshold is calculated as
@@ -1921,8 +1921,6 @@
                cell broadcasting sms, and MMS. -->
     <bool name="config_sms_capable">true</bool>
 
-    <!-- TODO: STOPSHIP(b/110557011): Remove this from framework and overlays as we use
-         config_defaultRoleHolders now. -->
     <!-- Default SMS Application. This will be the default SMS application when
          the phone first boots. The user can then change the default app to one
          of their choosing.
@@ -1930,15 +1928,33 @@
          application is desired.
 
          If this string is empty or the specified package does not exist, then
-         the platform will search for an SMS app and use that (if there is one)-->
+         the platform will search for an SMS app and use that (if there is one)
+
+         Note: This config is deprecated, please use config_defaultSms instead. -->
     <string name="default_sms_application" translatable="false">com.android.messaging</string>
 
-    <!-- Default role holders. This will be an array of roles and package names of their default
-         holders, with each item in the format of "ROLE_NAME: PACKAGE_NAME_1, PACKAGE_NAME_2". -->
-    <string-array name="config_defaultRoleHolders" translatable="false">
-        <item>android.app.role.SMS: com.android.messaging</item>
-        <item>android.app.role.DIALER: com.android.phone</item>
-    </string-array>
+    <!-- Default web browser.  This is the package name of the application that will
+         be the default browser when the device first boots.  Afterwards the user
+         can select whatever browser app they wish to use as the default.
+
+         If this string is empty or the specified package does not exist, then
+         the behavior will be as though no app was named as an explicit default.
+
+         Note: This config is deprecated, please use config_defaultBrowser instead. -->
+    <string name="default_browser" translatable="false"></string>
+
+    <!-- The name of the package that will hold the assistant role by default. -->
+    <string name="config_defaultAssistant" translatable="false" />
+    <!-- The name of the package that will hold the browser role by default. -->
+    <string name="config_defaultBrowser" translatable="false">@string/default_browser</string>
+    <!-- The name of the package that will hold the dialer role by default. -->
+    <string name="config_defaultDialer" translatable="false">com.android.phone</string>
+    <!-- The name of the package that will hold the SMS role by default. -->
+    <string name="config_defaultSms" translatable="false">@string/default_sms_application</string>
+    <!-- The name of the package that will hold the music role by default. -->
+    <string name="config_defaultMusic" translatable="false">com.android.music</string>
+    <!-- The name of the package that will hold the gallery role by default. -->
+    <string name="config_defaultGallery" translatable="false">com.android.gallery3d</string>
 
     <!-- Enable/disable default bluetooth profiles:
         HSP_AG, ObexObjectPush, Audio, NAP -->
@@ -2632,6 +2648,7 @@
         extractor must come first -->
         <item>com.android.server.notification.NotificationChannelExtractor</item>
         <item>com.android.server.notification.NotificationAdjustmentExtractor</item>
+        <item>com.android.server.notification.BubbleExtractor</item>
         <!-- depends on AdjustmentExtractor-->
         <item>com.android.server.notification.ValidateNotificationPeople</item>
         <item>com.android.server.notification.PriorityExtractor</item>
@@ -3424,8 +3441,10 @@
     <!-- Flag indicates that whether non-system apps can be installed on internal storage. -->
     <bool name="config_allow3rdPartyAppOnInternal">true</bool>
 
-    <!-- Package name of the default cell broadcast receiver -->
-    <string name="config_defaultCellBroadcastReceiverPkg" translatable="false">com.android.cellbroadcastreceiver</string>
+    <!-- Package names of the default cell broadcast receivers -->
+    <string-array name="config_defaultCellBroadcastReceiverPkgs" translatable="false">
+        <item>com.android.cellbroadcastreceiver</item>
+    </string-array>
 
     <!-- Specifies the path that is used by AdaptiveIconDrawable class to crop launcher icons. -->
     <string name="config_icon_mask" translatable="false">"M50,0L92,0C96.42,0 100,4.58 100 8L100,92C100, 96.42 96.42 100 92 100L8 100C4.58, 100 0 96.42 0 92L0 8 C 0 4.42 4.42 0 8 0L50 0Z"</string>
diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml
index bbe3ff9..ce7995a 100644
--- a/core/res/res/values/ids.xml
+++ b/core/res/res/values/ids.xml
@@ -193,4 +193,7 @@
 
   <!-- A tag used to save the notification action object -->
   <item type="id" name="notification_action_index_tag" />
+
+  <!-- A tag used to save the index where the custom view is stored -->
+  <item type="id" name="notification_custom_view_index_tag" />
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index e7d8102..d2c3b40 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2925,11 +2925,11 @@
         <public name="importantForContentCapture" />
         <public name="supportsMultipleDisplays" />
         <public name="useAppZygote" />
-        <public name="usageInfoRequired" />
-        <public name="dataSentOffDevice" />
-        <public name="dataSharedWithThirdParty" />
-        <public name="dataUsedForMonetization" />
-        <public name="dataRetentionTime" />
+        <public name="__removed1" />
+        <public name="__removed2" />
+        <public name="__removed3" />
+        <public name="__removed4" />
+        <public name="__removed5" />
         <public name="selectionDividerHeight" />
         <public name="foregroundServiceType" />
         <public name="hasFragileUserData" />
@@ -2938,6 +2938,7 @@
         <public name="inheritShowWhenLocked" />
         <public name="zygotePreloadName" />
         <public name="useEmbeddedDex" />
+        <public name="forceUriPermissions" />
     </public-group>
 
     <public-group type="drawable" first-id="0x010800b4">
@@ -2970,6 +2971,18 @@
         <public name="config_feedbackIntentExtraKey" />
         <!-- @hide @SystemApi -->
         <public name="config_feedbackIntentNameKey" />
+      <!-- @hide @SystemApi @TestApi -->
+      <public name="config_defaultAssistant" />
+      <!-- @hide @SystemApi -->
+      <public name="config_defaultBrowser" />
+      <!-- @hide @SystemApi @TestApi -->
+      <public name="config_defaultDialer" />
+      <!-- @hide @SystemApi -->
+      <public name="config_defaultSms" />
+      <!-- @hide @SystemApi -->
+      <public name="config_defaultMusic" />
+      <!-- @hide @SystemApi -->
+      <public name="config_defaultGallery" />
     </public-group>
 
     <public-group type="bool" first-id="0x01110000">
@@ -2989,11 +3002,6 @@
         <public name="system_notification_accent_color" />
     </public-group>
 
-    <public-group type="array" first-id="0x01070006">
-      <!-- @hide @TestApi @SystemApi -->
-      <public name="config_defaultRoleHolders" />
-    </public-group>
-
   <!-- ===============================================================
        DO NOT ADD UN-GROUPED ITEMS HERE
 
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index fadb28f..6d5bd4b 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1471,6 +1471,8 @@
     <string name="biometric_not_recognized">Not recognized</string>
     <!-- Message shown when biometric authentication has been canceled [CHAR LIMIT=50] -->
     <string name="biometric_error_canceled">Authentication canceled</string>
+    <!-- Message returned to applications if BiometricPrompt setAllowDeviceCredentials is enabled but no pin, pattern, or password is set. [CHAR LIMIT=NONE] -->
+    <string name="biometric_error_device_not_secured">No pin, pattern, or password set</string>
 
     <!-- Message shown during fingerprint acquisision when the fingerprint cannot be recognized -->
     <string name="fingerprint_acquired_partial">Partial fingerprint detected. Please try again.</string>
@@ -1512,7 +1514,7 @@
     <!-- Generic error message shown when the user has no enrolled fingerprints -->
     <string name="fingerprint_error_no_fingerprints">No fingerprints enrolled.</string>
     <!-- Generic error message shown when the app requests fingerprint authentication on a device without a sensor -->
-    <string name="fingerprint_error_hw_not_present">This device does not have a fingerprint sensor</string>
+    <string name="fingerprint_error_hw_not_present">This device does not have a fingerprint sensor.</string>
 
     <!-- Template to be used to name enrolled fingerprints by default. -->
     <string name="fingerprint_name_template">Finger <xliff:g id="fingerId" example="1">%d</xliff:g></string>
@@ -1555,8 +1557,22 @@
     <string name="face_acquired_poor_gaze">Please look at the sensor.</string>
     <!-- Message shown during face acquisition when the user is not detected [CHAR LIMIT=50] -->
     <string name="face_acquired_not_detected">No face detected.</string>
-    <!-- Message shown during face acquisition when the face is not kept steady infront of device [CHAR LIMIT=50] -->
-    <string name="face_acquired_not_steady">Keep face steady infront of device.</string>
+    <!-- Message shown during face acquisition when the device is not steady [CHAR LIMIT=50] -->
+    <string name="face_acquired_too_much_motion">Too much motion.</string>
+    <!-- Message shown during face acquisition when the sensor needs to be recalibrated [CHAR LIMIT=50] -->
+    <string name="face_acquired_recalibrate">Please re-enroll your face.</string>
+    <!-- Message shown during face enrollment when a different person's face is detected [CHAR LIMIT=50] -->
+    <string name="face_acquired_too_different">Different face detected.</string>
+    <!-- Message shown during face enrollment when the face is too similar to a previous acquisition [CHAR LIMIT=50] -->
+    <string name="face_acquired_too_similar">Too similar, please change your pose.</string>
+    <!-- Message shown during acqusition when the user's face is turned too far left or right [CHAR LIMIT=50] -->
+    <string name="face_acquired_pan_too_extreme">Please look more directly at the camera.</string>
+    <!-- Message shown during acqusition when the user's face is tilted too high or too low [CHAR LIMIT=50] -->
+    <string name="face_acquired_tilt_too_extreme">Please look more directly at the camera.</string>
+    <!-- Message shown during acquisiton when the user's face is tilted too far left or right [CHAR LIMIT=50] -->
+    <string name="face_acquired_roll_too_extreme">Please straighten your head vertically.</string>
+    <!-- Message shown during acquisition when the user's face is obscured [CHAR LIMIT=50] -->
+    <string name="face_acquired_obscured">Please uncover your face.</string>
     <!-- Array containing custom messages shown during face acquisition from vendor.  Vendor is expected to add and translate these strings -->
     <string-array name="face_acquired_vendor">
     </string-array>
@@ -1580,7 +1596,7 @@
     <!-- Generic error message shown when the user has no enrolled face. [CHAR LIMIT=50] -->
     <string name="face_error_not_enrolled">No face enrolled.</string>
     <!-- Generic error message shown when the app requests face authentication on a device without a sensor. [CHAR LIMIT=60] -->
-    <string name="face_error_hw_not_present">This device does not have a face authentication sensor</string>
+    <string name="face_error_hw_not_present">This device does not have a face authentication sensor.</string>
 
     <!-- Template to be used to name enrolled faces by default. [CHAR LIMIT=10] -->
     <string name="face_name_template">Face <xliff:g id="faceId" example="1">%d</xliff:g></string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 6d4b04c..8e251fd 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1034,6 +1034,7 @@
   <java-symbol type="string" name="sipAddressTypeOther" />
   <java-symbol type="string" name="sipAddressTypeWork" />
   <java-symbol type="string" name="default_sms_application" />
+  <java-symbol type="string" name="default_browser" />
   <java-symbol type="string" name="sms_control_message" />
   <java-symbol type="string" name="sms_control_title" />
   <java-symbol type="string" name="sms_control_no" />
@@ -2472,6 +2473,7 @@
   <java-symbol type="string" name="biometric_error_user_canceled" />
   <java-symbol type="string" name="biometric_not_recognized" />
   <java-symbol type="string" name="biometric_error_canceled" />
+  <java-symbol type="string" name="biometric_error_device_not_secured" />
 
   <!-- Fingerprint messages -->
   <java-symbol type="string" name="fingerprint_error_unable_to_process" />
@@ -2521,6 +2523,14 @@
   <java-symbol type="string" name="face_acquired_too_left" />
   <java-symbol type="string" name="face_acquired_poor_gaze" />
   <java-symbol type="string" name="face_acquired_not_detected" />
+  <java-symbol type="string" name="face_acquired_too_much_motion" />
+  <java-symbol type="string" name="face_acquired_recalibrate" />
+  <java-symbol type="string" name="face_acquired_too_different" />
+  <java-symbol type="string" name="face_acquired_too_similar" />
+  <java-symbol type="string" name="face_acquired_pan_too_extreme" />
+  <java-symbol type="string" name="face_acquired_tilt_too_extreme" />
+  <java-symbol type="string" name="face_acquired_roll_too_extreme" />
+  <java-symbol type="string" name="face_acquired_obscured" />
   <java-symbol type="array" name="face_acquired_vendor" />
   <java-symbol type="string" name="face_name_template" />
   <java-symbol type="string" name="face_authenticated_no_confirmation_required" />
@@ -2744,7 +2754,6 @@
   <java-symbol type="drawable" name="scroll_indicator_material" />
 
   <java-symbol type="layout" name="chooser_row" />
-  <java-symbol type="color" name="chooser_service_row_background_color" />
   <java-symbol type="id" name="target_badge" />
   <java-symbol type="bool" name="config_supportDoubleTapWake" />
   <java-symbol type="drawable" name="ic_perm_device_info" />
@@ -3152,7 +3161,7 @@
   <java-symbol type="drawable" name="lockscreen_selected" />
 
   <java-symbol type="string" name="notification_header_divider_symbol_with_spaces" />
-  <java-symbol type="string" name="config_defaultCellBroadcastReceiverPkg" />
+  <java-symbol type="array" name="config_defaultCellBroadcastReceiverPkgs" />
 
   <java-symbol type="color" name="notification_primary_text_color_light" />
   <java-symbol type="color" name="notification_primary_text_color_dark" />
@@ -3586,6 +3595,7 @@
   <java-symbol type="bool" name="config_useSmsAppService" />
 
   <java-symbol type="id" name="transition_overlay_view_tag" />
+  <java-symbol type="id" name="notification_custom_view_index_tag" />
 
   <java-symbol type="dimen" name="rounded_corner_radius" />
   <java-symbol type="dimen" name="rounded_corner_radius_top" />
@@ -3596,7 +3606,7 @@
 
   <!-- For Secondary Launcher -->
   <java-symbol type="string" name="config_secondaryHomeComponent" />
-  
+
   <java-symbol type="string" name="dynamic_mode_notification_channel_name" />
   <java-symbol type="string" name="dynamic_mode_notification_title" />
   <java-symbol type="string" name="dynamic_mode_notification_summary" />
@@ -3633,4 +3643,6 @@
   <java-symbol type="array" name="config_displayWhiteBalanceDecreaseThresholds" />
   <java-symbol type="dimen" name="config_displayWhiteBalanceLowLightAmbientBrightnessThreshold" />
   <java-symbol type="dimen" name="config_displayWhiteBalanceLowLightAmbientColorTemperature" />
+
+  <java-symbol type="drawable" name="ic_action_open" />
 </resources>
diff --git a/core/tests/coretests/src/android/content/pm/PackageParserTest.java b/core/tests/coretests/src/android/content/pm/PackageParserTest.java
index 300394d..aa0e0cd 100644
--- a/core/tests/coretests/src/android/content/pm/PackageParserTest.java
+++ b/core/tests/coretests/src/android/content/pm/PackageParserTest.java
@@ -162,14 +162,13 @@
     }
 
     private void verifyComputeTargetSdkVersion(int targetSdkVersion, String targetSdkCodename,
-            boolean isPlatformReleased, int expectedTargetSdk, boolean forceCurrentDev) {
+            boolean isPlatformReleased, int expectedTargetSdk) {
         final String[] outError = new String[1];
         final int result = PackageParser.computeTargetSdkVersion(
                 targetSdkVersion,
                 targetSdkCodename,
                 isPlatformReleased ? CODENAMES_RELEASED : CODENAMES_PRE_RELEASE,
-                outError,
-                forceCurrentDev);
+                outError);
 
         assertEquals(result, expectedTargetSdk);
 
@@ -185,28 +184,23 @@
         // Do allow older release targetSdkVersion on pre-release platform.
         // APP: Released API 10
         // DEV: Pre-release API 20
-        verifyComputeTargetSdkVersion(OLDER_VERSION, RELEASED, false, OLDER_VERSION,
-                false /* forceCurrentDev */);
+        verifyComputeTargetSdkVersion(OLDER_VERSION, RELEASED, false, OLDER_VERSION);
 
         // Do allow same release targetSdkVersion on pre-release platform.
         // APP: Released API 20
         // DEV: Pre-release API 20
-        verifyComputeTargetSdkVersion(PLATFORM_VERSION, RELEASED, false, PLATFORM_VERSION,
-                false /* forceCurrentDev */);
+        verifyComputeTargetSdkVersion(PLATFORM_VERSION, RELEASED, false, PLATFORM_VERSION);
 
         // Do allow newer release targetSdkVersion on pre-release platform.
         // APP: Released API 30
         // DEV: Pre-release API 20
-        verifyComputeTargetSdkVersion(NEWER_VERSION, RELEASED, false, NEWER_VERSION,
-                false /* forceCurrentDev */);
+        verifyComputeTargetSdkVersion(NEWER_VERSION, RELEASED, false, NEWER_VERSION);
 
         // Don't allow older pre-release targetSdkVersion on pre-release platform.
         // APP: Pre-release API 10
         // DEV: Pre-release API 20
-        verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE, false, -1,
-                false /* forceCurrentDev */);
-        verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE_WITH_FINGERPRINT, false, -1,
-                false /* forceCurrentDev */);
+        verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE, false, -1);
+        verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE_WITH_FINGERPRINT, false, -1);
 
 
         // Do allow same pre-release targetSdkVersion on pre-release platform,
@@ -214,27 +208,16 @@
         // APP: Pre-release API 20
         // DEV: Pre-release API 20
         verifyComputeTargetSdkVersion(PLATFORM_VERSION, PRE_RELEASE, false,
-                Build.VERSION_CODES.CUR_DEVELOPMENT, false /* forceCurrentDev */);
+                Build.VERSION_CODES.CUR_DEVELOPMENT);
         verifyComputeTargetSdkVersion(PLATFORM_VERSION, PRE_RELEASE_WITH_FINGERPRINT, false,
-                Build.VERSION_CODES.CUR_DEVELOPMENT, false /* forceCurrentDev */);
+                Build.VERSION_CODES.CUR_DEVELOPMENT);
 
 
         // Don't allow newer pre-release targetSdkVersion on pre-release platform.
         // APP: Pre-release API 30
         // DEV: Pre-release API 20
-        verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, false, -1,
-                false /* forceCurrentDev */);
-        verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE_WITH_FINGERPRINT, false, -1,
-                false /* forceCurrentDev */);
-
-
-        // Force newer pre-release targetSdkVersion to current pre-release platform.
-        // APP: Pre-release API 30
-        // DEV: Pre-release API 20
-        verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, false,
-                Build.VERSION_CODES.CUR_DEVELOPMENT, true /* forceCurrentDev */);
-        verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE_WITH_FINGERPRINT, false,
-                Build.VERSION_CODES.CUR_DEVELOPMENT, true /* forceCurrentDev */);
+        verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, false, -1);
+        verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE_WITH_FINGERPRINT, false, -1);
     }
 
     @Test
@@ -242,45 +225,36 @@
         // Do allow older release targetSdkVersion on released platform.
         // APP: Released API 10
         // DEV: Released API 20
-        verifyComputeTargetSdkVersion(OLDER_VERSION, RELEASED, true, OLDER_VERSION,
-                false /* forceCurrentDev */);
+        verifyComputeTargetSdkVersion(OLDER_VERSION, RELEASED, true, OLDER_VERSION);
 
         // Do allow same release targetSdkVersion on released platform.
         // APP: Released API 20
         // DEV: Released API 20
-        verifyComputeTargetSdkVersion(PLATFORM_VERSION, RELEASED, true, PLATFORM_VERSION,
-                false /* forceCurrentDev */);
+        verifyComputeTargetSdkVersion(PLATFORM_VERSION, RELEASED, true, PLATFORM_VERSION);
 
         // Do allow newer release targetSdkVersion on released platform.
         // APP: Released API 30
         // DEV: Released API 20
-        verifyComputeTargetSdkVersion(NEWER_VERSION, RELEASED, true, NEWER_VERSION,
-                false /* forceCurrentDev */);
+        verifyComputeTargetSdkVersion(NEWER_VERSION, RELEASED, true, NEWER_VERSION);
 
         // Don't allow older pre-release targetSdkVersion on released platform.
         // APP: Pre-release API 10
         // DEV: Released API 20
-        verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE, true, -1,
-                false /* forceCurrentDev */);
-        verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE_WITH_FINGERPRINT, true, -1,
-                false /* forceCurrentDev */);
+        verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE, true, -1);
+        verifyComputeTargetSdkVersion(OLDER_VERSION, OLDER_PRE_RELEASE_WITH_FINGERPRINT, true, -1);
 
         // Don't allow same pre-release targetSdkVersion on released platform.
         // APP: Pre-release API 20
         // DEV: Released API 20
-        verifyComputeTargetSdkVersion(PLATFORM_VERSION, PRE_RELEASE, true, -1,
-                false /* forceCurrentDev */);
-        verifyComputeTargetSdkVersion(PLATFORM_VERSION, PRE_RELEASE_WITH_FINGERPRINT, true, -1,
-                false /* forceCurrentDev */);
+        verifyComputeTargetSdkVersion(PLATFORM_VERSION, PRE_RELEASE, true, -1);
+        verifyComputeTargetSdkVersion(PLATFORM_VERSION, PRE_RELEASE_WITH_FINGERPRINT, true, -1);
 
 
         // Don't allow newer pre-release targetSdkVersion on released platform.
         // APP: Pre-release API 30
         // DEV: Released API 20
-        verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, true, -1,
-                false /* forceCurrentDev */);
-        verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE_WITH_FINGERPRINT, true, -1,
-                false /* forceCurrentDev */);
+        verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE, true, -1);
+        verifyComputeTargetSdkVersion(NEWER_VERSION, NEWER_PRE_RELEASE_WITH_FINGERPRINT, true, -1);
     }
 
     /**
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 2cb925a..ec57f79 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -210,6 +210,7 @@
                     Settings.Global.DATA_STALL_VALID_DNS_TIME_THRESHOLD,
                     Settings.Global.DEBUG_APP,
                     Settings.Global.DEBUG_VIEW_ATTRIBUTES,
+                    Settings.Global.DEBUG_VIEW_ATTRIBUTES_APPLICATION_PACKAGE,
                     Settings.Global.DEFAULT_DNS_SERVER,
                     Settings.Global.DEFAULT_INSTALL_LOCATION,
                     Settings.Global.DEFAULT_RESTRICT_BACKGROUND_DATA,
diff --git a/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java b/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
index da81d17..80b1f9c 100644
--- a/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
+++ b/core/tests/coretests/src/android/view/ImeInsetsSourceConsumerTest.java
@@ -19,6 +19,7 @@
 import static android.view.ImeInsetsSourceConsumer.areEditorsSimilar;
 import static android.view.InsetsState.TYPE_IME;
 
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
 
@@ -73,7 +74,7 @@
                     false,
                     new DisplayCutout(
                             Insets.of(10, 10, 10, 10), rect, rect, rect, rect),
-                    rect, rect);
+                    rect, rect, SOFT_INPUT_ADJUST_RESIZE);
             mImeConsumer = new ImeInsetsSourceConsumer(
                     new InsetsState(), Transaction::new, mController);
         });
diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java
index 6dad6a2..731d564 100644
--- a/core/tests/coretests/src/android/view/InsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java
@@ -20,10 +20,16 @@
 import static android.view.InsetsState.TYPE_NAVIGATION_BAR;
 import static android.view.InsetsState.TYPE_TOP_BAR;
 
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertNull;
 import static junit.framework.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
 
 import android.content.Context;
 import android.graphics.Insets;
@@ -73,7 +79,7 @@
                     false,
                     new DisplayCutout(
                             Insets.of(10, 10, 10, 10), rect, rect, rect, rect),
-                    rect, rect);
+                    rect, rect, SOFT_INPUT_ADJUST_RESIZE);
         });
         InstrumentationRegistry.getInstrumentation().waitForIdleSync();
     }
@@ -95,6 +101,17 @@
     }
 
     @Test
+    public void testFrameDoesntMatchDisplay() {
+        mController.onFrameChanged(new Rect(0, 0, 100, 100));
+        mController.getState().setDisplayFrame(new Rect(0, 0, 200, 200));
+        WindowInsetsAnimationControlListener controlListener =
+                mock(WindowInsetsAnimationControlListener.class);
+        mController.controlWindowInsetsAnimation(0, controlListener);
+        verify(controlListener).onCancelled();
+        verify(controlListener, never()).onReady(any(), anyInt());
+    }
+
+    @Test
     public void testAnimationEndState() {
         InsetsSourceControl[] controls = prepareControls();
         InsetsSourceControl navBar = controls[0];
diff --git a/core/tests/coretests/src/android/view/InsetsStateTest.java b/core/tests/coretests/src/android/view/InsetsStateTest.java
index 03af67d..bd036b0 100644
--- a/core/tests/coretests/src/android/view/InsetsStateTest.java
+++ b/core/tests/coretests/src/android/view/InsetsStateTest.java
@@ -25,6 +25,8 @@
 import static android.view.InsetsState.TYPE_SIDE_BAR_3;
 import static android.view.InsetsState.TYPE_TOP_BAR;
 
+import static android.view.WindowInsets.Type.ime;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
@@ -37,6 +39,7 @@
 import android.platform.test.annotations.Presubmit;
 import android.util.SparseIntArray;
 import android.view.WindowInsets.Type;
+import android.view.test.InsetsModeSession;
 
 import androidx.test.filters.FlakyTest;
 import androidx.test.runner.AndroidJUnit4;
@@ -53,49 +56,70 @@
     private InsetsState mState2 = new InsetsState();
 
     @Test
-    public void testCalculateInsets() {
+    public void testCalculateInsets() throws Exception {
+        try (final InsetsModeSession session =
+                     new InsetsModeSession(ViewRootImpl.NEW_INSETS_MODE_FULL)) {
+            mState.getSource(TYPE_TOP_BAR).setFrame(new Rect(0, 0, 100, 100));
+            mState.getSource(TYPE_TOP_BAR).setVisible(true);
+            mState.getSource(TYPE_IME).setFrame(new Rect(0, 200, 100, 300));
+            mState.getSource(TYPE_IME).setVisible(true);
+            SparseIntArray typeSideMap = new SparseIntArray();
+            WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), false, false,
+                    DisplayCutout.NO_CUTOUT, null, null, SOFT_INPUT_ADJUST_RESIZE, typeSideMap);
+            assertEquals(Insets.of(0, 100, 0, 100), insets.getSystemWindowInsets());
+            assertEquals(Insets.of(0, 100, 0, 100), insets.getInsets(Type.all()));
+            assertEquals(INSET_SIDE_TOP, typeSideMap.get(TYPE_TOP_BAR));
+            assertEquals(INSET_SIDE_BOTTOM, typeSideMap.get(TYPE_IME));
+            assertEquals(Insets.of(0, 100, 0, 0), insets.getInsets(Type.topBar()));
+            assertEquals(Insets.of(0, 0, 0, 100), insets.getInsets(Type.ime()));
+        }
+    }
+
+    @Test
+    public void testCalculateInsets_imeAndNav() throws Exception{
+        try (final InsetsModeSession session =
+                     new InsetsModeSession(ViewRootImpl.NEW_INSETS_MODE_FULL)) {
+            mState.getSource(TYPE_NAVIGATION_BAR).setFrame(new Rect(0, 200, 100, 300));
+            mState.getSource(TYPE_NAVIGATION_BAR).setVisible(true);
+            mState.getSource(TYPE_IME).setFrame(new Rect(0, 100, 100, 300));
+            mState.getSource(TYPE_IME).setVisible(true);
+            WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), false, false,
+                    DisplayCutout.NO_CUTOUT, null, null, SOFT_INPUT_ADJUST_RESIZE, null);
+            assertEquals(100, insets.getStableInsetBottom());
+            assertEquals(Insets.of(0, 0, 0, 100), insets.getMaxInsets(Type.systemBars()));
+            assertEquals(Insets.of(0, 0, 0, 200), insets.getSystemWindowInsets());
+            assertEquals(Insets.of(0, 0, 0, 200), insets.getInsets(Type.all()));
+            assertEquals(Insets.of(0, 0, 0, 100), insets.getInsets(Type.sideBars()));
+            assertEquals(Insets.of(0, 0, 0, 200), insets.getInsets(Type.ime()));
+        }
+    }
+
+    @Test
+    public void testCalculateInsets_navRightStatusTop() throws Exception {
+        try (final InsetsModeSession session =
+                     new InsetsModeSession(ViewRootImpl.NEW_INSETS_MODE_FULL)) {
+            mState.getSource(TYPE_TOP_BAR).setFrame(new Rect(0, 0, 100, 100));
+            mState.getSource(TYPE_TOP_BAR).setVisible(true);
+            mState.getSource(TYPE_NAVIGATION_BAR).setFrame(new Rect(80, 0, 100, 300));
+            mState.getSource(TYPE_NAVIGATION_BAR).setVisible(true);
+            WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), false, false,
+                    DisplayCutout.NO_CUTOUT, null, null, 0, null);
+            assertEquals(Insets.of(0, 100, 20, 0), insets.getSystemWindowInsets());
+            assertEquals(Insets.of(0, 100, 0, 0), insets.getInsets(Type.topBar()));
+            assertEquals(Insets.of(0, 0, 20, 0), insets.getInsets(Type.sideBars()));
+        }
+    }
+
+    @Test
+    public void testCalculateInsets_imeIgnoredWithoutAdjustResize() {
         mState.getSource(TYPE_TOP_BAR).setFrame(new Rect(0, 0, 100, 100));
         mState.getSource(TYPE_TOP_BAR).setVisible(true);
         mState.getSource(TYPE_IME).setFrame(new Rect(0, 200, 100, 300));
         mState.getSource(TYPE_IME).setVisible(true);
-        SparseIntArray typeSideMap = new SparseIntArray();
         WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), false, false,
-                DisplayCutout.NO_CUTOUT, null, null, typeSideMap);
-        assertEquals(Insets.of(0, 100, 0, 100), insets.getSystemWindowInsets());
-        assertEquals(Insets.of(0, 100, 0, 100), insets.getInsets(Type.all()));
-        assertEquals(INSET_SIDE_TOP, typeSideMap.get(TYPE_TOP_BAR));
-        assertEquals(INSET_SIDE_BOTTOM, typeSideMap.get(TYPE_IME));
-        assertEquals(Insets.of(0, 100, 0, 0), insets.getInsets(Type.topBar()));
-        assertEquals(Insets.of(0, 0, 0, 100), insets.getInsets(Type.ime()));
-    }
-
-    @Test
-    public void testCalculateInsets_imeAndNav() {
-        mState.getSource(TYPE_NAVIGATION_BAR).setFrame(new Rect(0, 200, 100, 300));
-        mState.getSource(TYPE_NAVIGATION_BAR).setVisible(true);
-        mState.getSource(TYPE_IME).setFrame(new Rect(0, 100, 100, 300));
-        mState.getSource(TYPE_IME).setVisible(true);
-        WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), false, false,
-                DisplayCutout.NO_CUTOUT, null, null, null);
-        assertEquals(100, insets.getStableInsetBottom());
-        assertEquals(Insets.of(0, 0, 0, 100), insets.getMaxInsets(Type.all()));
-        assertEquals(Insets.of(0, 0, 0, 200), insets.getSystemWindowInsets());
-        assertEquals(Insets.of(0, 0, 0, 200), insets.getInsets(Type.all()));
-        assertEquals(Insets.of(0, 0, 0, 100), insets.getInsets(Type.sideBars()));
-        assertEquals(Insets.of(0, 0, 0, 200), insets.getInsets(Type.ime()));
-    }
-
-    @Test
-    public void testCalculateInsets_navRightStatusTop() {
-        mState.getSource(TYPE_TOP_BAR).setFrame(new Rect(0, 0, 100, 100));
-        mState.getSource(TYPE_TOP_BAR).setVisible(true);
-        mState.getSource(TYPE_NAVIGATION_BAR).setFrame(new Rect(80, 0, 100, 300));
-        mState.getSource(TYPE_NAVIGATION_BAR).setVisible(true);
-        WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), false, false,
-                DisplayCutout.NO_CUTOUT, null, null, null);
-        assertEquals(Insets.of(0, 100, 20, 0), insets.getSystemWindowInsets());
-        assertEquals(Insets.of(0, 100, 0, 0), insets.getInsets(Type.topBar()));
-        assertEquals(Insets.of(0, 0, 20, 0), insets.getInsets(Type.sideBars()));
+                DisplayCutout.NO_CUTOUT, null, null, 0, null);
+        assertEquals(0, insets.getSystemWindowInsetBottom());
+        assertTrue(insets.isVisible(ime()));
     }
 
     @Test
@@ -106,7 +130,7 @@
         mState.getSource(TYPE_IME).setVisible(true);
         mState.removeSource(TYPE_IME);
         WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), false, false,
-                DisplayCutout.NO_CUTOUT, null, null, null);
+                DisplayCutout.NO_CUTOUT, null, null, SOFT_INPUT_ADJUST_RESIZE, null);
         assertEquals(0, insets.getSystemWindowInsetBottom());
     }
 
@@ -114,14 +138,14 @@
     public void testEquals_differentRect() {
         mState.getSource(TYPE_TOP_BAR).setFrame(new Rect(0, 0, 100, 100));
         mState2.getSource(TYPE_TOP_BAR).setFrame(new Rect(0, 0, 10, 10));
-        assertNotEquals(mState, mState2);
+        assertNotEqualsAndHashCode();
     }
 
     @Test
     public void testEquals_differentSource() {
         mState.getSource(TYPE_TOP_BAR).setFrame(new Rect(0, 0, 100, 100));
         mState2.getSource(TYPE_IME).setFrame(new Rect(0, 0, 100, 100));
-        assertNotEquals(mState, mState2);
+        assertNotEqualsAndHashCode();
     }
 
     @Test
@@ -130,7 +154,7 @@
         mState.getSource(TYPE_IME).setFrame(new Rect(0, 0, 100, 100));
         mState2.getSource(TYPE_IME).setFrame(new Rect(0, 0, 100, 100));
         mState2.getSource(TYPE_TOP_BAR).setFrame(new Rect(0, 0, 100, 100));
-        assertEquals(mState, mState2);
+        assertEqualsAndHashCode();
     }
 
     @Test
@@ -138,7 +162,21 @@
         mState.getSource(TYPE_IME).setFrame(new Rect(0, 0, 100, 100));
         mState.getSource(TYPE_IME).setVisible(true);
         mState2.getSource(TYPE_IME).setFrame(new Rect(0, 0, 100, 100));
-        assertNotEquals(mState, mState2);
+        assertNotEqualsAndHashCode();
+    }
+
+    @Test
+    public void testEquals_differentFrame() {
+        mState.setDisplayFrame(new Rect(0, 1, 2, 3));
+        mState.setDisplayFrame(new Rect(4, 5, 6, 7));
+        assertNotEqualsAndHashCode();
+    }
+
+    @Test
+    public void testEquals_sameFrame() {
+        mState.setDisplayFrame(new Rect(0, 1, 2, 3));
+        mState2.setDisplayFrame(new Rect(0, 1, 2, 3));
+        assertEqualsAndHashCode();
     }
 
     @Test
@@ -148,6 +186,7 @@
         mState.getSource(TYPE_TOP_BAR).setFrame(new Rect(0, 0, 100, 100));
         Parcel p = Parcel.obtain();
         mState.writeToParcel(p, 0 /* flags */);
+        p.setDataPosition(0);
         mState2.readFromParcel(p);
         p.recycle();
         assertEquals(mState, mState2);
@@ -161,4 +200,14 @@
         assertTrue(InsetsState.getDefaultVisibility(TYPE_SIDE_BAR_3));
         assertFalse(InsetsState.getDefaultVisibility(TYPE_IME));
     }
+
+    private void assertEqualsAndHashCode() {
+        assertEquals(mState, mState2);
+        assertEquals(mState.hashCode(), mState2.hashCode());
+    }
+
+    private void assertNotEqualsAndHashCode() {
+        assertNotEquals(mState, mState2);
+        assertNotEquals(mState.hashCode(), mState2.hashCode());
+    }
 }
diff --git a/core/tests/coretests/src/android/view/accessibility/FindViewByIdTest.java b/core/tests/coretests/src/android/view/accessibility/FindViewByIdTest.java
new file mode 100644
index 0000000..da6ecb4
--- /dev/null
+++ b/core/tests/coretests/src/android/view/accessibility/FindViewByIdTest.java
@@ -0,0 +1,100 @@
+/*
+ * 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.view.accessibility;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import android.app.Activity;
+import android.content.Context;
+import android.view.View;
+import android.widget.LinearLayout;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.annotation.UiThreadTest;
+import androidx.test.filters.MediumTest;
+import androidx.test.rule.ActivityTestRule;
+
+import org.junit.Rule;
+import org.junit.Test;
+
+@MediumTest
+public class FindViewByIdTest {
+
+    @Rule
+    public ActivityTestRule<Activity> mActivityRule = new ActivityTestRule<>(Activity.class);
+
+    private Context getContext() {
+        return InstrumentationRegistry.getTargetContext();
+    }
+
+    private Activity getActivity() {
+        return mActivityRule.getActivity();
+    }
+
+    @UiThreadTest
+    @Test
+    public void testFindViewById() {
+        LinearLayout contentView = new LinearLayout(getContext());
+        getActivity().setContentView(contentView);
+        View child1 = new View(getContext());
+        View child2 = new View(getContext());
+        child1.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
+        child2.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
+
+        contentView.addView(child1);
+        contentView.addView(child2);
+        View result = AccessibilityNodeIdManager.getInstance().findView(
+                child2.getAccessibilityViewId());
+        assertEquals(result, child2);
+    }
+
+    @UiThreadTest
+    @Test
+    public void testFindViewByIdReturnNullIfRemovedFromHierarchy() {
+        LinearLayout contentView = new LinearLayout(getContext());
+        getActivity().setContentView(contentView);
+        View child1 = new View(getContext());
+        View child2 = new View(getContext());
+        contentView.addView(child1);
+        contentView.addView(child2);
+        child1.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
+        child2.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
+
+        contentView.removeView(child1);
+        View result = AccessibilityNodeIdManager.getInstance().findView(
+                child1.getAccessibilityViewId());
+        assertNull(result);
+    }
+
+    @UiThreadTest
+    @Test
+    public void testFindViewByIdReturnNullIfNotImportant() {
+        LinearLayout contentView = new LinearLayout(getContext());
+        getActivity().setContentView(contentView);
+        View child1 = new View(getContext());
+        View child2 = new View(getContext());
+        child2.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
+
+        contentView.addView(child1);
+        contentView.addView(child2);
+
+        View result = AccessibilityNodeIdManager.getInstance().findView(
+                child1.getAccessibilityViewId());
+        assertNull(result);
+    }
+}
diff --git a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureEventTest.java b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureEventTest.java
new file mode 100644
index 0000000..f325d89
--- /dev/null
+++ b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureEventTest.java
@@ -0,0 +1,229 @@
+/*
+ * 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.view.contentcapture;
+
+import static android.view.contentcapture.ContentCaptureEvent.TYPE_SESSION_FINISHED;
+import static android.view.contentcapture.ContentCaptureEvent.TYPE_SESSION_STARTED;
+import static android.view.contentcapture.ContentCaptureEvent.TYPE_VIEW_DISAPPEARED;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.testng.Assert.assertThrows;
+
+import android.os.Parcel;
+import android.os.SystemClock;
+import android.view.autofill.AutofillId;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+import java.util.ArrayList;
+
+/**
+ * Unit test for {@link ContentCaptureEvent}.
+ *
+ * <p>To run it:
+ * {@code atest FrameworksCoreTests:android.view.contentcapture.ContentCaptureEventTest}
+ */
+@RunWith(JUnit4.class)
+public class ContentCaptureEventTest {
+
+    private static final long MY_EPOCH = SystemClock.uptimeMillis();
+
+    // Not using @Mock because it's final - no need to be fancy here....
+    private final ContentCaptureContext mClientContext = new ContentCaptureContext.Builder()
+            .setAction("WHATEVER").build();
+
+    @Test
+    public void testSetAutofillId_null() {
+        final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_VIEW_DISAPPEARED);
+
+        assertThrows(NullPointerException.class, () -> event.setAutofillId(null));
+        assertThat(event.getId()).isNull();
+        assertThat(event.getIds()).isNull();
+    }
+
+    @Test
+    public void testSetAutofillIds_null() {
+        final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_VIEW_DISAPPEARED);
+
+        assertThrows(NullPointerException.class, () -> event.setAutofillIds(null));
+        assertThat(event.getId()).isNull();
+        assertThat(event.getIds()).isNull();
+    }
+
+    @Test
+    public void testAddAutofillId_null() {
+        final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_VIEW_DISAPPEARED);
+
+        assertThrows(NullPointerException.class, () -> event.addAutofillId(null));
+        assertThat(event.getId()).isNull();
+        assertThat(event.getIds()).isNull();
+    }
+
+    @Test
+    public void testSetAutofillId() {
+        final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_VIEW_DISAPPEARED);
+
+        final AutofillId id = new AutofillId(108);
+        event.setAutofillId(id);
+        assertThat(event.getId()).isEqualTo(id);
+        assertThat(event.getIds()).isNull();
+    }
+
+    @Test
+    public void testSetAutofillIds() {
+        final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_VIEW_DISAPPEARED);
+
+        final AutofillId id = new AutofillId(108);
+        final ArrayList<AutofillId> ids = new ArrayList<>(1);
+        ids.add(id);
+        event.setAutofillIds(ids);
+        assertThat(event.getId()).isNull();
+        assertThat(event.getIds()).containsExactly(id);
+    }
+
+    @Test
+    public void testAddAutofillId() {
+        final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_VIEW_DISAPPEARED);
+
+        final AutofillId id1 = new AutofillId(108);
+        event.addAutofillId(id1);
+        assertThat(event.getId()).isNull();
+        assertThat(event.getIds()).containsExactly(id1);
+
+        final AutofillId id2 = new AutofillId(666);
+        event.addAutofillId(id2);
+        assertThat(event.getId()).isNull();
+        assertThat(event.getIds()).containsExactly(id1, id2).inOrder();
+    }
+
+    @Test
+    public void testAddAutofillId_afterSetId() {
+        final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_VIEW_DISAPPEARED);
+
+        final AutofillId id1 = new AutofillId(108);
+        event.setAutofillId(id1);
+        assertThat(event.getId()).isEqualTo(id1);
+        assertThat(event.getIds()).isNull();
+
+        final AutofillId id2 = new AutofillId(666);
+        event.addAutofillId(id2);
+        assertThat(event.getId()).isNull();
+        assertThat(event.getIds()).containsExactly(id1, id2).inOrder();
+    }
+
+    @Test
+    public void testAddAutofillId_afterSetIds() {
+        final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_VIEW_DISAPPEARED);
+
+        final AutofillId id1 = new AutofillId(108);
+        final ArrayList<AutofillId> ids = new ArrayList<>(1);
+        ids.add(id1);
+        event.setAutofillIds(ids);
+        assertThat(event.getId()).isNull();
+        assertThat(event.getIds()).containsExactly(id1);
+
+        final AutofillId id2 = new AutofillId(666);
+        event.addAutofillId(id2);
+        assertThat(event.getId()).isNull();
+        assertThat(event.getIds()).containsExactly(id1, id2).inOrder();
+    }
+
+    @Test
+    public void testSessionStarted_directly() {
+        final ContentCaptureEvent event = newEventForSessionStarted();
+        assertSessionStartedEvent(event);
+    }
+
+    @Test
+    public void testSessionStarted_throughParcel() {
+        final ContentCaptureEvent event = newEventForSessionStarted();
+        final ContentCaptureEvent clone = cloneThroughParcel(event);
+        assertSessionStartedEvent(clone);
+    }
+
+    private ContentCaptureEvent newEventForSessionStarted() {
+        final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_SESSION_STARTED)
+                .setClientContext(mClientContext)
+                .setParentSessionId("108");
+        assertThat(event).isNotNull();
+        return event;
+    }
+
+    private void assertSessionStartedEvent(ContentCaptureEvent event) {
+        assertThat(event.getType()).isEqualTo(TYPE_SESSION_STARTED);
+        assertThat(event.getEventTime()).isAtLeast(MY_EPOCH);
+        assertThat(event.getSessionId()).isEqualTo("42");
+        assertThat(event.getParentSessionId()).isEqualTo("108");
+        assertThat(event.getId()).isNull();
+        assertThat(event.getIds()).isNull();
+        assertThat(event.getText()).isNull();
+        assertThat(event.getViewNode()).isNull();
+        final ContentCaptureContext clientContext = event.getClientContext();
+        assertThat(clientContext.getAction()).isEqualTo("WHATEVER");
+    }
+
+    @Test
+    public void testSessionFinished_directly() {
+        final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_SESSION_FINISHED)
+                .setParentSessionId("108");
+        assertThat(event).isNotNull();
+        assertSessionFinishedEvent(event);
+    }
+
+    @Test
+    public void testSessionFinished_throughParcel() {
+        final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_SESSION_FINISHED)
+                .setClientContext(mClientContext) // should not be writting to parcel
+                .setParentSessionId("108");
+        assertThat(event).isNotNull();
+        final ContentCaptureEvent clone = cloneThroughParcel(event);
+        assertSessionFinishedEvent(clone);
+    }
+
+    private void assertSessionFinishedEvent(ContentCaptureEvent event) {
+        assertThat(event.getType()).isEqualTo(TYPE_SESSION_FINISHED);
+        assertThat(event.getEventTime()).isAtLeast(MY_EPOCH);
+        assertThat(event.getSessionId()).isEqualTo("42");
+        assertThat(event.getParentSessionId()).isEqualTo("108");
+        assertThat(event.getId()).isNull();
+        assertThat(event.getIds()).isNull();
+        assertThat(event.getText()).isNull();
+        assertThat(event.getViewNode()).isNull();
+        assertThat(event.getClientContext()).isNull();
+    }
+
+    private ContentCaptureEvent cloneThroughParcel(ContentCaptureEvent event) {
+        Parcel parcel = Parcel.obtain();
+
+        try {
+            // Write to parcel
+            parcel.setDataPosition(0); // Sanity / paranoid check
+            event.writeToParcel(parcel, 0);
+
+            // Read from parcel
+            parcel.setDataPosition(0);
+            ContentCaptureEvent clone = ContentCaptureEvent.CREATOR.createFromParcel(parcel);
+            assertThat(clone).isNotNull();
+            return clone;
+        } finally {
+            parcel.recycle();
+        }
+    }
+
+}
diff --git a/core/tests/coretests/src/android/view/contentcapture/UserDataRemovalRequestTest.java b/core/tests/coretests/src/android/view/contentcapture/UserDataRemovalRequestTest.java
deleted file mode 100644
index bebb2a8..0000000
--- a/core/tests/coretests/src/android/view/contentcapture/UserDataRemovalRequestTest.java
+++ /dev/null
@@ -1,88 +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 android.view.contentcapture;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.testng.Assert.assertThrows;
-
-import android.net.Uri;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-import org.mockito.junit.MockitoJUnitRunner;
-
-/**
- * Unit test for {@link UserDataRemovalRequest}.
- *
- * <p>To run it:
- * {@code atest FrameworksCoreTests:android.view.contentcapture.UserDataRemovalRequestTest}
- */
-@RunWith(MockitoJUnitRunner.class)
-public class UserDataRemovalRequestTest {
-
-    @Mock
-    private final Uri mUri = Uri.parse("content://com.example/");
-
-    private UserDataRemovalRequest.Builder mBuilder = new UserDataRemovalRequest.Builder();
-
-    @Test
-    public void testBuilder_addUri_invalid() {
-        assertThrows(NullPointerException.class, () -> mBuilder.addUri(null, false));
-    }
-
-    @Test
-    public void testBuilder_addUri_valid() {
-        assertThat(mBuilder.addUri(mUri, false)).isNotNull();
-        assertThat(mBuilder.addUri(Uri.parse("content://com.example2"), true)).isNotNull();
-    }
-
-    @Test
-    public void testBuilder_addUriAfterForEverything() {
-        assertThat(mBuilder.forEverything()).isNotNull();
-        assertThrows(IllegalStateException.class, () -> mBuilder.addUri(mUri, false));
-    }
-
-    @Test
-    public void testBuilder_forEverythingAfterAddingUri() {
-        assertThat(mBuilder.addUri(mUri, false)).isNotNull();
-        assertThrows(IllegalStateException.class, () -> mBuilder.forEverything());
-    }
-
-    @Test
-    public void testBuild_invalid() {
-        assertThrows(IllegalStateException.class, () -> mBuilder.build());
-    }
-
-    @Test
-    public void testBuild_valid() {
-        assertThat(new UserDataRemovalRequest.Builder().forEverything().build())
-                .isNotNull();
-        assertThat(new UserDataRemovalRequest.Builder().addUri(mUri, false).build())
-                .isNotNull();
-    }
-
-    @Test
-    public void testNoMoreInteractionsAfterBuild() {
-        assertThat(mBuilder.forEverything().build()).isNotNull();
-
-        assertThrows(IllegalStateException.class, () -> mBuilder.addUri(mUri, false));
-        assertThrows(IllegalStateException.class, () -> mBuilder.forEverything());
-        assertThrows(IllegalStateException.class, () -> mBuilder.build());
-
-    }
-}
diff --git a/core/tests/coretests/src/android/view/contentcapture/ViewNodeTest.java b/core/tests/coretests/src/android/view/contentcapture/ViewNodeTest.java
index b84a098..213cd40 100644
--- a/core/tests/coretests/src/android/view/contentcapture/ViewNodeTest.java
+++ b/core/tests/coretests/src/android/view/contentcapture/ViewNodeTest.java
@@ -18,29 +18,18 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static org.testng.Assert.assertThrows;
-
 import android.content.Context;
 import android.graphics.Matrix;
-import android.os.Bundle;
-import android.os.LocaleList;
-import android.os.Parcel;
+import android.support.test.InstrumentationRegistry;
 import android.view.View;
 import android.view.ViewStructure.HtmlInfo;
-import android.view.autofill.AutofillId;
-import android.view.autofill.AutofillValue;
 import android.view.contentcapture.ViewNode.ViewStructureImpl;
-import android.widget.FrameLayout;
-
-import androidx.test.InstrumentationRegistry;
 
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.junit.MockitoJUnitRunner;
 
-import java.util.Locale;
-
 /**
  * Unit tests for {@link ViewNode}.
  *
@@ -55,100 +44,6 @@
     private HtmlInfo mHtmlInfoMock;
 
     @Test
-    public void testAutofillIdMethods_orphanView() {
-        View view = new View(mContext);
-        AutofillId initialId = new AutofillId(42);
-        view.setAutofillId(initialId);
-
-        ViewStructureImpl structure = new ViewStructureImpl(view);
-        ViewNode node = structure.getNode();
-
-        assertThat(node.getAutofillId()).isEqualTo(initialId);
-        assertThat(node.getParentAutofillId()).isNull();
-
-        AutofillId newId = new AutofillId(108);
-        structure.setAutofillId(newId);
-        assertThat(node.getAutofillId()).isEqualTo(newId);
-        assertThat(node.getParentAutofillId()).isNull();
-
-        structure.setAutofillId(new AutofillId(66), 6);
-        assertThat(node.getAutofillId()).isEqualTo(new AutofillId(66, 6));
-        assertThat(node.getParentAutofillId()).isEqualTo(new AutofillId(66));
-    }
-
-    @Test
-    public void testAutofillIdMethods_parentedView() {
-        FrameLayout parent = new FrameLayout(mContext);
-        AutofillId initialParentId = new AutofillId(48);
-        parent.setAutofillId(initialParentId);
-
-        View child = new View(mContext);
-        AutofillId initialChildId = new AutofillId(42);
-        child.setAutofillId(initialChildId);
-
-        parent.addView(child);
-
-        ViewStructureImpl structure = new ViewStructureImpl(child);
-        ViewNode node = structure.getNode();
-
-        assertThat(node.getAutofillId()).isEqualTo(initialChildId);
-        assertThat(node.getParentAutofillId()).isEqualTo(initialParentId);
-
-        AutofillId newChildId = new AutofillId(108);
-        structure.setAutofillId(newChildId);
-        assertThat(node.getAutofillId()).isEqualTo(newChildId);
-        assertThat(node.getParentAutofillId()).isEqualTo(initialParentId);
-
-        AutofillId newParentId = new AutofillId(15162342);
-        parent.setAutofillId(newParentId);
-        assertThat(node.getAutofillId()).isEqualTo(newChildId);
-        assertThat(node.getParentAutofillId()).isEqualTo(initialParentId);
-
-        structure.setAutofillId(new AutofillId(66), 6);
-        assertThat(node.getAutofillId()).isEqualTo(new AutofillId(66, 6));
-        assertThat(node.getParentAutofillId()).isEqualTo(new AutofillId(66));
-    }
-
-    @Test
-    public void testAutofillIdMethods_explicitIdsConstructor() {
-        AutofillId initialParentId = new AutofillId(42);
-        ViewStructureImpl structure = new ViewStructureImpl(initialParentId, 108, 666);
-        ViewNode node = structure.getNode();
-
-        assertThat(node.getAutofillId()).isEqualTo(new AutofillId(initialParentId, 108, 666));
-        assertThat(node.getParentAutofillId()).isEqualTo(initialParentId);
-
-        AutofillId newChildId = new AutofillId(108);
-        structure.setAutofillId(newChildId);
-        assertThat(node.getAutofillId()).isEqualTo(newChildId);
-        assertThat(node.getParentAutofillId()).isEqualTo(initialParentId);
-
-        structure.setAutofillId(new AutofillId(66), 6);
-        assertThat(node.getAutofillId()).isEqualTo(new AutofillId(66, 6));
-        assertThat(node.getParentAutofillId()).isEqualTo(new AutofillId(66));
-    }
-
-    @Test
-    public void testInvalidSetters() {
-        View view = new View(mContext);
-        AutofillId initialId = new AutofillId(42);
-        view.setAutofillId(initialId);
-
-        ViewStructureImpl structure = new ViewStructureImpl(view);
-        ViewNode node = structure.getNode();
-        assertThat(node.getAutofillId()).isEqualTo(initialId); // sanity check
-
-        assertThrows(NullPointerException.class, () -> structure.setAutofillId(null));
-        assertThat(node.getAutofillId()).isEqualTo(initialId); // invariant
-
-        assertThrows(NullPointerException.class, () -> structure.setAutofillId(null, 666));
-        assertThat(node.getAutofillId()).isEqualTo(initialId); // invariant
-
-        assertThrows(NullPointerException.class, () -> structure.setTextIdEntry(null));
-        assertThat(node.getTextIdEntry()).isNull();
-    }
-
-    @Test
     public void testUnsupportedProperties() {
         View view = new View(mContext);
 
@@ -190,273 +85,4 @@
         structure.setTransformation(Matrix.IDENTITY_MATRIX);
         assertThat(node.getTransformation()).isNull();
     }
-
-    @Test
-    public void testValidProperties_directly() {
-        ViewStructureImpl structure = newSimpleStructure();
-        assertSimpleStructure(structure);
-        assertSimpleNode(structure.getNode());
-    }
-
-    @Test
-    public void testValidProperties_throughParcel() {
-        ViewStructureImpl structure = newSimpleStructure();
-        final ViewNode node = structure.getNode();
-        assertSimpleNode(node); // sanity check
-
-        final ViewNode clone = cloneThroughParcel(node);
-        assertSimpleNode(clone);
-    }
-
-    @Test
-    public void testComplexText_directly() {
-        ViewStructureImpl structure = newStructureWithComplexText();
-        assertStructureWithComplexText(structure);
-        assertNodeWithComplexText(structure.getNode());
-    }
-
-    @Test
-    public void testComplexText_throughParcel() {
-        ViewStructureImpl structure = newStructureWithComplexText();
-        final ViewNode node = structure.getNode();
-        assertNodeWithComplexText(node); // sanity check
-
-        ViewNode clone = cloneThroughParcel(node);
-        assertNodeWithComplexText(clone);
-    }
-
-    @Test
-    public void testVisibility() {
-        // Visibility is a special case becase it use flag masks, so we want to make sure it works
-        // fine
-        View view = new View(mContext);
-        ViewStructureImpl structure = new ViewStructureImpl(view);
-        ViewNode node = structure.getNode();
-
-        structure.setVisibility(View.VISIBLE);
-        assertThat(node.getVisibility()).isEqualTo(View.VISIBLE);
-        assertThat(cloneThroughParcel(node).getVisibility()).isEqualTo(View.VISIBLE);
-
-        structure.setVisibility(View.GONE);
-        assertThat(node.getVisibility()).isEqualTo(View.GONE);
-        assertThat(cloneThroughParcel(node).getVisibility()).isEqualTo(View.GONE);
-
-        structure.setVisibility(View.VISIBLE);
-        assertThat(node.getVisibility()).isEqualTo(View.VISIBLE);
-        assertThat(cloneThroughParcel(node).getVisibility()).isEqualTo(View.VISIBLE);
-
-        structure.setVisibility(View.INVISIBLE);
-        assertThat(node.getVisibility()).isEqualTo(View.INVISIBLE);
-        assertThat(cloneThroughParcel(node).getVisibility()).isEqualTo(View.INVISIBLE);
-
-        structure.setVisibility(View.INVISIBLE | View.GONE);
-        assertThat(node.getVisibility()).isEqualTo(View.INVISIBLE | View.GONE);
-        assertThat(cloneThroughParcel(node).getVisibility()).isEqualTo(View.INVISIBLE | View.GONE);
-
-
-        final int invalidValue = Math.max(Math.max(View.VISIBLE, View.INVISIBLE), View.GONE) * 2;
-        structure.setVisibility(View.VISIBLE);
-        structure.setVisibility(invalidValue); // should be ignored
-        assertThat(node.getVisibility()).isEqualTo(View.VISIBLE);
-        assertThat(cloneThroughParcel(node).getVisibility()).isEqualTo(View.VISIBLE);
-
-        structure.setVisibility(View.GONE | invalidValue);
-        assertThat(node.getVisibility()).isEqualTo(View.GONE);
-        assertThat(cloneThroughParcel(node).getVisibility()).isEqualTo(View.GONE);
-    }
-
-    /**
-     * Creates a {@link ViewStructureImpl} that can be asserted through
-     * {@link #assertSimpleNode(ViewNode)}.
-     */
-    private ViewStructureImpl newSimpleStructure() {
-        View view = new View(mContext);
-        view.setAutofillId(new AutofillId(42));
-
-        ViewStructureImpl structure = new ViewStructureImpl(view);
-
-        // Basic properties
-        structure.setText("Text is set!");
-        structure.setClassName("Classy!");
-        structure.setContentDescription("Described I am!");
-        structure.setVisibility(View.INVISIBLE);
-
-        // Autofill properties
-        structure.setAutofillType(View.AUTOFILL_TYPE_TEXT);
-        structure.setAutofillHints(new String[] { "Auto", "Man" });
-        structure.setAutofillOptions(new String[] { "Maybe" });
-        structure.setAutofillValue(AutofillValue.forText("Malkovich"));
-
-        // Extra text properties
-        structure.setMinTextEms(6);
-        structure.setMaxTextLength(66);
-        structure.setMaxTextEms(666);
-        structure.setInputType(42);
-        structure.setTextIdEntry("TEXT, Y U NO ENTRY?");
-        structure.setLocaleList(new LocaleList(Locale.US, Locale.ENGLISH));
-
-        // Resource id
-        structure.setId(16, "package.name", "type.name", "entry.name");
-
-        // Dimensions
-        structure.setDimens(4, 8, 15, 16, 23, 42);
-
-        // Boolean properties
-        structure.setAssistBlocked(true);
-        structure.setEnabled(true);
-        structure.setClickable(true);
-        structure.setLongClickable(true);
-        structure.setContextClickable(true);
-        structure.setFocusable(true);
-        structure.setFocused(true);
-        structure.setAccessibilityFocused(true);
-        structure.setChecked(true);
-        structure.setActivated(true);
-        structure.setOpaque(true);
-
-        // Bundle
-        assertThat(structure.hasExtras()).isFalse();
-        final Bundle bundle = structure.getExtras();
-        assertThat(bundle).isNotNull();
-        bundle.putString("Marlon", "Bundle");
-        assertThat(structure.hasExtras()).isTrue();
-        return structure;
-    }
-
-    /**
-     * Asserts the properties of a {@link ViewNode} that was created by
-     * {@link #newSimpleStructure()}.
-     */
-    private void assertSimpleNode(ViewNode node) {
-
-        // Basic properties
-        assertThat(node.getAutofillId()).isEqualTo(new AutofillId(42));
-        assertThat(node.getParentAutofillId()).isNull();
-        assertThat(node.getText()).isEqualTo("Text is set!");
-        assertThat(node.getClassName()).isEqualTo("Classy!");
-        assertThat(node.getContentDescription().toString()).isEqualTo("Described I am!");
-        assertThat(node.getVisibility()).isEqualTo(View.INVISIBLE);
-
-        // Autofill properties
-        assertThat(node.getAutofillType()).isEqualTo(View.AUTOFILL_TYPE_TEXT);
-        assertThat(node.getAutofillHints()).asList().containsExactly("Auto", "Man").inOrder();
-        assertThat(node.getAutofillOptions()).asList().containsExactly("Maybe").inOrder();
-        assertThat(node.getAutofillValue().getTextValue()).isEqualTo("Malkovich");
-
-        // Extra text properties
-        assertThat(node.getMinTextEms()).isEqualTo(6);
-        assertThat(node.getMaxTextLength()).isEqualTo(66);
-        assertThat(node.getMaxTextEms()).isEqualTo(666);
-        assertThat(node.getInputType()).isEqualTo(42);
-        assertThat(node.getTextIdEntry()).isEqualTo("TEXT, Y U NO ENTRY?");
-        assertThat(node.getLocaleList()).isEqualTo(new LocaleList(Locale.US, Locale.ENGLISH));
-
-        // Resource id
-        assertThat(node.getId()).isEqualTo(16);
-        assertThat(node.getIdPackage()).isEqualTo("package.name");
-        assertThat(node.getIdType()).isEqualTo("type.name");
-        assertThat(node.getIdEntry()).isEqualTo("entry.name");
-
-        // Dimensions
-        assertThat(node.getLeft()).isEqualTo(4);
-        assertThat(node.getTop()).isEqualTo(8);
-        assertThat(node.getScrollX()).isEqualTo(15);
-        assertThat(node.getScrollY()).isEqualTo(16);
-        assertThat(node.getWidth()).isEqualTo(23);
-        assertThat(node.getHeight()).isEqualTo(42);
-
-        // Boolean properties
-        assertThat(node.isAssistBlocked()).isTrue();
-        assertThat(node.isEnabled()).isTrue();
-        assertThat(node.isClickable()).isTrue();
-        assertThat(node.isLongClickable()).isTrue();
-        assertThat(node.isContextClickable()).isTrue();
-        assertThat(node.isFocusable()).isTrue();
-        assertThat(node.isFocused()).isTrue();
-        assertThat(node.isAccessibilityFocused()).isTrue();
-        assertThat(node.isChecked()).isTrue();
-        assertThat(node.isActivated()).isTrue();
-        assertThat(node.isOpaque()).isTrue();
-
-        // Bundle
-        final Bundle bundle = node.getExtras();
-        assertThat(bundle).isNotNull();
-        assertThat(bundle.size()).isEqualTo(1);
-        assertThat(bundle.getString("Marlon")).isEqualTo("Bundle");
-    }
-
-    /**
-     * Asserts the properties of a {@link ViewStructureImpl} that was created by
-     * {@link #newSimpleStructure()}.
-     */
-    private void assertSimpleStructure(ViewStructureImpl structure) {
-        assertThat(structure.getAutofillId()).isEqualTo(new AutofillId(42));
-        assertThat(structure.getText()).isEqualTo("Text is set!");
-
-        // Bundle
-        final Bundle bundle = structure.getExtras();
-        assertThat(bundle.size()).isEqualTo(1);
-        assertThat(bundle.getString("Marlon")).isEqualTo("Bundle");
-    }
-
-    /**
-     * Creates a {@link ViewStructureImpl} with "complex" text properties (such as selection); it
-     * can be asserted through {@link #assertNodeWithComplexText(ViewNode)}.
-     */
-    private ViewStructureImpl newStructureWithComplexText() {
-        View view = new View(mContext);
-        ViewStructureImpl structure = new ViewStructureImpl(view);
-        structure.setText("IGNORE ME!");
-        structure.setText("Now we're talking!", 4, 8);
-        structure.setHint("Soylent Green is SPOILER ALERT");
-        structure.setTextStyle(15.0f, 16, 23, 42);
-        structure.setTextLines(new int[] {4,  8, 15} , new int[] {16, 23, 42});
-        return structure;
-    }
-
-    /**
-     * Asserts the properties of a {@link ViewNode} that was created by
-     * {@link #newStructureWithComplexText()}.
-     */
-    private void assertNodeWithComplexText(ViewNode node) {
-        assertThat(node.getText()).isEqualTo("Now we're talking!");
-        assertThat(node.getTextSelectionStart()).isEqualTo(4);
-        assertThat(node.getTextSelectionEnd()).isEqualTo(8);
-        assertThat(node.getHint()).isEqualTo("Soylent Green is SPOILER ALERT");
-        assertThat(node.getTextSize()).isWithin(1.0e-10f).of(15.0f);
-        assertThat(node.getTextColor()).isEqualTo(16);
-        assertThat(node.getTextBackgroundColor()).isEqualTo(23);
-        assertThat(node.getTextStyle()).isEqualTo(42);
-        assertThat(node.getTextLineCharOffsets()).asList().containsExactly(4, 8, 15).inOrder();
-        assertThat(node.getTextLineBaselines()).asList().containsExactly(16, 23, 42).inOrder();
-    }
-
-    /**
-     * Asserts the properties of a {@link ViewStructureImpl} that was created by
-     * {@link #newStructureWithComplexText()}.
-     */
-    private void assertStructureWithComplexText(ViewStructureImpl structure) {
-        assertThat(structure.getText()).isEqualTo("Now we're talking!");
-        assertThat(structure.getTextSelectionStart()).isEqualTo(4);
-        assertThat(structure.getTextSelectionEnd()).isEqualTo(8);
-        assertThat(structure.getHint()).isEqualTo("Soylent Green is SPOILER ALERT");
-    }
-
-    private ViewNode cloneThroughParcel(ViewNode node) {
-        Parcel parcel = Parcel.obtain();
-
-        try {
-            // Write to parcel
-            parcel.setDataPosition(0); // Sanity / paranoid check
-            ViewNode.writeToParcel(parcel, node, 0);
-
-            // Read from parcel
-            parcel.setDataPosition(0);
-            ViewNode clone = ViewNode.readFromParcel(parcel);
-            assertThat(clone).isNotNull();
-            return clone;
-        } finally {
-            parcel.recycle();
-        }
-    }
 }
diff --git a/core/tests/coretests/src/android/view/textclassifier/TemplateClassificationIntentFactoryTest.java b/core/tests/coretests/src/android/view/textclassifier/TemplateClassificationIntentFactoryTest.java
index 08ad62a..d9dac31 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TemplateClassificationIntentFactoryTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TemplateClassificationIntentFactoryTest.java
@@ -41,6 +41,7 @@
 
     private static final String TEXT = "text";
     private static final String TITLE = "Map";
+    private static final String DESCRIPTION = "Opens in Maps";
     private static final String ACTION = Intent.ACTION_VIEW;
 
     @Mock
@@ -57,19 +58,6 @@
 
     @Test
     public void create_foreignText() {
-        RemoteActionTemplate remoteActionTemplate = new RemoteActionTemplate(
-                TITLE,
-                null,
-                ACTION,
-                null,
-                null,
-                null,
-                null,
-                null,
-                null,
-                null
-        );
-
         AnnotatorModel.ClassificationResult classificationResult =
                 new AnnotatorModel.ClassificationResult(
                         TextClassifier.TYPE_ADDRESS,
@@ -81,7 +69,7 @@
                         null,
                         null,
                         null,
-                        new RemoteActionTemplate[]{remoteActionTemplate});
+                        createRemoteActionTemplates());
 
         List<TextClassifierImpl.LabeledIntent> intents =
                 mTemplateClassificationIntentFactory.create(
@@ -106,19 +94,6 @@
 
     @Test
     public void create_notForeignText() {
-        RemoteActionTemplate remoteActionTemplate = new RemoteActionTemplate(
-                TITLE,
-                null,
-                ACTION,
-                null,
-                null,
-                null,
-                null,
-                null,
-                null,
-                null
-        );
-
         AnnotatorModel.ClassificationResult classificationResult =
                 new AnnotatorModel.ClassificationResult(
                         TextClassifier.TYPE_ADDRESS,
@@ -130,7 +105,7 @@
                         null,
                         null,
                         null,
-                        new RemoteActionTemplate[]{remoteActionTemplate});
+                        createRemoteActionTemplates());
 
         List<TextClassifierImpl.LabeledIntent> intents =
                 mTemplateClassificationIntentFactory.create(
@@ -147,4 +122,21 @@
         assertThat(intent.getAction()).isEqualTo(ACTION);
         assertThat(intent.hasExtra(TextClassifier.EXTRA_FROM_TEXT_CLASSIFIER)).isTrue();
     }
+
+    private static RemoteActionTemplate[] createRemoteActionTemplates() {
+        return new RemoteActionTemplate[]{
+                new RemoteActionTemplate(
+                        TITLE,
+                        DESCRIPTION,
+                        ACTION,
+                        null,
+                        null,
+                        null,
+                        null,
+                        null,
+                        null,
+                        null
+                )
+        };
+    }
 }
diff --git a/core/tests/coretests/src/android/view/textclassifier/TemplateIntentFactoryTest.java b/core/tests/coretests/src/android/view/textclassifier/TemplateIntentFactoryTest.java
index 0d364a3..a1158a7 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TemplateIntentFactoryTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TemplateIntentFactoryTest.java
@@ -81,7 +81,6 @@
                 REQUEST_CODE
         );
 
-
         List<TextClassifierImpl.LabeledIntent> intents =
                 mTemplateIntentFactory.create(new RemoteActionTemplate[]{remoteActionTemplate});
 
@@ -97,14 +96,79 @@
         assertThat(intent.getFlags()).isEqualTo(FLAG);
         assertThat(intent.getCategories()).containsExactly((Object[]) CATEGORY);
         assertThat(intent.getPackage()).isNull();
-        assertThat(
-                intent.getStringExtra(KEY_ONE)).isEqualTo(VALUE_ONE);
+        assertThat(intent.getStringExtra(KEY_ONE)).isEqualTo(VALUE_ONE);
         assertThat(intent.getIntExtra(KEY_TWO, 0)).isEqualTo(VALUE_TWO);
         assertThat(intent.hasExtra(TextClassifier.EXTRA_FROM_TEXT_CLASSIFIER)).isTrue();
     }
 
     @Test
-    public void create_packageIsNotNull() {
+    public void normalizesScheme() {
+        RemoteActionTemplate remoteActionTemplate = new RemoteActionTemplate(
+                TITLE,
+                DESCRIPTION,
+                ACTION,
+                "HTTp://www.android.com",
+                TYPE,
+                FLAG,
+                CATEGORY,
+                /* packageName */ null,
+                NAMED_VARIANTS,
+                REQUEST_CODE
+        );
+
+        List<TextClassifierImpl.LabeledIntent> intents =
+                mTemplateIntentFactory.create(new RemoteActionTemplate[] {remoteActionTemplate});
+
+        String data = intents.get(0).getIntent().getData().toString();
+        assertThat(data).isEqualTo("http://www.android.com");
+    }
+
+    @Test
+    public void create_minimal() {
+        RemoteActionTemplate remoteActionTemplate = new RemoteActionTemplate(
+                TITLE,
+                DESCRIPTION,
+                ACTION,
+                null,
+                null,
+                null,
+                null,
+                null,
+                null,
+                null
+        );
+
+        List<TextClassifierImpl.LabeledIntent> intents =
+                mTemplateIntentFactory.create(new RemoteActionTemplate[]{remoteActionTemplate});
+
+        assertThat(intents).hasSize(1);
+        TextClassifierImpl.LabeledIntent labeledIntent = intents.get(0);
+        assertThat(labeledIntent.getTitle()).isEqualTo(TITLE);
+        assertThat(labeledIntent.getDescription()).isEqualTo(DESCRIPTION);
+        assertThat(labeledIntent.getRequestCode()).isEqualTo(
+                TextClassifierImpl.LabeledIntent.DEFAULT_REQUEST_CODE);
+        Intent intent = labeledIntent.getIntent();
+        assertThat(intent.getAction()).isEqualTo(ACTION);
+        assertThat(intent.getData()).isNull();
+        assertThat(intent.getType()).isNull();
+        assertThat(intent.getFlags()).isEqualTo(0);
+        assertThat(intent.getCategories()).isNull();
+        assertThat(intent.getPackage()).isNull();
+        assertThat(intent.hasExtra(TextClassifier.EXTRA_FROM_TEXT_CLASSIFIER)).isTrue();
+    }
+
+    @Test
+    public void invalidTemplate_nullTemplate() {
+        RemoteActionTemplate remoteActionTemplate = null;
+
+        List<TextClassifierImpl.LabeledIntent> intents =
+                mTemplateIntentFactory.create(new RemoteActionTemplate[] {remoteActionTemplate});
+
+        assertThat(intents).isEmpty();
+    }
+
+    @Test
+    public void invalidTemplate_nonEmptyPackageName() {
         RemoteActionTemplate remoteActionTemplate = new RemoteActionTemplate(
                 TITLE,
                 DESCRIPTION,
@@ -121,41 +185,69 @@
         List<TextClassifierImpl.LabeledIntent> intents =
                 mTemplateIntentFactory.create(new RemoteActionTemplate[] {remoteActionTemplate});
 
-        assertThat(intents).hasSize(0);
+        assertThat(intents).isEmpty();
     }
 
     @Test
-    public void create_minimal() {
+    public void invalidTemplate_emptyTitle() {
         RemoteActionTemplate remoteActionTemplate = new RemoteActionTemplate(
                 null,
+                DESCRIPTION,
+                ACTION,
                 null,
                 null,
                 null,
                 null,
                 null,
                 null,
+                null
+        );
+
+        List<TextClassifierImpl.LabeledIntent> intents =
+                mTemplateIntentFactory.create(new RemoteActionTemplate[] {remoteActionTemplate});
+
+        assertThat(intents).isEmpty();
+    }
+
+    @Test
+    public void invalidTemplate_emptyDescription() {
+        RemoteActionTemplate remoteActionTemplate = new RemoteActionTemplate(
+                TITLE,
+                null,
+                ACTION,
+                null,
+                null,
+                null,
+                null,
+                null,
+                null,
+                null
+        );
+
+        List<TextClassifierImpl.LabeledIntent> intents =
+                mTemplateIntentFactory.create(new RemoteActionTemplate[] {remoteActionTemplate});
+
+        assertThat(intents).isEmpty();
+    }
+
+    @Test
+    public void invalidTemplate_emptyIntentAction() {
+        RemoteActionTemplate remoteActionTemplate = new RemoteActionTemplate(
+                TITLE,
+                DESCRIPTION,
+                null,
+                null,
+                null,
+                null,
+                null,
                 null,
                 null,
                 null
         );
 
         List<TextClassifierImpl.LabeledIntent> intents =
-                mTemplateIntentFactory.create(new RemoteActionTemplate[]{remoteActionTemplate});
+                mTemplateIntentFactory.create(new RemoteActionTemplate[] {remoteActionTemplate});
 
-
-        assertThat(intents).hasSize(1);
-        TextClassifierImpl.LabeledIntent labeledIntent = intents.get(0);
-        assertThat(labeledIntent.getTitle()).isNull();
-        assertThat(labeledIntent.getDescription()).isNull();
-        assertThat(labeledIntent.getRequestCode()).isEqualTo(
-                TextClassifierImpl.LabeledIntent.DEFAULT_REQUEST_CODE);
-        Intent intent = labeledIntent.getIntent();
-        assertThat(intent.getAction()).isNull();
-        assertThat(intent.getData()).isNull();
-        assertThat(intent.getType()).isNull();
-        assertThat(intent.getFlags()).isEqualTo(0);
-        assertThat(intent.getCategories()).isNull();
-        assertThat(intent.getPackage()).isNull();
-        assertThat(intent.hasExtra(TextClassifier.EXTRA_FROM_TEXT_CLASSIFIER)).isTrue();
+        assertThat(intents).isEmpty();
     }
 }
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java
index 32bafec..fe2a660 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationConstantsTest.java
@@ -195,11 +195,13 @@
         assertWithMessage("in_app_conversation_action_types_default")
                 .that(constants.getInAppConversationActionTypes())
                 .containsExactly("text_reply", "create_reminder", "call_phone", "open_url",
-                        "send_email", "send_sms", "track_flight", "view_calendar", "view_map");
+                        "send_email", "send_sms", "track_flight", "view_calendar", "view_map",
+                        "add_contact");
         assertWithMessage("notification_conversation_action_types_default")
                 .that(constants.getNotificationConversationActionTypes())
                 .containsExactly("text_reply", "create_reminder", "call_phone", "open_url",
-                        "send_email", "send_sms", "track_flight", "view_calendar", "view_map");
+                        "send_email", "send_sms", "track_flight", "view_calendar", "view_map",
+                        "add_contact");
         assertWithMessage("lang_id_threshold_override")
                 .that(constants.getLangIdThresholdOverride()).isWithin(EPSILON).of(-1f);
     }
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
index 582be9d..bdd0370 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassifierTest.java
@@ -176,6 +176,7 @@
 
         TextClassification classification = mClassifier.classifyText(request);
         assertThat(classification, isTextClassification(classifiedText, TextClassifier.TYPE_URL));
+        assertThat(classification, containsIntentWithAction(Intent.ACTION_VIEW));
     }
 
     @Test
@@ -207,6 +208,7 @@
 
         TextClassification classification = mClassifier.classifyText(request);
         assertThat(classification, isTextClassification(classifiedText, TextClassifier.TYPE_URL));
+        assertThat(classification, containsIntentWithAction(Intent.ACTION_VIEW));
     }
 
     @Test
@@ -517,6 +519,24 @@
         };
     }
 
+    private static Matcher<TextClassification> containsIntentWithAction(final String action) {
+        return new BaseMatcher<TextClassification>() {
+            @Override
+            public boolean matches(Object o) {
+                if (o instanceof TextClassification) {
+                    TextClassification result = (TextClassification) o;
+                    return ExtrasUtils.findAction(result, action) != null;
+                }
+                return false;
+            }
+
+            @Override
+            public void describeTo(Description description) {
+                description.appendText("intent action=").appendValue(action);
+            }
+        };
+    }
+
     private static Matcher<TextLanguage> isTextLanguage(final String languageTag) {
         return new BaseMatcher<TextLanguage>() {
             @Override
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 73af567..1980a60 100644
--- a/core/tests/coretests/src/android/view/textclassifier/logging/TextClassifierEventTronLoggerTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/logging/TextClassifierEventTronLoggerTest.java
@@ -91,8 +91,8 @@
                 .isEqualTo(ConversationAction.TYPE_CALL_PHONE);
         assertThat((float) logMaker.getTaggedData(FIELD_TEXT_CLASSIFIER_SCORE))
                 .isWithin(0.00001f).of(0.5f);
-        assertThat(logMaker.getTaggedData(FIELD_TEXT_CLASSIFIER_EVENT_TIME))
-                .isEqualTo(EVENT_TIME);
+        // Never write event time.
+        assertThat(logMaker.getTaggedData(FIELD_TEXT_CLASSIFIER_EVENT_TIME)).isNull();
         assertThat(logMaker.getPackageName()).isEqualTo(PACKAGE_NAME);
         assertThat(logMaker.getTaggedData(FIELD_TEXT_CLASSIFIER_WIDGET_TYPE))
                 .isEqualTo(WIDGET_TYPE);
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
index b6f56ad..3d59835a 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
@@ -27,7 +27,9 @@
 
 import static org.hamcrest.CoreMatchers.is;
 import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.CoreMatchers.notNullValue;
 import static org.hamcrest.MatcherAssert.assertThat;
+import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -43,6 +45,7 @@
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Paint;
+import android.metrics.LogMaker;
 import android.net.Uri;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -51,11 +54,14 @@
 
 import com.android.internal.R;
 import com.android.internal.app.ResolverActivity.ResolvedComponentInfo;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto;
 
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
 import org.mockito.Mockito;
 
 import java.util.ArrayList;
@@ -66,6 +72,11 @@
  */
 @RunWith(AndroidJUnit4.class)
 public class ChooserActivityTest {
+
+    private static final int CONTENT_PREVIEW_IMAGE = 1;
+    private static final int CONTENT_PREVIEW_FILE = 2;
+    private static final int CONTENT_PREVIEW_TEXT = 3;
+
     @Rule
     public ActivityTestRule<ChooserWrapperActivity> mActivityRule =
             new ActivityTestRule<>(ChooserWrapperActivity.class, false,
@@ -402,16 +413,15 @@
                 createResolvedComponentsForTestWithOtherProfile(1);
 
         when(ChooserWrapperActivity.sOverrides.resolverListController.getResolversForIntent(
-                Mockito.anyBoolean(),
-                Mockito.anyBoolean(),
-                Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
+            Mockito.anyBoolean(),
+            Mockito.anyBoolean(),
+            Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
 
         final ChooserWrapperActivity activity = mActivityRule
                 .launchActivity(Intent.createChooser(sendIntent, null));
         waitForIdle();
 
         onView(withId(R.id.copy_button)).perform(click());
-
         ClipboardManager clipboard = (ClipboardManager) activity.getSystemService(
                 Context.CLIPBOARD_SERVICE);
         ClipData clipData = clipboard.getPrimaryClip();
@@ -488,8 +498,8 @@
         List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
 
         when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
-                Mockito.anyBoolean(),
-                Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
+            Mockito.anyBoolean(),
+            Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
         mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
         waitForIdle();
         onView(withId(R.id.content_preview_image_1_large)).check(matches(isDisplayed()));
@@ -498,6 +508,93 @@
         onView(withId(R.id.content_preview_image_3_small)).check(matches(isDisplayed()));
     }
 
+    @Test
+    public void testOnCreateLogging() {
+        Intent sendIntent = createSendTextIntent();
+        sendIntent.setType("TestType");
+
+        MetricsLogger mockLogger = sOverrides.metricsLogger;
+        ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class);
+        mActivityRule.launchActivity(Intent.createChooser(sendIntent, "logger test"));
+        waitForIdle();
+        verify(mockLogger, atLeastOnce()).write(logMakerCaptor.capture());
+        assertThat(logMakerCaptor.getAllValues().get(0).getCategory(),
+                is(MetricsProto.MetricsEvent.ACTION_ACTIVITY_CHOOSER_SHOWN));
+        assertThat(logMakerCaptor
+                .getAllValues().get(0)
+                .getTaggedData(MetricsProto.MetricsEvent.FIELD_TIME_TO_APP_TARGETS),
+                is(notNullValue()));
+        assertThat(logMakerCaptor
+                .getAllValues().get(0)
+                .getTaggedData(MetricsProto.MetricsEvent.FIELD_SHARESHEET_MIMETYPE),
+                is("TestType"));
+    }
+
+    @Test
+    public void testEmptyPreviewLogging() {
+        Intent sendIntent = createSendTextIntentWithPreview(null, null);
+
+        MetricsLogger mockLogger = sOverrides.metricsLogger;
+        ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class);
+        mActivityRule.launchActivity(Intent.createChooser(sendIntent, "empty preview logger test"));
+        waitForIdle();
+        verify(mockLogger, Mockito.times(2)).write(logMakerCaptor.capture());
+        // First invocation is from onCreate
+        assertThat(logMakerCaptor.getAllValues().get(1).getCategory(),
+                is(MetricsProto.MetricsEvent.ACTION_SHARE_WITH_PREVIEW));
+        assertThat(logMakerCaptor.getAllValues().get(1).getSubtype(),
+                is(CONTENT_PREVIEW_TEXT));
+    }
+
+    @Test
+    public void testTitlePreviewLogging() {
+        Intent sendIntent = createSendTextIntentWithPreview("TestTitle", null);
+
+        MetricsLogger mockLogger = sOverrides.metricsLogger;
+        ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class);
+        mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
+        waitForIdle();
+        verify(mockLogger, Mockito.times(2)).write(logMakerCaptor.capture());
+        // First invocation is from onCreate
+        assertThat(logMakerCaptor.getAllValues().get(1).getCategory(),
+                is(MetricsProto.MetricsEvent.ACTION_SHARE_WITH_PREVIEW));
+        assertThat(logMakerCaptor.getAllValues().get(1).getSubtype(),
+                is(CONTENT_PREVIEW_TEXT));
+    }
+
+    @Test
+    public void testImagePreviewLogging() {
+        Uri uri = Uri.parse("android.resource://com.android.frameworks.coretests/"
+                + com.android.frameworks.coretests.R.drawable.test320x240);
+
+        ArrayList<Uri> uris = new ArrayList<>();
+        uris.add(uri);
+
+        Intent sendIntent = createSendImageIntentWithPreview(uris);
+        sOverrides.previewThumbnail = createBitmap();
+
+        List<ResolvedComponentInfo> resolvedComponentInfos = createResolvedComponentsForTest(2);
+
+        when(sOverrides.resolverListController.getResolversForIntent(Mockito.anyBoolean(),
+            Mockito.anyBoolean(),
+            Mockito.isA(List.class))).thenReturn(resolvedComponentInfos);
+
+        MetricsLogger mockLogger = sOverrides.metricsLogger;
+        ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class);
+        mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
+        waitForIdle();
+        verify(mockLogger, Mockito.times(3)).write(logMakerCaptor.capture());
+        // First invocation is from onCreate
+        assertThat(logMakerCaptor.getAllValues().get(1).getCategory(),
+                is(MetricsProto.MetricsEvent.ACTION_SHARE_WITH_PREVIEW));
+        assertThat(logMakerCaptor.getAllValues().get(1).getSubtype(),
+                is(CONTENT_PREVIEW_IMAGE));
+        assertThat(logMakerCaptor.getAllValues().get(2).getCategory(),
+                is(MetricsProto.MetricsEvent.ACTION_SHARE_WITH_PREVIEW));
+        assertThat(logMakerCaptor.getAllValues().get(2).getSubtype(),
+                is(CONTENT_PREVIEW_IMAGE));
+    }
+
     private Intent createSendTextIntent() {
         Intent sendIntent = new Intent();
         sendIntent.setAction(Intent.ACTION_SEND);
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
index ec8122f..f60467b 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
@@ -25,6 +25,8 @@
 import android.net.Uri;
 import android.util.Size;
 
+import com.android.internal.logging.MetricsLogger;
+
 import java.util.function.Function;
 
 public class ChooserWrapperActivity extends ChooserActivity {
@@ -94,6 +96,11 @@
         return super.isImageType(mimeType);
     }
 
+    @Override
+    protected MetricsLogger getMetricsLogger() {
+        return sOverrides.metricsLogger;
+    }
+
     /**
      * We cannot directly mock the activity created since instrumentation creates it.
      * <p>
@@ -106,6 +113,7 @@
         public ResolverListController resolverListController;
         public Boolean isVoiceInteraction;
         public Bitmap previewThumbnail;
+        public MetricsLogger metricsLogger;
 
         public void reset() {
             onSafelyStartCallback = null;
@@ -113,6 +121,7 @@
             createPackageManager = null;
             previewThumbnail = null;
             resolverListController = mock(ResolverListController.class);
+            metricsLogger = mock(MetricsLogger.class);
         }
     }
 }
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 0f35918..6770ae1 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -104,16 +104,6 @@
         <permission name="android.permission.WRITE_SECURE_SETTINGS"/>
     </privapp-permissions>
 
-    <privapp-permissions package="com.android.omadm.service">
-        <permission name="android.permission.CHANGE_CONFIGURATION"/>
-        <permission name="android.permission.CONNECTIVITY_INTERNAL"/>
-        <permission name="android.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS"/>
-        <permission name="android.permission.MODIFY_PHONE_STATE"/>
-        <permission name="android.permission.READ_PRIVILEGED_PHONE_STATE"/>
-        <permission name="android.permission.WRITE_APN_SETTINGS"/>
-        <permission name="android.permission.WRITE_SECURE_SETTINGS"/>
-    </privapp-permissions>
-
     <privapp-permissions package="com.android.packageinstaller">
         <permission name="android.permission.DELETE_PACKAGES"/>
         <permission name="android.permission.INSTALL_PACKAGES"/>
diff --git a/graphics/java/android/graphics/FontFamily.java b/graphics/java/android/graphics/FontFamily.java
index 229923c..5d8ba93 100644
--- a/graphics/java/android/graphics/FontFamily.java
+++ b/graphics/java/android/graphics/FontFamily.java
@@ -36,7 +36,10 @@
  * A family of typefaces with different styles.
  *
  * @hide
+ *
+ * @deprecated Use {@link android.graphics.fonts.FontFamily} instead.
  */
+@Deprecated
 public class FontFamily {
 
     private static String TAG = "FontFamily";
@@ -51,20 +54,28 @@
 
     /**
      * @hide
+     *
+     * This cannot be deleted because it's in use by AndroidX.
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(trackingBug = 123768928)
     public long mNativePtr;
 
     // Points native font family builder. Must be zero after freezing this family.
     private long mBuilderPtr;
 
-    @UnsupportedAppUsage
+    /**
+     * This cannot be deleted because it's in use by AndroidX.
+     */
+    @UnsupportedAppUsage(trackingBug = 123768928)
     public FontFamily() {
         mBuilderPtr = nInitBuilder(null, 0);
         mNativeBuilderCleaner = sBuilderRegistry.registerNativeAllocation(this, mBuilderPtr);
     }
 
-    @UnsupportedAppUsage
+    /**
+     * This cannot be deleted because it's in use by AndroidX.
+     */
+    @UnsupportedAppUsage(trackingBug = 123768928)
     public FontFamily(@Nullable String[] langs, int variant) {
         final String langsString;
         if (langs == null || langs.length == 0) {
@@ -83,8 +94,10 @@
      *
      * @return boolean returns false if some error happens in native code, e.g. broken font file is
      *                 passed, etc.
+     *
+     * This cannot be deleted because it's in use by AndroidX.
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(trackingBug = 123768928)
     public boolean freeze() {
         if (mBuilderPtr == 0) {
             throw new IllegalStateException("This FontFamily is already frozen");
@@ -98,7 +111,10 @@
         return mNativePtr != 0;
     }
 
-    @UnsupportedAppUsage
+    /**
+     * This cannot be deleted because it's in use by AndroidX.
+     */
+    @UnsupportedAppUsage(trackingBug = 123768928)
     public void abortCreation() {
         if (mBuilderPtr == 0) {
             throw new IllegalStateException("This FontFamily is already frozen or abandoned");
@@ -107,6 +123,10 @@
         mBuilderPtr = 0;
     }
 
+    /**
+     * This cannot be deleted because it's in use by AndroidX.
+     */
+    @UnsupportedAppUsage(trackingBug = 123768928)
     public boolean addFont(String path, int ttcIndex, FontVariationAxis[] axes, int weight,
             int italic) {
         if (mBuilderPtr == 0) {
@@ -128,7 +148,10 @@
         }
     }
 
-    @UnsupportedAppUsage
+    /**
+     * This cannot be deleted because it's in use by AndroidX.
+     */
+    @UnsupportedAppUsage(trackingBug = 123768928)
     public boolean addFontFromBuffer(ByteBuffer font, int ttcIndex, FontVariationAxis[] axes,
             int weight, int italic) {
         if (mBuilderPtr == 0) {
@@ -153,8 +176,10 @@
      * @param isItalic Whether this font is italic. If the weight is set to 0, this will be resolved
      *            using the OS/2 table in the font.
      * @return
+     *
+     * This cannot be deleted because it's in use by AndroidX.
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(trackingBug = 123768928)
     public boolean addFontFromAssetManager(AssetManager mgr, String path, int cookie,
             boolean isAsset, int ttcIndex, int weight, int isItalic,
             FontVariationAxis[] axes) {
diff --git a/graphics/java/android/graphics/ImageFormat.java b/graphics/java/android/graphics/ImageFormat.java
index 0787d85..6264774 100644
--- a/graphics/java/android/graphics/ImageFormat.java
+++ b/graphics/java/android/graphics/ImageFormat.java
@@ -716,6 +716,14 @@
     public static final int PRIVATE = 0x22;
 
     /**
+     * Compressed HEIC format.
+     *
+     * <p>This format defines the HEIC brand of High Efficiency Image File
+     * Format as described in ISO/IEC 23008-12.</p>
+     */
+    public static final int HEIC = 0x48454946;
+
+    /**
      * Use this function to retrieve the number of bits per pixel of an
      * ImageFormat.
      *
@@ -796,6 +804,7 @@
             case RAW_DEPTH:
             case Y8:
             case DEPTH_JPEG:
+            case HEIC:
                 return true;
         }
 
diff --git a/telephony/java/android/telephony/ims/RcsThreadQueryParameters.aidl b/graphics/java/android/graphics/Insets.aidl
similarity index 78%
rename from telephony/java/android/telephony/ims/RcsThreadQueryParameters.aidl
rename to graphics/java/android/graphics/Insets.aidl
index feb2d4d..e65e72d 100644
--- a/telephony/java/android/telephony/ims/RcsThreadQueryParameters.aidl
+++ b/graphics/java/android/graphics/Insets.aidl
@@ -1,6 +1,6 @@
-/*
+/* //device/java/android/android/graphics/Insets.aidl
 **
-** Copyright 2018, The Android Open Source Project
+** Copyright 2019, The Android Open Source Project
 **
 ** Licensed under the Apache License, Version 2.0 (the "License");
 ** you may not use this file except in compliance with the License.
@@ -15,6 +15,6 @@
 ** limitations under the License.
 */
 
-package android.telephony.ims;
+package android.graphics;
 
-parcelable RcsThreadQueryParameters;
+parcelable Insets;
diff --git a/graphics/java/android/graphics/Insets.java b/graphics/java/android/graphics/Insets.java
index 8258b57..c64c789 100644
--- a/graphics/java/android/graphics/Insets.java
+++ b/graphics/java/android/graphics/Insets.java
@@ -18,6 +18,8 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
 
 /**
  * An Insets instance holds four integer offsets which describe changes to the four
@@ -27,7 +29,7 @@
  * Insets are immutable so may be treated as values.
  *
  */
-public final class Insets {
+public final class Insets implements Parcelable {
     public static final Insets NONE = new Insets(0, 0, 0, 0);
 
     public final int left;
@@ -73,7 +75,7 @@
     }
 
     /**
-     * Returns a Rect intance with the appropriate values.
+     * Returns a Rect instance with the appropriate values.
      *
      * @hide
      */
@@ -168,4 +170,29 @@
                 ", bottom=" + bottom +
                 '}';
     }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(left);
+        out.writeInt(top);
+        out.writeInt(right);
+        out.writeInt(bottom);
+    }
+
+    public static final Parcelable.Creator<Insets> CREATOR = new Parcelable.Creator<Insets>() {
+        @Override
+        public Insets createFromParcel(Parcel in) {
+            return new Insets(in.readInt(), in.readInt(), in.readInt(), in.readInt());
+        }
+
+        @Override
+        public Insets[] newArray(int size) {
+            return new Insets[size];
+        }
+    };
 }
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 73442db..e617c42 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -1279,7 +1279,6 @@
      * (content of the render target).
      * <p />
      * Pass null to clear any previous blend mode.
-     * As a convenience, the parameter passed is also returned.
      * <p />
      *
      * @see BlendMode
diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java
index d07088b..7c9529b 100644
--- a/graphics/java/android/graphics/Typeface.java
+++ b/graphics/java/android/graphics/Typeface.java
@@ -92,7 +92,13 @@
     /** The NORMAL style of the default monospace typeface. */
     public static final Typeface MONOSPACE;
 
-    @UnsupportedAppUsage
+    /**
+     * The default {@link Typeface}s for different text styles.
+     * Call {@link #defaultFromStyle(int)} to get the default typeface for the given text style.
+     * It shouldn't be changed for app wide typeface settings. Please use theme and font XML for
+     * the same purpose.
+     */
+    @UnsupportedAppUsage(trackingBug = 123769446)
     static Typeface[] sDefaults;
 
     /**
@@ -125,7 +131,11 @@
     static final Map<String, Typeface> sSystemFontMap;
 
     // We cannot support sSystemFallbackMap since we will migrate to public FontFamily API.
-    @UnsupportedAppUsage
+    /**
+     * @deprecated Use {@link android.graphics.fonts.FontFamily} instead.
+     */
+    @UnsupportedAppUsage(trackingBug = 123768928)
+    @Deprecated
     static final Map<String, android.graphics.FontFamily[]> sSystemFallbackMap =
             Collections.emptyMap();
 
@@ -993,7 +1003,7 @@
      * @deprecated
      */
     @Deprecated
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(trackingBug = 123768928)
     private static Typeface createFromFamilies(android.graphics.FontFamily[] families) {
         long[] ptrArray = new long[families.length];
         for (int i = 0; i < families.length; i++) {
@@ -1019,8 +1029,11 @@
 
     /**
      * This method is used by supportlib-v27.
+     *
+     * @deprecated Use {@link android.graphics.fonts.FontFamily} instead.
      */
     @UnsupportedAppUsage(trackingBug = 123768395)
+    @Deprecated
     private static Typeface createFromFamiliesWithDefault(
             android.graphics.FontFamily[] families, int weight, int italic) {
         return createFromFamiliesWithDefault(families, DEFAULT_FAMILY, weight, italic);
@@ -1038,8 +1051,11 @@
      *               the first family's font is used. If the first family has multiple fonts, the
      *               closest to the regular weight and upright font is used.
      * @param families array of font families
+     *
+     * @deprecated Use {@link android.graphics.fonts.FontFamily} instead.
      */
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(trackingBug = 123768928)
+    @Deprecated
     private static Typeface createFromFamiliesWithDefault(android.graphics.FontFamily[] families,
                 String fallbackName, int weight, int italic) {
         android.graphics.fonts.FontFamily[] fallback = SystemFonts.getSystemFallback(fallbackName);
diff --git a/graphics/java/android/graphics/drawable/ColorStateListDrawable.java b/graphics/java/android/graphics/drawable/ColorStateListDrawable.java
index c0c6a4f..5181d89 100644
--- a/graphics/java/android/graphics/drawable/ColorStateListDrawable.java
+++ b/graphics/java/android/graphics/drawable/ColorStateListDrawable.java
@@ -157,28 +157,22 @@
 
     @Override
     public void invalidateDrawable(Drawable who) {
-        final Callback callback = getCallback();
-
-        if (callback != null) {
-            callback.invalidateDrawable(who);
+        if (who == mColorDrawable && getCallback() != null) {
+            getCallback().invalidateDrawable(this);
         }
     }
 
     @Override
     public void scheduleDrawable(Drawable who, Runnable what, long when) {
-        final Callback callback = getCallback();
-
-        if (callback != null) {
-            callback.scheduleDrawable(who, what, when);
+        if (who == mColorDrawable && getCallback() != null) {
+            getCallback().scheduleDrawable(this, what, when);
         }
     }
 
     @Override
     public void unscheduleDrawable(Drawable who, Runnable what) {
-        final Callback callback = getCallback();
-
-        if (callback != null) {
-            callback.unscheduleDrawable(who, what);
+        if (who == mColorDrawable && getCallback() != null) {
+            getCallback().unscheduleDrawable(this, what);
         }
     }
 
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index 5d5e40f..eb169be 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -18,8 +18,8 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SdkConstant;
-import android.annotation.WorkerThread;
 import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.WorkerThread;
 import android.app.Activity;
 import android.app.PendingIntent;
 import android.app.Service;
@@ -29,7 +29,6 @@
 import android.content.ServiceConnection;
 import android.net.Uri;
 import android.os.Binder;
-import android.os.Build;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Process;
@@ -38,6 +37,8 @@
 import android.security.keystore.AndroidKeyStoreProvider;
 import android.security.keystore.KeyProperties;
 
+import com.android.org.conscrypt.TrustedCertificateStore;
+
 import java.io.ByteArrayInputStream;
 import java.io.Closeable;
 import java.io.Serializable;
@@ -58,8 +59,6 @@
 
 import javax.security.auth.x500.X500Principal;
 
-import com.android.org.conscrypt.TrustedCertificateStore;
-
 /**
  * The {@code KeyChain} class provides access to private keys and
  * their corresponding certificate chains in credential storage.
@@ -214,8 +213,8 @@
      *
      * @deprecated Use {@link #ACTION_KEYCHAIN_CHANGED}, {@link #ACTION_TRUST_STORE_CHANGED} or
      * {@link #ACTION_KEY_ACCESS_CHANGED}. Apps that target a version higher than
-     * {@link Build.VERSION_CODES#N_MR1} will only receive this broadcast if they register for it
-     * at runtime.
+     * {@link android.os.Build.VERSION_CODES#N_MR1} will only receive this broadcast if they
+     * register for it at runtime.
      */
     @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
     public static final String ACTION_STORAGE_CHANGED = "android.security.STORAGE_CHANGED";
@@ -532,8 +531,8 @@
     }
 
     /**
-     * Returns the {@code PrivateKey} for the requested alias, or null
-     * if there is no result.
+     * Returns the {@code PrivateKey} for the requested alias, or null if the alias does not exist
+     * or the caller has no permission to access it (see note on exceptions below).
      *
      * <p> This method may block while waiting for a connection to another process, and must never
      * be called from the main thread.
@@ -541,6 +540,15 @@
      * at any time from the main thread, it is safer to rely on a long-lived context such as one
      * returned from {@link Context#getApplicationContext()}.
      *
+     * <p> If the caller provides a valid alias to which it was not granted access, then the
+     * caller must invoke {@link #choosePrivateKeyAlias} again to get another valid alias
+     * or a grant to access the same alias.
+     * <p>On Android versions prior to Q, when a key associated with the specified alias is
+     * unavailable, the method will throw a {@code KeyChainException} rather than return null.
+     * If the exception's cause (as obtained by calling {@code KeyChainException.getCause()})
+     * is a throwable of type {@code IllegalStateException} then the caller lacks a grant
+     * to access the key and certificates associated with this alias.
+     *
      * @param alias The alias of the desired private key, typically returned via
      *              {@link KeyChainAliasCallback#alias}.
      * @throws KeyChainException if the alias was valid but there was some problem accessing it.
@@ -591,8 +599,10 @@
     }
 
     /**
-     * Returns the {@code X509Certificate} chain for the requested
-     * alias, or null if there is no result.
+     * Returns the {@code X509Certificate} chain for the requested alias, or null if the alias
+     * does not exist or the caller has no permission to access it (see note on exceptions
+     * in {@link #getPrivateKey}).
+     *
      * <p>
      * <strong>Note:</strong> If a certificate chain was explicitly specified when the alias was
      * installed, this method will return that chain. If only the client certificate was specified
@@ -604,6 +614,9 @@
      * <p> As {@link Activity} and {@link Service} contexts are short-lived and can be destroyed
      * at any time from the main thread, it is safer to rely on a long-lived context such as one
      * returned from {@link Context#getApplicationContext()}.
+     * <p> In case the caller specifies an alias for which it lacks a grant, it must call
+     * {@link #choosePrivateKeyAlias} again. See {@link #getPrivateKey} for more details on
+     * coping with this scenario.
      *
      * @param alias The alias of the desired certificate chain, typically
      * returned via {@link KeyChainAliasCallback#alias}.
diff --git a/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index 20303eb..66d8542 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -203,6 +203,27 @@
   return nullptr;
 }
 
+const std::unordered_map<std::string, std::string>*
+  AssetManager2::GetOverlayableMapForPackage(uint32_t package_id) const {
+
+  if (package_id >= package_ids_.size()) {
+    return nullptr;
+  }
+
+  const size_t idx = package_ids_[package_id];
+  if (idx == 0xff) {
+    return nullptr;
+  }
+
+  const PackageGroup& package_group = package_groups_[idx];
+  if (package_group.packages_.size() == 0) {
+    return nullptr;
+  }
+
+  const auto loaded_package = package_group.packages_[0].loaded_package_;
+  return &loaded_package->GetOverlayableMap();
+}
+
 void AssetManager2::SetConfiguration(const ResTable_config& configuration) {
   const int diff = configuration_.diff(configuration);
   configuration_ = configuration;
@@ -704,9 +725,29 @@
   return cookie;
 }
 
+const std::vector<uint32_t> AssetManager2::GetBagResIdStack(uint32_t resid) {
+  auto cached_iter = cached_bag_resid_stacks_.find(resid);
+  if (cached_iter != cached_bag_resid_stacks_.end()) {
+    return cached_iter->second;
+  } else {
+    auto found_resids = std::vector<uint32_t>();
+    GetBag(resid, found_resids);
+    // Cache style stacks if they are not already cached.
+    cached_bag_resid_stacks_[resid] = found_resids;
+    return found_resids;
+  }
+}
+
 const ResolvedBag* AssetManager2::GetBag(uint32_t resid) {
   auto found_resids = std::vector<uint32_t>();
-  return GetBag(resid, found_resids);
+  auto bag = GetBag(resid, found_resids);
+
+  // Cache style stacks if they are not already cached.
+  auto cached_iter = cached_bag_resid_stacks_.find(resid);
+  if (cached_iter == cached_bag_resid_stacks_.end()) {
+    cached_bag_resid_stacks_[resid] = found_resids;
+  }
+  return bag;
 }
 
 const ResolvedBag* AssetManager2::GetBag(uint32_t resid, std::vector<uint32_t>& child_resids) {
diff --git a/libs/androidfw/DisplayEventDispatcher.cpp b/libs/androidfw/DisplayEventDispatcher.cpp
index 7708e43..3b9a348 100644
--- a/libs/androidfw/DisplayEventDispatcher.cpp
+++ b/libs/androidfw/DisplayEventDispatcher.cpp
@@ -68,7 +68,7 @@
 
         // Drain all pending events.
         nsecs_t vsyncTimestamp;
-        int32_t vsyncDisplayId;
+        PhysicalDisplayId vsyncDisplayId;
         uint32_t vsyncCount;
         if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount)) {
             ALOGE("dispatcher %p ~ last event processed while scheduling was for %" PRId64 "",
@@ -101,10 +101,11 @@
 
     // Drain all pending events, keep the last vsync.
     nsecs_t vsyncTimestamp;
-    int32_t vsyncDisplayId;
+    PhysicalDisplayId vsyncDisplayId;
     uint32_t vsyncCount;
     if (processPendingEvents(&vsyncTimestamp, &vsyncDisplayId, &vsyncCount)) {
-        ALOGV("dispatcher %p ~ Vsync pulse: timestamp=%" PRId64 ", id=%d, count=%d",
+        ALOGV("dispatcher %p ~ Vsync pulse: timestamp=%" PRId64 ", displayId=%"
+                ANDROID_PHYSICAL_DISPLAY_ID_FORMAT ", count=%d",
                 this, ns2ms(vsyncTimestamp), vsyncDisplayId, vsyncCount);
         mWaitingForVsync = false;
         dispatchVsync(vsyncTimestamp, vsyncDisplayId, vsyncCount);
@@ -114,7 +115,7 @@
 }
 
 bool DisplayEventDispatcher::processPendingEvents(
-        nsecs_t* outTimestamp, int32_t* outId, uint32_t* outCount) {
+        nsecs_t* outTimestamp, PhysicalDisplayId* outDisplayId, uint32_t* outCount) {
     bool gotVsync = false;
     DisplayEventReceiver::Event buf[EVENT_BUFFER_SIZE];
     ssize_t n;
@@ -128,11 +129,11 @@
                 // ones. That's fine, we only care about the most recent.
                 gotVsync = true;
                 *outTimestamp = ev.header.timestamp;
-                *outId = ev.header.id;
+                *outDisplayId = ev.header.displayId;
                 *outCount = ev.vsync.count;
                 break;
             case DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG:
-                dispatchHotplug(ev.header.timestamp, ev.header.id, ev.hotplug.connected);
+                dispatchHotplug(ev.header.timestamp, ev.header.displayId, ev.hotplug.connected);
                 break;
             default:
                 ALOGW("dispatcher %p ~ ignoring unknown event type %#x", this, ev.header.type);
diff --git a/libs/androidfw/LoadedArsc.cpp b/libs/androidfw/LoadedArsc.cpp
index bdd4706..72873ab 100644
--- a/libs/androidfw/LoadedArsc.cpp
+++ b/libs/androidfw/LoadedArsc.cpp
@@ -598,6 +598,13 @@
         std::string actor;
         util::ReadUtf16StringFromDevice(header->actor, arraysize(header->actor), &actor);
 
+        if (loaded_package->overlayable_map_.find(name) !=
+            loaded_package->overlayable_map_.end()) {
+          LOG(ERROR) << "Multiple <overlayable> blocks with the same name '" << name << "'.";
+          return {};
+        }
+        loaded_package->overlayable_map_.emplace(name, actor);
+
         // Iterate over the overlayable policy chunks contained within the overlayable chunk data
         ChunkIterator overlayable_iter(child_chunk.data_ptr(), child_chunk.data_size());
         while (overlayable_iter.HasNext()) {
diff --git a/libs/androidfw/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h
index f29769b..fc5aa9c7 100644
--- a/libs/androidfw/include/androidfw/AssetManager2.h
+++ b/libs/androidfw/include/androidfw/AssetManager2.h
@@ -124,6 +124,9 @@
   // This may be nullptr if the APK represented by `cookie` has no resource table.
   const DynamicRefTable* GetDynamicRefTableForCookie(ApkAssetsCookie cookie) const;
 
+  const std::unordered_map<std::string, std::string>*
+    GetOverlayableMapForPackage(uint32_t package_id) const;
+
   // Sets/resets the configuration for this AssetManager. This will cause all
   // caches that are related to the configuration change to be invalidated.
   void SetConfiguration(const ResTable_config& configuration);
@@ -237,6 +240,8 @@
   // resource has been resolved yet.
   std::string GetLastResourceResolution() const;
 
+  const std::vector<uint32_t> GetBagResIdStack(uint32_t resid);
+
   // Retrieves the best matching bag/map resource with ID `resid`.
   // This method will resolve all parent references for this bag and merge keys with the child.
   // To iterate over the keys, use the following idiom:
@@ -355,6 +360,10 @@
   // which involves some calculation.
   std::unordered_map<uint32_t, util::unique_cptr<ResolvedBag>> cached_bags_;
 
+  // Cached set of bag resid stacks for each bag. These are cached because they might be requested
+  // a number of times for each view during View inspection.
+  std::unordered_map<uint32_t, std::vector<uint32_t>> cached_bag_resid_stacks_;
+
   // Whether or not to save resource resolution steps
   bool resource_resolution_logging_enabled_ = false;
 
diff --git a/libs/androidfw/include/androidfw/DisplayEventDispatcher.h b/libs/androidfw/include/androidfw/DisplayEventDispatcher.h
index bf35aa3..d2addba 100644
--- a/libs/androidfw/include/androidfw/DisplayEventDispatcher.h
+++ b/libs/androidfw/include/androidfw/DisplayEventDispatcher.h
@@ -37,10 +37,12 @@
     DisplayEventReceiver mReceiver;
     bool mWaitingForVsync;
 
-    virtual void dispatchVsync(nsecs_t timestamp, int32_t id, uint32_t count) = 0;
-    virtual void dispatchHotplug(nsecs_t timestamp, int32_t id, bool connected) = 0;
+    virtual void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count) = 0;
+    virtual void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId,
+                                 bool connected) = 0;
 
     virtual int handleEvent(int receiveFd, int events, void* data);
-    bool processPendingEvents(nsecs_t* outTimestamp, int32_t* id, uint32_t* outCount);
+    bool processPendingEvents(nsecs_t* outTimestamp, PhysicalDisplayId* outDisplayId,
+                              uint32_t* outCount);
 };
 }
diff --git a/libs/androidfw/include/androidfw/LoadedArsc.h b/libs/androidfw/include/androidfw/LoadedArsc.h
index b5f4006..950f541 100644
--- a/libs/androidfw/include/androidfw/LoadedArsc.h
+++ b/libs/androidfw/include/androidfw/LoadedArsc.h
@@ -20,6 +20,7 @@
 #include <memory>
 #include <set>
 #include <vector>
+#include <unordered_map>
 #include <unordered_set>
 
 #include "android-base/macros.h"
@@ -242,6 +243,10 @@
     return defines_overlayable_;
   }
 
+  const std::unordered_map<std::string, std::string>& GetOverlayableMap() const {
+    return overlayable_map_;
+  }
+
  private:
   DISALLOW_COPY_AND_ASSIGN(LoadedPackage);
 
@@ -261,6 +266,7 @@
   ByteBucketArray<uint32_t> resource_ids_;
   std::vector<DynamicPackageEntry> dynamic_package_map_;
   std::vector<const std::pair<OverlayableInfo, std::unordered_set<uint32_t>>> overlayable_infos_;
+  std::unordered_map<std::string, std::string> overlayable_map_;
 };
 
 // Read-only view into a resource table. This class validates all data
diff --git a/libs/androidfw/tests/AssetManager2_test.cpp b/libs/androidfw/tests/AssetManager2_test.cpp
index 447fdf5..40c8e46 100644
--- a/libs/androidfw/tests/AssetManager2_test.cpp
+++ b/libs/androidfw/tests/AssetManager2_test.cpp
@@ -71,6 +71,9 @@
 
     app_assets_ = ApkAssets::Load(GetTestDataPath() + "/app/app.apk");
     ASSERT_THAT(app_assets_, NotNull());
+
+    overlayable_assets_ = ApkAssets::Load(GetTestDataPath() + "/overlayable/overlayable.apk");
+    ASSERT_THAT(overlayable_assets_, NotNull());
   }
 
  protected:
@@ -83,6 +86,7 @@
   std::unique_ptr<const ApkAssets> appaslib_assets_;
   std::unique_ptr<const ApkAssets> system_assets_;
   std::unique_ptr<const ApkAssets> app_assets_;
+  std::unique_ptr<const ApkAssets> overlayable_assets_;
 };
 
 TEST_F(AssetManager2Test, FindsResourceFromSingleApkAssets) {
@@ -703,4 +707,20 @@
   EXPECT_EQ("", resultDisabled);
 }
 
+TEST_F(AssetManager2Test, GetOverlayableMap) {
+  ResTable_config desired_config;
+  memset(&desired_config, 0, sizeof(desired_config));
+
+  AssetManager2 assetmanager;
+  assetmanager.SetResourceResolutionLoggingEnabled(true);
+  assetmanager.SetConfiguration(desired_config);
+  assetmanager.SetApkAssets({overlayable_assets_.get()});
+
+  const auto map = assetmanager.GetOverlayableMapForPackage(0x7f);
+  ASSERT_NE(nullptr, map);
+  ASSERT_EQ(2, map->size());
+  ASSERT_EQ(map->at("OverlayableResources1"), "overlay://theme");
+  ASSERT_EQ(map->at("OverlayableResources2"), "overlay://com.android.overlayable");
+}
+
 }  // namespace android
diff --git a/libs/androidfw/tests/LoadedArsc_test.cpp b/libs/androidfw/tests/LoadedArsc_test.cpp
index b8d3c6b..d58e8d2 100644
--- a/libs/androidfw/tests/LoadedArsc_test.cpp
+++ b/libs/androidfw/tests/LoadedArsc_test.cpp
@@ -331,7 +331,7 @@
 
   const std::vector<std::unique_ptr<const LoadedPackage>>& packages = loaded_arsc->GetPackages();
   ASSERT_EQ(1u, packages.size());
-  EXPECT_EQ(std::string("com.android.basic"), packages[0]->GetPackageName());
+  ASSERT_EQ(std::string("com.android.basic"), packages[0]->GetPackageName());
 
   const auto& loaded_package = packages[0];
   auto iter = loaded_package->begin();
@@ -369,6 +369,24 @@
   ASSERT_EQ(end, iter);
 }
 
+TEST(LoadedArscTest, GetOverlayableMap) {
+  std::string contents;
+  ASSERT_TRUE(ReadFileFromZipToString(GetTestDataPath() + "/overlayable/overlayable.apk",
+                                      "resources.arsc", &contents));
+
+  std::unique_ptr<const LoadedArsc> loaded_arsc = LoadedArsc::Load(StringPiece(contents));
+  ASSERT_NE(nullptr, loaded_arsc);
+
+  const std::vector<std::unique_ptr<const LoadedPackage>>& packages = loaded_arsc->GetPackages();
+  ASSERT_EQ(1u, packages.size());
+  ASSERT_EQ(std::string("com.android.overlayable"), packages[0]->GetPackageName());
+
+  const auto map = packages[0]->GetOverlayableMap();
+  ASSERT_EQ(2, map.size());
+  ASSERT_EQ(map.at("OverlayableResources1"), "overlay://theme");
+  ASSERT_EQ(map.at("OverlayableResources2"), "overlay://com.android.overlayable");
+}
+
 // structs with size fields (like Res_value, ResTable_entry) should be
 // backwards and forwards compatible (aka checking the size field against
 // sizeof(Res_value) might not be backwards compatible.
diff --git a/libs/hwui/DeviceInfo.cpp b/libs/hwui/DeviceInfo.cpp
index 4c67513..cf5d7ce 100644
--- a/libs/hwui/DeviceInfo.cpp
+++ b/libs/hwui/DeviceInfo.cpp
@@ -55,9 +55,12 @@
         return sDummyDisplay;
     }
 
+    const sp<IBinder> token = SurfaceComposerClient::getInternalDisplayToken();
+    LOG_ALWAYS_FATAL_IF(token == nullptr,
+                        "Failed to get display info because internal display is disconnected");
+
     DisplayInfo displayInfo;
-    sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
-    status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &displayInfo);
+    status_t status = SurfaceComposerClient::getDisplayInfo(token, &displayInfo);
     LOG_ALWAYS_FATAL_IF(status, "Failed to get display info, error %d", status);
     return displayInfo;
 }
diff --git a/libs/hwui/Readback.cpp b/libs/hwui/Readback.cpp
index 2a48837..76c5660 100644
--- a/libs/hwui/Readback.cpp
+++ b/libs/hwui/Readback.cpp
@@ -164,14 +164,15 @@
      * with reading incorrect data from EGLImage backed SkImage (likely a driver bug).
      */
     sk_sp<SkSurface> tmpSurface = SkSurface::MakeRenderTarget(mRenderThread.getGrContext(),
-                                                              SkBudgeted::kYes, bitmap->info());
+                                                              SkBudgeted::kYes, bitmap->info(), 0,
+                                                              kTopLeft_GrSurfaceOrigin, nullptr);
 
     // if we can't generate a GPU surface that matches the destination bitmap (e.g. 565) then we
     // attempt to do the intermediate rendering step in 8888
     if (!tmpSurface.get()) {
         SkImageInfo tmpInfo = bitmap->info().makeColorType(SkColorType::kN32_SkColorType);
         tmpSurface = SkSurface::MakeRenderTarget(mRenderThread.getGrContext(), SkBudgeted::kYes,
-                                                 tmpInfo);
+                                                 tmpInfo, 0, kTopLeft_GrSurfaceOrigin, nullptr);
         if (!tmpSurface.get()) {
             ALOGW("Unable to generate GPU buffer in a format compatible with the provided bitmap");
             return false;
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 1f24f0e..3904ed2 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -329,7 +329,7 @@
 bool RenderThread::threadLoop() {
     setpriority(PRIO_PROCESS, 0, PRIORITY_DISPLAY);
     if (gOnStartHook) {
-        gOnStartHook();
+        gOnStartHook("RenderThread");
     }
     initThreadLocals();
 
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index d062dba..b182928 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -75,7 +75,7 @@
 
 class DummyVsyncSource;
 
-typedef void (*JVMAttachHook)();
+typedef void (*JVMAttachHook)(const char* name);
 
 class RenderThread : private ThreadBase {
     PREVENT_COPY_AND_ASSIGN(RenderThread);
diff --git a/libs/hwui/tests/common/TestContext.cpp b/libs/hwui/tests/common/TestContext.cpp
index 92b6cbd..0a54aca 100644
--- a/libs/hwui/tests/common/TestContext.cpp
+++ b/libs/hwui/tests/common/TestContext.cpp
@@ -37,11 +37,13 @@
         0,      // presentationDeadline
 };
 
-DisplayInfo getBuiltInDisplay() {
+DisplayInfo getInternalDisplay() {
 #if !HWUI_NULL_GPU
     DisplayInfo display;
-    sp<IBinder> dtoken(SurfaceComposerClient::getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
-    status_t status = SurfaceComposerClient::getDisplayInfo(dtoken, &display);
+    const sp<IBinder> token = SurfaceComposerClient::getInternalDisplayToken();
+    LOG_ALWAYS_FATAL_IF(token == nullptr,
+                        "Failed to get display info because internal display is disconnected\n");
+    status_t status = SurfaceComposerClient::getDisplayInfo(token, &display);
     LOG_ALWAYS_FATAL_IF(status, "Failed to get display info\n");
     return display;
 #else
diff --git a/libs/hwui/tests/common/TestContext.h b/libs/hwui/tests/common/TestContext.h
index 0996f4d..116d4de 100644
--- a/libs/hwui/tests/common/TestContext.h
+++ b/libs/hwui/tests/common/TestContext.h
@@ -36,7 +36,7 @@
 extern DisplayInfo gDisplay;
 #define dp(x) ((x)*android::uirenderer::test::gDisplay.density)
 
-DisplayInfo getBuiltInDisplay();
+DisplayInfo getInternalDisplay();
 
 class TestContext {
 public:
diff --git a/libs/hwui/tests/macrobench/TestSceneRunner.cpp b/libs/hwui/tests/macrobench/TestSceneRunner.cpp
index 5fa008b..0e61899e 100644
--- a/libs/hwui/tests/macrobench/TestSceneRunner.cpp
+++ b/libs/hwui/tests/macrobench/TestSceneRunner.cpp
@@ -109,7 +109,7 @@
 void run(const TestScene::Info& info, const TestScene::Options& opts,
          benchmark::BenchmarkReporter* reporter) {
     // Switch to the real display
-    gDisplay = getBuiltInDisplay();
+    gDisplay = getInternalDisplay();
 
     Properties::forceDrawFrame = true;
     TestContext testContext;
diff --git a/libs/hwui/thread/TaskManager.cpp b/libs/hwui/thread/TaskManager.cpp
index 6493d49..de10ff1 100644
--- a/libs/hwui/thread/TaskManager.cpp
+++ b/libs/hwui/thread/TaskManager.cpp
@@ -87,7 +87,7 @@
     setpriority(PRIO_PROCESS, 0, PRIORITY_FOREGROUND);
     auto onStartHook = renderthread::RenderThread::getOnStartHook();
     if (onStartHook) {
-        onStartHook();
+        onStartHook(mName.c_str());
     }
 
     return NO_ERROR;
diff --git a/libs/incident/Android.bp b/libs/incident/Android.bp
index 0619a9c..905e303 100644
--- a/libs/incident/Android.bp
+++ b/libs/incident/Android.bp
@@ -36,7 +36,6 @@
 
     srcs: [
         ":libincident_aidl",
-        "proto/android/os/header.proto",
         "proto/android/os/metadata.proto",
         "src/IncidentReportArgs.cpp",
     ],
@@ -47,4 +46,4 @@
     },
 
     export_include_dirs: ["include"],
-}
+}
\ No newline at end of file
diff --git a/libs/incident/include/android/os/IncidentReportArgs.h b/libs/incident/include/android/os/IncidentReportArgs.h
index ee1e33c..5e8eac1 100644
--- a/libs/incident/include/android/os/IncidentReportArgs.h
+++ b/libs/incident/include/android/os/IncidentReportArgs.h
@@ -24,8 +24,6 @@
 #include <set>
 #include <vector>
 
-#include "frameworks/base/libs/incident/proto/android/os/header.pb.h"
-
 namespace android {
 namespace os {
 
@@ -49,7 +47,7 @@
     void setAll(bool all);
     void setDest(int dest);
     void addSection(int section);
-    void addHeader(const IncidentHeaderProto& headerProto);
+    void addHeader(const vector<uint8_t>& headerProto);
 
     inline bool all() const { return mAll; }
     bool containsSection(int section) const;
diff --git a/libs/incident/src/IncidentReportArgs.cpp b/libs/incident/src/IncidentReportArgs.cpp
index 26261ef..06b7a5b 100644
--- a/libs/incident/src/IncidentReportArgs.cpp
+++ b/libs/incident/src/IncidentReportArgs.cpp
@@ -161,15 +161,9 @@
 }
 
 void
-IncidentReportArgs::addHeader(const IncidentHeaderProto& headerProto)
+IncidentReportArgs::addHeader(const vector<uint8_t>& headerProto)
 {
-    vector<uint8_t> header;
-    auto serialized = headerProto.SerializeAsString();
-    if (serialized.empty()) return;
-    for (auto it = serialized.begin(); it != serialized.end(); it++) {
-        header.push_back((uint8_t)*it);
-    }
-    mHeaders.push_back(header);
+    mHeaders.push_back(headerProto);
 }
 
 bool
diff --git a/location/java/android/location/GnssMeasurement.java b/location/java/android/location/GnssMeasurement.java
index 602cc3e..59eff64 100644
--- a/location/java/android/location/GnssMeasurement.java
+++ b/location/java/android/location/GnssMeasurement.java
@@ -17,6 +17,7 @@
 package android.location;
 
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.annotation.TestApi;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -49,6 +50,7 @@
     private double mSnrInDb;
     private double mAutomaticGainControlLevelInDb;
     private int mCodeType;
+    private String mOtherCodeTypeName;
 
     // The following enumerations must be in sync with the values declared in gps.h
 
@@ -209,8 +211,8 @@
      */
     @IntDef(prefix = { "CODE_TYPE_" }, value = {
             CODE_TYPE_UNKNOWN, CODE_TYPE_A, CODE_TYPE_B, CODE_TYPE_C, CODE_TYPE_I, CODE_TYPE_L,
-            CODE_TYPE_M, CODE_TYPE_P, CODE_TYPE_Q, CODE_TYPE_S, CODE_TYPE_W, CODE_TYPE_X,
-            CODE_TYPE_Y, CODE_TYPE_Z, CODE_TYPE_CODELESS
+            CODE_TYPE_M, CODE_TYPE_N, CODE_TYPE_P, CODE_TYPE_Q, CODE_TYPE_S, CODE_TYPE_W,
+            CODE_TYPE_X, CODE_TYPE_Y, CODE_TYPE_Z, CODE_TYPE_OTHER
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface CodeType {}
@@ -299,7 +301,16 @@
     /**
      * The GNSS Measurement's code type is one of the following: GPS L1 codeless, GPS L2 codeless.
      */
-    public static final int CODE_TYPE_CODELESS = 13;
+    public static final int CODE_TYPE_N = 13;
+
+    /**
+     * Other code type that does not belong to any of the above code types.
+     *
+     * This code type is used in the case that the code type being tracked in this measurement, as
+     * classified by RINEX standards, does not fit into one of the existing enumerated values. When
+     * this code type is set, the field otherCodeTypeName must specify the new code type.
+     */
+    public static final int CODE_TYPE_OTHER = 255;
 
     /**
      * All the 'Accumulated Delta Range' flags.
@@ -349,6 +360,7 @@
         mSnrInDb = measurement.mSnrInDb;
         mAutomaticGainControlLevelInDb = measurement.mAutomaticGainControlLevelInDb;
         mCodeType = measurement.mCodeType;
+        mOtherCodeTypeName = measurement.mOtherCodeTypeName;
     }
 
     /**
@@ -1175,8 +1187,8 @@
     /**
      * Gets the GNSS measurement's code type.
      *
-     * <p>Similar to the Attribute field described in Rinex 3.03, e.g., in Tables 4-10, and Table
-     * A2 at the Rinex 3.03 Update 1 Document.
+     * <p>Similar to the Attribute field described in RINEX 3.03, e.g., in Tables 4-10, and Table
+     * A2 at the RINEX 3.03 Update 1 Document.
      */
     @CodeType
     public int getCodeType() {
@@ -1206,6 +1218,29 @@
     }
 
     /**
+     * Gets the GNSS measurement's code type name when the code type is {@link #CODE_TYPE_OTHER}.
+     *
+     * <p>This is used to specify the observation descriptor defined in GNSS Observation Data File
+     * Header Section Description in the RINEX standard (Version 3.XX), in cases where the code type
+     * does not align with an existing Android enumerated value. For example, if a code type "G" is
+     * added, this string shall be set to "G".
+     */
+    @NonNull
+    public String getOtherCodeTypeName() {
+        return mOtherCodeTypeName;
+    }
+
+    /**
+     * Sets the GNSS measurement's code type name when the code type is {@link #CODE_TYPE_OTHER}.
+     *
+     * @hide
+     */
+    @TestApi
+    public void setOtherCodeTypeName(@NonNull String otherCodeTypeName) {
+        mOtherCodeTypeName = otherCodeTypeName;
+    }
+
+    /**
      * Gets a string representation of the 'code type'.
      *
      * <p>For internal and logging use only.
@@ -1226,6 +1261,8 @@
                 return "CODE_TYPE_L";
             case CODE_TYPE_M:
                 return "CODE_TYPE_M";
+            case CODE_TYPE_N:
+                return "CODE_TYPE_N";
             case CODE_TYPE_P:
                 return "CODE_TYPE_P";
             case CODE_TYPE_Q:
@@ -1240,8 +1277,8 @@
                 return "CODE_TYPE_Y";
             case CODE_TYPE_Z:
                 return "CODE_TYPE_Z";
-            case CODE_TYPE_CODELESS:
-                return "CODE_TYPE_CODELESS";
+            case CODE_TYPE_OTHER:
+                return "CODE_TYPE_OTHER";
             default:
                 return "<Invalid: " + mCodeType + ">";
         }
@@ -1273,6 +1310,7 @@
             gnssMeasurement.mSnrInDb = parcel.readDouble();
             gnssMeasurement.mAutomaticGainControlLevelInDb = parcel.readDouble();
             gnssMeasurement.mCodeType = parcel.readInt();
+            gnssMeasurement.mOtherCodeTypeName = parcel.readString();
 
             return gnssMeasurement;
         }
@@ -1306,6 +1344,7 @@
         parcel.writeDouble(mSnrInDb);
         parcel.writeDouble(mAutomaticGainControlLevelInDb);
         parcel.writeInt(mCodeType);
+        parcel.writeString(mOtherCodeTypeName);
     }
 
     @Override
@@ -1384,6 +1423,9 @@
                 format,
                 "CodeType",
                 hasCodeType() ? getCodeTypeString() : null));
+        builder.append(String.format(
+                format,
+                "OtherCodeTypeName", mOtherCodeTypeName));
 
         return builder.toString();
     }
@@ -1409,6 +1451,7 @@
         resetSnrInDb();
         resetAutomaticGainControlLevel();
         resetCodeType();
+        setOtherCodeTypeName("");
     }
 
     private void setFlag(int flag) {
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index b9088d4..31d2232 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -31,6 +31,8 @@
 import android.util.Log;
 import android.util.Pair;
 
+import com.android.internal.util.ArrayUtils;
+
 import libcore.io.IoUtils;
 import libcore.io.Streams;
 
@@ -395,6 +397,12 @@
      * http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/PanasonicRaw.html
      */
     public static final String TAG_RW2_JPG_FROM_RAW = "JpgFromRaw";
+    /**
+     * Type is byte[]. See <a href=
+     * "https://en.wikipedia.org/wiki/Extensible_Metadata_Platform">Extensible
+     * Metadata Platform (XMP)</a> for details on contents.
+     */
+    public static final String TAG_XMP = "Xmp";
 
     /**
      * Private tags used for pointing the other IFD offsets.
@@ -1012,7 +1020,8 @@
             new ExifTag(TAG_RW2_SENSOR_BOTTOM_BORDER, 6, IFD_FORMAT_ULONG),
             new ExifTag(TAG_RW2_SENSOR_RIGHT_BORDER, 7, IFD_FORMAT_ULONG),
             new ExifTag(TAG_RW2_ISO, 23, IFD_FORMAT_USHORT),
-            new ExifTag(TAG_RW2_JPG_FROM_RAW, 46, IFD_FORMAT_UNDEFINED)
+            new ExifTag(TAG_RW2_JPG_FROM_RAW, 46, IFD_FORMAT_UNDEFINED),
+            new ExifTag(TAG_XMP, 700, IFD_FORMAT_BYTE),
     };
 
     // Primary image IFD Exif Private tags (See JEITA CP-3451C Section 4.6.8 Tag Support Levels)
@@ -1243,6 +1252,8 @@
     private static final Charset ASCII = Charset.forName("US-ASCII");
     // Identifier for EXIF APP1 segment in JPEG
     private static final byte[] IDENTIFIER_EXIF_APP1 = "Exif\0\0".getBytes(ASCII);
+    // Identifier for XMP APP1 segment in JPEG
+    private static final byte[] IDENTIFIER_XMP_APP1 = "http://ns.adobe.com/xap/1.0/\0".getBytes(ASCII);
     // JPEG segment markers, that each marker consumes two bytes beginning with 0xff and ending with
     // the indicator. There is no SOF4, SOF8, SOF16 markers in JPEG and SOFx markers indicates start
     // of frame(baseline DCT) and the image size info exists in its beginning part.
@@ -2046,6 +2057,22 @@
     }
 
     /**
+     * Returns the raw bytes for the value of the requested tag inside the image
+     * file, or {@code null} if the tag is not contained.
+     *
+     * @return raw bytes for the value of the requested tag, or {@code null} if
+     *         no tag was found.
+     */
+    public @Nullable byte[] getAttributeBytes(@NonNull String tag) {
+        final ExifAttribute attribute = getExifAttribute(tag);
+        if (attribute != null) {
+            return attribute.bytes;
+        } else {
+            return null;
+        }
+    }
+
+    /**
      * Stores the latitude and longitude value in a float array. The first element is
      * the latitude, and the second element is the longitude. Returns false if the
      * Exif tags are not available.
@@ -2432,40 +2459,32 @@
             }
             switch (marker) {
                 case MARKER_APP1: {
-                    if (DEBUG) {
-                        Log.d(TAG, "MARKER_APP1");
-                    }
-                    if (length < 6) {
-                        // Skip if it's not an EXIF APP1 segment.
-                        break;
-                    }
-                    byte[] identifier = new byte[6];
-                    if (in.read(identifier) != 6) {
-                        throw new IOException("Invalid exif");
-                    }
-                    bytesRead += 6;
-                    length -= 6;
-                    if (!Arrays.equals(identifier, IDENTIFIER_EXIF_APP1)) {
-                        // Skip if it's not an EXIF APP1 segment.
-                        break;
-                    }
-                    if (length <= 0) {
-                        throw new IOException("Invalid exif");
-                    }
-                    if (DEBUG) {
-                        Log.d(TAG, "readExifSegment with a byte array (length: " + length + ")");
-                    }
-                    // Save offset values for createJpegThumbnailBitmap() function
-                    mExifOffset = bytesRead;
-
-                    byte[] bytes = new byte[length];
-                    if (in.read(bytes) != length) {
-                        throw new IOException("Invalid exif");
-                    }
+                    final int start = bytesRead;
+                    final byte[] bytes = new byte[length];
+                    in.readFully(bytes);
                     bytesRead += length;
                     length = 0;
 
-                    readExifSegment(bytes, imageType);
+                    if (ArrayUtils.startsWith(bytes, IDENTIFIER_EXIF_APP1)) {
+                        final long offset = start + IDENTIFIER_EXIF_APP1.length;
+                        final byte[] value = Arrays.copyOfRange(bytes,
+                                IDENTIFIER_EXIF_APP1.length, bytes.length);
+
+                        readExifSegment(value, imageType);
+
+                        // Save offset values for createJpegThumbnailBitmap() function
+                        mExifOffset = (int) offset;
+                    } else if (ArrayUtils.startsWith(bytes, IDENTIFIER_XMP_APP1)) {
+                        // See XMP Specification Part 3: Storage in Files, 1.1.3 JPEG, Table 6
+                        final long offset = start + IDENTIFIER_XMP_APP1.length;
+                        final byte[] value = Arrays.copyOfRange(bytes,
+                                IDENTIFIER_XMP_APP1.length, bytes.length);
+
+                        if (getAttribute(TAG_XMP) == null) {
+                            mAttributes[IFD_TYPE_PRIMARY].put(TAG_XMP, new ExifAttribute(
+                                    IFD_FORMAT_BYTE, value.length, offset, value));
+                        }
+                    }
                     break;
                 }
 
diff --git a/media/java/android/media/Image.java b/media/java/android/media/Image.java
index 26b9b8c..70a343f 100644
--- a/media/java/android/media/Image.java
+++ b/media/java/android/media/Image.java
@@ -155,6 +155,13 @@
      *   UnSupportedOperationException being thrown.
      *   </td>
      * </tr>
+     * <tr>
+     *   <td>{@link android.graphics.ImageFormat#HEIC HEIC}</td>
+     *   <td>1</td>
+     *   <td>Compressed data, so row and pixel strides are 0. To uncompress, use
+     *      {@link android.graphics.BitmapFactory#decodeByteArray BitmapFactory#decodeByteArray}.
+     *   </td>
+     * </tr>
      * </table>
      *
      * @see android.graphics.ImageFormat
diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java
index 60ef1d9..6116429 100644
--- a/media/java/android/media/ImageReader.java
+++ b/media/java/android/media/ImageReader.java
@@ -821,6 +821,7 @@
                 case ImageFormat.DEPTH_POINT_CLOUD:
                 case ImageFormat.RAW_PRIVATE:
                 case ImageFormat.DEPTH_JPEG:
+                case ImageFormat.HEIC:
                     width = ImageReader.this.getWidth();
                     break;
                 default:
@@ -838,6 +839,7 @@
                 case ImageFormat.DEPTH_POINT_CLOUD:
                 case ImageFormat.RAW_PRIVATE:
                 case ImageFormat.DEPTH_JPEG:
+                case ImageFormat.HEIC:
                     height = ImageReader.this.getHeight();
                     break;
                 default:
diff --git a/media/java/android/media/ImageUtils.java b/media/java/android/media/ImageUtils.java
index b77a884..d8a0bb3 100644
--- a/media/java/android/media/ImageUtils.java
+++ b/media/java/android/media/ImageUtils.java
@@ -36,8 +36,8 @@
      * {@link android.graphics.PixelFormat PixelFormat} are supported by
      * ImageReader. When reading RGB data from a surface, the formats defined in
      * {@link android.graphics.PixelFormat PixelFormat} can be used; when
-     * reading YUV, JPEG or raw sensor data (for example, from the camera or video
-     * decoder), formats from {@link android.graphics.ImageFormat ImageFormat}
+     * reading YUV, JPEG, HEIC or raw sensor data (for example, from the camera
+     * or video decoder), formats from {@link android.graphics.ImageFormat ImageFormat}
      * are used.
      */
     public static int getNumPlanesForFormat(int format) {
@@ -64,6 +64,7 @@
             case ImageFormat.DEPTH_POINT_CLOUD:
             case ImageFormat.RAW_DEPTH:
             case ImageFormat.DEPTH_JPEG:
+            case ImageFormat.HEIC:
                 return 1;
             case ImageFormat.PRIVATE:
                 return 0;
@@ -194,6 +195,7 @@
             case ImageFormat.JPEG:
             case ImageFormat.DEPTH_POINT_CLOUD:
             case ImageFormat.DEPTH_JPEG:
+            case ImageFormat.HEIC:
                 estimatedBytePerPixel = 0.3;
                 break;
             case ImageFormat.Y8:
@@ -262,6 +264,7 @@
             case ImageFormat.RAW10:
             case ImageFormat.RAW12:
             case ImageFormat.RAW_DEPTH:
+            case ImageFormat.HEIC:
                 return new Size(image.getWidth(), image.getHeight());
             case ImageFormat.PRIVATE:
                 return new Size(0, 0);
diff --git a/media/java/android/media/MediaCodecInfo.java b/media/java/android/media/MediaCodecInfo.java
index 751d57b..4bc3897 100644
--- a/media/java/android/media/MediaCodecInfo.java
+++ b/media/java/android/media/MediaCodecInfo.java
@@ -1614,29 +1614,59 @@
         }
 
         /**
-         * Video performance points are a set of standard performance points defined by pixel rate.
+         * Video performance points are a set of standard performance points defined by number of
+         * pixels, pixel rate and frame rate. Performance point represents an upper bound. This
+         * means that it covers all performance points with fewer pixels, pixel rate and frame
+         * rate.
          */
         public static final class PerformancePoint {
             /**
-             * Frame width in pixels.
+             * (Maximum) number of macroblocks in the frame.
+             *
+             * Video frames are conceptually divided into 16-by-16 pixel blocks called macroblocks.
+             * Most coding standards operate on these 16-by-16 pixel blocks; thus, codec performance
+             * is characterized using such blocks.
              */
-            public final int width;
+            public final int macroBlocks;
 
             /**
-             * Frame height in pixels.
-             */
-            public final int height;
-
-            /**
-             * Frame rate in frames per second.
+             * (Maximum) frame rate in frames per second.
              */
             public final int frameRate;
 
+            /**
+             * (Maximum) number of macroblocks processed per second.
+             */
+            public final long macroBlockRate;
+
             /* package private */
-            PerformancePoint(int width_, int height_, int frameRate_) {
-                width = width_;
-                height = height_;
-                frameRate = frameRate_;
+            PerformancePoint(int width_, int height_, int frameRate_, int maxFrameRate_) {
+                macroBlocks = saturateLongToInt(
+                        ((Math.max(1, (long)width_) + 15) / 16)
+                                * ((Math.max(1, (long)height_) + 15) / 16));
+                frameRate = Math.max(1, frameRate_);
+                macroBlockRate = Math.max(maxFrameRate_, frameRate) * macroBlocks;
+            }
+
+            /**
+             * Create a performance point for a given frame size and frame rate.
+             *
+             * @param width_ width of the frame in pixels
+             * @param height_ height of the frame in pixels
+             * @param frameRate_ frame rate in frames per second
+             */
+            public PerformancePoint(int width_, int height_, int frameRate_) {
+                this(width_, height_, frameRate_, frameRate_ /* maxFrameRate */);
+            }
+
+            private int saturateLongToInt(long value) {
+                if (value < Integer.MIN_VALUE) {
+                    return Integer.MIN_VALUE;
+                } else if (value > Integer.MAX_VALUE) {
+                    return Integer.MAX_VALUE;
+                } else {
+                    return (int)value;
+                }
             }
 
             /**
@@ -1647,26 +1677,40 @@
              * @return {@code true} if the performance point covers the format.
              */
             public boolean covers(@NonNull MediaFormat format) {
-                // for simplicity, this code assumes a 16x16 block size.
-                long macroBlocks = ((width + 15) / 16) * (long)((height + 15) / 16);
-                long mbps = macroBlocks * frameRate;
-
-                long formatMacroBlocks =
-                    (long)((format.getInteger(MediaFormat.KEY_WIDTH, 0) + 15) / 16)
-                            * ((format.getInteger(MediaFormat.KEY_HEIGHT, 0) + 15) / 16);
-                double formatMbps =
-                    Math.ceil(formatMacroBlocks
-                              * format.getNumber(MediaFormat.KEY_FRAME_RATE, 0).doubleValue());
-                return formatMacroBlocks > 0 && formatMacroBlocks <= macroBlocks
-                        && formatMbps <= mbps;
+                PerformancePoint other = new PerformancePoint(
+                        format.getInteger(MediaFormat.KEY_WIDTH, 0),
+                        format.getInteger(MediaFormat.KEY_HEIGHT, 0),
+                        // safely convert ceil(double) to int through float case and Math.round
+                        Math.round((float)(
+                                Math.ceil(format.getNumber(MediaFormat.KEY_FRAME_RATE, 0)
+                                        .doubleValue()))));
+                return covers(other);
             }
 
+            /**
+             * Checks whether the performance point covers another performance point. Use this
+             * method to determine if a performance point advertised by a codec covers the
+             * performance point required. This method can also be used for lose ordering as this
+             * method is transitive.
+             *
+             * @param other other performance point considered
+             *
+             * @return {@code true} if the performance point covers the other.
+             */
+            public boolean covers(@NonNull PerformancePoint other) {
+                return (macroBlocks >= other.macroBlocks
+                        && frameRate >= other.frameRate
+                        && macroBlockRate >= other.macroBlockRate);
+            }
+
+
             @Override
             public boolean equals(Object o) {
                 if (o instanceof PerformancePoint) {
                     PerformancePoint other = (PerformancePoint)o;
-                    return ((long)width * height) == ((long)other.width * other.height)
-                            && frameRate == other.frameRate;
+                    return (macroBlocks == other.macroBlocks
+                            && frameRate == other.frameRate
+                            && macroBlockRate == other.macroBlockRate);
                 }
                 return false;
             }
@@ -1931,7 +1975,8 @@
                     continue;
                 }
                 ret.add(new PerformancePoint(
-                        size.getWidth(), size.getHeight(), range.getLower().intValue()));
+                        size.getWidth(), size.getHeight(), range.getLower().intValue(),
+                        range.getUpper().intValue()));
             }
             // check if the component specified no performance point indication
             if (ret.size() == 0) {
@@ -1939,9 +1984,12 @@
             }
 
             // sort reversed by area first, then by frame rate
-            ret.sort((a, b) -> (a.width * a.height != b.width * b.height ?
-                                    (b.width * b.height - a.width * a.height) :
-                                    (b.frameRate - a.frameRate)));
+            ret.sort((a, b) -> -((a.macroBlocks != b.macroBlocks) ?
+                                        (a.macroBlocks < b.macroBlocks ? -1 : 1) :
+                                (a.macroBlockRate != b.macroBlockRate) ?
+                                        (a.macroBlockRate < b.macroBlockRate ? -1 : 1) :
+                                (a.frameRate != b.frameRate) ?
+                                        (a.frameRate < b.frameRate ? -1 : 1) : 0));
             return ret;
         }
 
@@ -2363,39 +2411,45 @@
                     boolean supported = true;
                     switch (profileLevel.level) {
                         case CodecProfileLevel.AVCLevel1:
-                            MBPS =    1485; FS =    99; BR =     64; DPB =    396; break;
+                            MBPS =     1485; FS =     99; BR =     64; DPB =    396; break;
                         case CodecProfileLevel.AVCLevel1b:
-                            MBPS =    1485; FS =    99; BR =    128; DPB =    396; break;
+                            MBPS =     1485; FS =     99; BR =    128; DPB =    396; break;
                         case CodecProfileLevel.AVCLevel11:
-                            MBPS =    3000; FS =   396; BR =    192; DPB =    900; break;
+                            MBPS =     3000; FS =    396; BR =    192; DPB =    900; break;
                         case CodecProfileLevel.AVCLevel12:
-                            MBPS =    6000; FS =   396; BR =    384; DPB =   2376; break;
+                            MBPS =     6000; FS =    396; BR =    384; DPB =   2376; break;
                         case CodecProfileLevel.AVCLevel13:
-                            MBPS =   11880; FS =   396; BR =    768; DPB =   2376; break;
+                            MBPS =    11880; FS =    396; BR =    768; DPB =   2376; break;
                         case CodecProfileLevel.AVCLevel2:
-                            MBPS =   11880; FS =   396; BR =   2000; DPB =   2376; break;
+                            MBPS =    11880; FS =    396; BR =   2000; DPB =   2376; break;
                         case CodecProfileLevel.AVCLevel21:
-                            MBPS =   19800; FS =   792; BR =   4000; DPB =   4752; break;
+                            MBPS =    19800; FS =    792; BR =   4000; DPB =   4752; break;
                         case CodecProfileLevel.AVCLevel22:
-                            MBPS =   20250; FS =  1620; BR =   4000; DPB =   8100; break;
+                            MBPS =    20250; FS =   1620; BR =   4000; DPB =   8100; break;
                         case CodecProfileLevel.AVCLevel3:
-                            MBPS =   40500; FS =  1620; BR =  10000; DPB =   8100; break;
+                            MBPS =    40500; FS =   1620; BR =  10000; DPB =   8100; break;
                         case CodecProfileLevel.AVCLevel31:
-                            MBPS =  108000; FS =  3600; BR =  14000; DPB =  18000; break;
+                            MBPS =   108000; FS =   3600; BR =  14000; DPB =  18000; break;
                         case CodecProfileLevel.AVCLevel32:
-                            MBPS =  216000; FS =  5120; BR =  20000; DPB =  20480; break;
+                            MBPS =   216000; FS =   5120; BR =  20000; DPB =  20480; break;
                         case CodecProfileLevel.AVCLevel4:
-                            MBPS =  245760; FS =  8192; BR =  20000; DPB =  32768; break;
+                            MBPS =   245760; FS =   8192; BR =  20000; DPB =  32768; break;
                         case CodecProfileLevel.AVCLevel41:
-                            MBPS =  245760; FS =  8192; BR =  50000; DPB =  32768; break;
+                            MBPS =   245760; FS =   8192; BR =  50000; DPB =  32768; break;
                         case CodecProfileLevel.AVCLevel42:
-                            MBPS =  522240; FS =  8704; BR =  50000; DPB =  34816; break;
+                            MBPS =   522240; FS =   8704; BR =  50000; DPB =  34816; break;
                         case CodecProfileLevel.AVCLevel5:
-                            MBPS =  589824; FS = 22080; BR = 135000; DPB = 110400; break;
+                            MBPS =   589824; FS =  22080; BR = 135000; DPB = 110400; break;
                         case CodecProfileLevel.AVCLevel51:
-                            MBPS =  983040; FS = 36864; BR = 240000; DPB = 184320; break;
+                            MBPS =   983040; FS =  36864; BR = 240000; DPB = 184320; break;
                         case CodecProfileLevel.AVCLevel52:
-                            MBPS = 2073600; FS = 36864; BR = 240000; DPB = 184320; break;
+                            MBPS =  2073600; FS =  36864; BR = 240000; DPB = 184320; break;
+                        case CodecProfileLevel.AVCLevel6:
+                            MBPS =  4177920; FS = 139264; BR = 240000; DPB = 696320; break;
+                        case CodecProfileLevel.AVCLevel61:
+                            MBPS =  8355840; FS = 139264; BR = 480000; DPB = 696320; break;
+                        case CodecProfileLevel.AVCLevel62:
+                            MBPS = 16711680; FS = 139264; BR = 800000; DPB = 696320; break;
                         default:
                             Log.w(TAG, "Unrecognized level "
                                     + profileLevel.level + " for " + mime);
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index a76cf1f..12e02e7 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -1520,6 +1520,7 @@
      * Create a copy of a media format object.
      */
     public MediaFormat(@NonNull MediaFormat other) {
+        this();
         mMap.putAll(other.mMap);
     }
 
diff --git a/media/java/android/media/audiopolicy/AudioMix.java b/media/java/android/media/audiopolicy/AudioMix.java
index 1c6210e..761b625 100644
--- a/media/java/android/media/audiopolicy/AudioMix.java
+++ b/media/java/android/media/audiopolicy/AudioMix.java
@@ -353,11 +353,6 @@
                 // no route flags set, use default as described in Builder.setRouteFlags(int)
                 mRouteFlags = ROUTE_FLAG_LOOP_BACK;
             }
-            // can't do loop back AND render at same time in this implementation
-            if (mRouteFlags == (ROUTE_FLAG_RENDER | ROUTE_FLAG_LOOP_BACK)) {
-                throw new IllegalArgumentException("Unsupported route behavior combination 0x" +
-                        Integer.toHexString(mRouteFlags));
-            }
             if (mFormat == null) {
                 // FIXME Can we eliminate this?  Will AudioMix work with an unspecified sample rate?
                 int rate = AudioSystem.getPrimaryOutputSamplingRate();
@@ -377,11 +372,11 @@
                     throw new IllegalArgumentException("Unsupported device on non-playback mix");
                 }
             } else {
-                if ((mRouteFlags & ROUTE_FLAG_RENDER) == ROUTE_FLAG_RENDER) {
+                if ((mRouteFlags & ROUTE_FLAG_SUPPORTED) == ROUTE_FLAG_RENDER) {
                     throw new IllegalArgumentException(
                             "Can't have flag ROUTE_FLAG_RENDER without an audio device");
                 }
-                if ((mRouteFlags & ROUTE_FLAG_SUPPORTED) == ROUTE_FLAG_LOOP_BACK) {
+                if ((mRouteFlags & ROUTE_FLAG_LOOP_BACK) == ROUTE_FLAG_LOOP_BACK) {
                     if (mRule.getTargetMixType() == MIX_TYPE_PLAYERS) {
                         mDeviceSystemType = AudioSystem.DEVICE_OUT_REMOTE_SUBMIX;
                     } else if (mRule.getTargetMixType() == MIX_TYPE_RECORDERS) {
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 406f9dd..f07f1e8 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -153,8 +153,12 @@
 
     if (nameIsType) {
         mCodec = MediaCodec::CreateByType(mLooper, name, encoder, &mInitStatus);
+        if (mCodec == nullptr || mCodec->getName(&mNameAtCreation) != OK) {
+            mNameAtCreation = "(null)";
+        }
     } else {
         mCodec = MediaCodec::CreateByComponentName(mLooper, name, &mInitStatus);
+        mNameAtCreation = name;
     }
     CHECK((mCodec != NULL) != (mInitStatus != OK));
 }
@@ -699,9 +703,8 @@
         return err;
     }
 
-    // TODO: get alias
     ScopedLocalRef<jstring> nameObject(env,
-            env->NewStringUTF(codecInfo->getCodecName()));
+            env->NewStringUTF(mNameAtCreation.c_str()));
 
     ScopedLocalRef<jstring> canonicalNameObject(env,
             env->NewStringUTF(codecInfo->getCodecName()));
diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h
index 0a53f1a..de08550 100644
--- a/media/jni/android_media_MediaCodec.h
+++ b/media/jni/android_media_MediaCodec.h
@@ -155,6 +155,7 @@
 
     sp<ALooper> mLooper;
     sp<MediaCodec> mCodec;
+    AString mNameAtCreation;
 
     sp<AMessage> mCallbackNotification;
     sp<AMessage> mOnFrameRenderedNotification;
diff --git a/media/jni/android_media_MediaCodecList.cpp b/media/jni/android_media_MediaCodecList.cpp
index cf14942..6b8f745 100644
--- a/media/jni/android_media_MediaCodecList.cpp
+++ b/media/jni/android_media_MediaCodecList.cpp
@@ -24,6 +24,10 @@
 #include <media/IMediaCodecList.h>
 #include <media/MediaCodecInfo.h>
 
+#include <utils/Vector.h>
+
+#include <vector>
+
 #include "android_runtime/AndroidRuntime.h"
 #include "jni.h"
 #include <nativehelper/JNIHelp.h>
@@ -31,25 +35,91 @@
 
 using namespace android;
 
-static sp<IMediaCodecList> getCodecList(JNIEnv *env) {
-    sp<IMediaCodecList> mcl = MediaCodecList::getInstance();
-    if (mcl == NULL) {
-        // This should never happen unless something is really wrong
-        jniThrowException(
-                    env, "java/lang/RuntimeException", "cannot get MediaCodecList");
+/**
+ * This object unwraps codec aliases into individual codec infos as the Java interface handles
+ * aliases in this way.
+ */
+class JavaMediaCodecListWrapper {
+public:
+    struct Info {
+        sp<MediaCodecInfo> info;
+        AString alias;
+    };
+
+    const Info getCodecInfo(size_t index) const {
+        if (index < mInfoList.size()) {
+            return mInfoList[index];
+        }
+        // return
+        return Info { nullptr /* info */, "(none)" /* alias */ };
     }
-    return mcl;
+
+    size_t countCodecs() const {
+        return mInfoList.size();
+    }
+
+    sp<IMediaCodecList> getCodecList() const {
+        return mCodecList;
+    }
+
+    size_t findCodecByName(AString name) const {
+        auto it = mInfoIndex.find(name);
+        return it == mInfoIndex.end() ? -ENOENT : it->second;
+    }
+
+    JavaMediaCodecListWrapper(sp<IMediaCodecList> mcl)
+            : mCodecList(mcl) {
+        size_t numCodecs = mcl->countCodecs();
+        for (size_t ix = 0; ix < numCodecs; ++ix) {
+            sp<MediaCodecInfo> info = mcl->getCodecInfo(ix);
+            Vector<AString> namesAndAliases;
+            info->getAliases(&namesAndAliases);
+            namesAndAliases.insertAt(0);
+            namesAndAliases.editItemAt(0) = info->getCodecName();
+            for (const AString &nameOrAlias : namesAndAliases) {
+                if (mInfoIndex.count(nameOrAlias) > 0) {
+                    // skip duplicate names or aliases
+                    continue;
+                }
+                mInfoIndex.emplace(nameOrAlias, mInfoList.size());
+                mInfoList.emplace_back(Info { info, nameOrAlias });
+            }
+        }
+    }
+
+private:
+    sp<IMediaCodecList> mCodecList;
+    std::vector<Info> mInfoList;
+    std::map<AString, size_t> mInfoIndex;
+};
+
+static std::mutex sMutex;
+static std::unique_ptr<JavaMediaCodecListWrapper> sListWrapper;
+
+static const JavaMediaCodecListWrapper *getCodecList(JNIEnv *env) {
+    std::lock_guard<std::mutex> lock(sMutex);
+    if (sListWrapper == nullptr) {
+        sp<IMediaCodecList> mcl = MediaCodecList::getInstance();
+        if (mcl == NULL) {
+            // This should never happen unless something is really wrong
+            jniThrowException(
+                        env, "java/lang/RuntimeException", "cannot get MediaCodecList");
+        }
+
+        sListWrapper.reset(new JavaMediaCodecListWrapper(mcl));
+    }
+    return sListWrapper.get();
 }
 
-static sp<MediaCodecInfo> getCodecInfo(JNIEnv *env, jint index) {
-    sp<IMediaCodecList> mcl = getCodecList(env);
-    if (mcl == NULL) {
+static JavaMediaCodecListWrapper::Info getCodecInfo(JNIEnv *env, jint index) {
+    const JavaMediaCodecListWrapper *mcl = getCodecList(env);
+    if (mcl == nullptr) {
         // Runtime exception already pending.
-        return NULL;
+        return JavaMediaCodecListWrapper::Info { nullptr /* info */, "(none)" /* alias */ };
     }
 
-    sp<MediaCodecInfo> info = mcl->getCodecInfo(index);
-    if (info == NULL) {
+    JavaMediaCodecListWrapper::Info info = mcl->getCodecInfo(index);
+    if (info.info == NULL) {
         jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
     }
 
@@ -58,36 +128,36 @@
 
 static jint android_media_MediaCodecList_getCodecCount(
         JNIEnv *env, jobject /* thiz */) {
-    sp<IMediaCodecList> mcl = getCodecList(env);
+    const JavaMediaCodecListWrapper *mcl = getCodecList(env);
     if (mcl == NULL) {
         // Runtime exception already pending.
         return 0;
     }
+
     return mcl->countCodecs();
 }
 
 static jstring android_media_MediaCodecList_getCodecName(
         JNIEnv *env, jobject /* thiz */, jint index) {
-    sp<MediaCodecInfo> info = getCodecInfo(env, index);
-    if (info == NULL) {
+    JavaMediaCodecListWrapper::Info info = getCodecInfo(env, index);
+    if (info.info == NULL) {
         // Runtime exception already pending.
         return NULL;
     }
 
-    // TODO: support aliases
-    const char *name = info->getCodecName();
+    const char *name = info.alias.c_str();
     return env->NewStringUTF(name);
 }
 
 static jstring android_media_MediaCodecList_getCanonicalName(
         JNIEnv *env, jobject /* thiz */, jint index) {
-    sp<MediaCodecInfo> info = getCodecInfo(env, index);
-    if (info == NULL) {
+    JavaMediaCodecListWrapper::Info info = getCodecInfo(env, index);
+    if (info.info == NULL) {
         // Runtime exception already pending.
         return NULL;
     }
 
-    const char *name = info->getCodecName();
+    const char *name = info.info->getCodecName();
     return env->NewStringUTF(name);
 }
 
@@ -104,7 +174,7 @@
         return -ENOENT;
     }
 
-    sp<IMediaCodecList> mcl = getCodecList(env);
+    const JavaMediaCodecListWrapper *mcl = getCodecList(env);
     if (mcl == NULL) {
         // Runtime exception already pending.
         env->ReleaseStringUTFChars(name, nameStr);
@@ -118,25 +188,25 @@
 
 static jboolean android_media_MediaCodecList_getAttributes(
         JNIEnv *env, jobject /* thiz */, jint index) {
-    sp<MediaCodecInfo> info = getCodecInfo(env, index);
-    if (info == NULL) {
+    JavaMediaCodecListWrapper::Info info = getCodecInfo(env, index);
+    if (info.info == NULL) {
         // Runtime exception already pending.
         return 0;
     }
 
-    return info->getAttributes();
+    return info.info->getAttributes();
 }
 
 static jarray android_media_MediaCodecList_getSupportedTypes(
         JNIEnv *env, jobject /* thiz */, jint index) {
-    sp<MediaCodecInfo> info = getCodecInfo(env, index);
-    if (info == NULL) {
+    JavaMediaCodecListWrapper::Info info = getCodecInfo(env, index);
+    if (info.info == NULL) {
         // Runtime exception already pending.
         return NULL;
     }
 
     Vector<AString> types;
-    info->getSupportedMediaTypes(&types);
+    info.info->getSupportedMediaTypes(&types);
 
     jclass clazz = env->FindClass("java/lang/String");
     CHECK(clazz != NULL);
@@ -160,8 +230,8 @@
         return NULL;
     }
 
-    sp<MediaCodecInfo> info = getCodecInfo(env, index);
-    if (info == NULL) {
+    JavaMediaCodecListWrapper::Info info = getCodecInfo(env, index);
+    if (info.info == NULL) {
         // Runtime exception already pending.
         return NULL;
     }
@@ -181,7 +251,7 @@
 
     // TODO query default-format also from codec/codec list
     const sp<MediaCodecInfo::Capabilities> &capabilities =
-        info->getCapabilitiesFor(typeStr);
+        info.info->getCapabilitiesFor(typeStr);
     env->ReleaseStringUTFChars(type, typeStr);
     typeStr = NULL;
     if (capabilities == NULL) {
@@ -192,7 +262,7 @@
     capabilities->getSupportedColorFormats(&colorFormats);
     capabilities->getSupportedProfileLevels(&profileLevels);
     sp<AMessage> details = capabilities->getDetails();
-    bool isEncoder = info->isEncoder();
+    bool isEncoder = info.info->isEncoder();
 
     jobject defaultFormatObj = NULL;
     if (ConvertMessageToMap(env, defaultFormat, &defaultFormatObj)) {
@@ -267,13 +337,13 @@
 }
 
 static jobject android_media_MediaCodecList_getGlobalSettings(JNIEnv *env, jobject /* thiz */) {
-    sp<IMediaCodecList> mcl = getCodecList(env);
+    const JavaMediaCodecListWrapper *mcl = getCodecList(env);
     if (mcl == NULL) {
         // Runtime exception already pending.
         return NULL;
     }
 
-    const sp<AMessage> settings = mcl->getGlobalSettings();
+    const sp<AMessage> settings = mcl->getCodecList()->getGlobalSettings();
     if (settings == NULL) {
         jniThrowException(env, "java/lang/RuntimeException", "cannot get global settings");
         return NULL;
diff --git a/media/jni/android_media_Utils.cpp b/media/jni/android_media_Utils.cpp
index 458d847..01baadb 100644
--- a/media/jni/android_media_Utils.cpp
+++ b/media/jni/android_media_Utils.cpp
@@ -29,6 +29,9 @@
 
 #define ALIGN(x, mask) ( ((x) + (mask) - 1) & ~((mask) - 1) )
 
+// Must be in sync with the value in HeicCompositeStream.cpp
+#define CAMERA3_HEIC_BLOB_ID 0x00FE
+
 namespace android {
 
 AssetStream::AssetStream(SkStream* stream)
@@ -609,34 +612,35 @@
     }
 }
 
-uint32_t Image_getJpegSize(LockedImage* buffer, bool usingRGBAOverride) {
+uint32_t Image_getBlobSize(LockedImage* buffer, bool usingRGBAOverride) {
     ALOGV("%s", __FUNCTION__);
     LOG_ALWAYS_FATAL_IF(buffer == NULL, "Input buffer is NULL!!!");
     uint32_t size = 0;
     uint32_t width = buffer->width;
-    uint8_t* jpegBuffer = buffer->data;
+    uint8_t* blobBuffer = buffer->data;
 
     if (usingRGBAOverride) {
         width = (buffer->width + buffer->stride * (buffer->height - 1)) * 4;
     }
 
-    // First check for JPEG transport header at the end of the buffer
-    uint8_t* header = jpegBuffer + (width - sizeof(struct camera3_jpeg_blob));
+    // First check for BLOB transport header at the end of the buffer
+    uint8_t* header = blobBuffer + (width - sizeof(struct camera3_jpeg_blob));
     struct camera3_jpeg_blob *blob = (struct camera3_jpeg_blob*)(header);
-    if (blob->jpeg_blob_id == CAMERA3_JPEG_BLOB_ID) {
+    if (blob->jpeg_blob_id == CAMERA3_JPEG_BLOB_ID ||
+            blob->jpeg_blob_id == CAMERA3_HEIC_BLOB_ID) {
         size = blob->jpeg_size;
-        ALOGV("%s: Jpeg size = %d", __FUNCTION__, size);
+        ALOGV("%s: Jpeg/Heic size = %d", __FUNCTION__, size);
     }
 
     // failed to find size, default to whole buffer
     if (size == 0) {
         /*
-         * This is a problem because not including the JPEG header
-         * means that in certain rare situations a regular JPEG blob
+         * This is a problem because not including the JPEG/BLOB header
+         * means that in certain rare situations a regular JPEG/HEIC blob
          * will be mis-identified as having a header, in which case
          * we will get a garbage size value.
          */
-        ALOGW("%s: No JPEG header detected, defaulting to size=width=%d",
+        ALOGW("%s: No JPEG/HEIC header detected, defaulting to size=width=%d",
                 __FUNCTION__, width);
         size = width;
     }
@@ -760,7 +764,7 @@
 
 
             pData = buffer->data;
-            dataSize = Image_getJpegSize(buffer, usingRGBAOverride);
+            dataSize = Image_getBlobSize(buffer, usingRGBAOverride);
             pStride = 0;
             rStride = 0;
             break;
diff --git a/media/jni/android_media_Utils.h b/media/jni/android_media_Utils.h
index 821c6b2..19c1b88 100644
--- a/media/jni/android_media_Utils.h
+++ b/media/jni/android_media_Utils.h
@@ -119,7 +119,7 @@
 
 int32_t applyFormatOverrides(int32_t imageFormat, int32_t containerFormat);
 
-uint32_t Image_getJpegSize(LockedImage* buffer, bool usingRGBAOverride);
+uint32_t Image_getBlobSize(LockedImage* buffer, bool usingRGBAOverride);
 
 bool isFormatOpaque(int format);
 
diff --git a/native/android/choreographer.cpp b/native/android/choreographer.cpp
index c3629da..2db575b 100644
--- a/native/android/choreographer.cpp
+++ b/native/android/choreographer.cpp
@@ -24,6 +24,7 @@
 #include <android/choreographer.h>
 #include <androidfw/DisplayEventDispatcher.h>
 #include <gui/ISurfaceComposer.h>
+#include <gui/SurfaceComposerClient.h>
 #include <utils/Looper.h>
 #include <utils/Mutex.h>
 #include <utils/Timers.h>
@@ -67,8 +68,8 @@
     explicit Choreographer(const sp<Looper>& looper);
     Choreographer(const Choreographer&) = delete;
 
-    virtual void dispatchVsync(nsecs_t timestamp, int32_t id, uint32_t count);
-    virtual void dispatchHotplug(nsecs_t timestamp, int32_t id, bool connected);
+    void dispatchVsync(nsecs_t timestamp, PhysicalDisplayId displayId, uint32_t count) override;
+    void dispatchHotplug(nsecs_t timestamp, PhysicalDisplayId displayId, bool connected) override;
 
     void scheduleCallbacks();
 
@@ -139,13 +140,10 @@
     }
 }
 
-
-void Choreographer::dispatchVsync(nsecs_t timestamp, int32_t id, uint32_t) {
-    if (id != ISurfaceComposer::eDisplayIdMain) {
-        ALOGV("choreographer %p ~ ignoring vsync signal for non-main display (id=%d)", this, id);
-        scheduleVsync();
-        return;
-    }
+// TODO(b/74619554): The PhysicalDisplayId is ignored because SF only emits VSYNC events for the
+// internal display and DisplayEventReceiver::requestNextVsync only allows requesting VSYNC for
+// the internal display implicitly.
+void Choreographer::dispatchVsync(nsecs_t timestamp, PhysicalDisplayId, uint32_t) {
     std::vector<FrameCallback> callbacks{};
     {
         AutoMutex _l{mLock};
@@ -160,9 +158,10 @@
     }
 }
 
-void Choreographer::dispatchHotplug(nsecs_t, int32_t id, bool connected) {
-    ALOGV("choreographer %p ~ received hotplug event (id=%" PRId32 ", connected=%s), ignoring.",
-            this, id, toString(connected));
+void Choreographer::dispatchHotplug(nsecs_t, PhysicalDisplayId displayId, bool connected) {
+    ALOGV("choreographer %p ~ received hotplug event (displayId=%"
+            ANDROID_PHYSICAL_DISPLAY_ID_FORMAT ", connected=%s), ignoring.",
+            this, displayId, toString(connected));
 }
 
 void Choreographer::handleMessage(const Message& message) {
diff --git a/native/android/surface_control.cpp b/native/android/surface_control.cpp
index 416ef42..7d2934b 100644
--- a/native/android/surface_control.cpp
+++ b/native/android/surface_control.cpp
@@ -46,7 +46,13 @@
 
 static bool getWideColorSupport(const sp<SurfaceControl>& surfaceControl) {
     sp<SurfaceComposerClient> client = surfaceControl->getClient();
-    sp<IBinder> display(client->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+
+    const sp<IBinder> display = client->getInternalDisplayToken();
+    if (display == nullptr) {
+        ALOGE("unable to get wide color support for disconnected internal display");
+        return false;
+    }
+
     bool isWideColorDisplay = false;
     status_t err = client->isWideColorDisplay(display, &isWideColorDisplay);
     if (err) {
@@ -58,7 +64,12 @@
 
 static bool getHdrSupport(const sp<SurfaceControl>& surfaceControl) {
     sp<SurfaceComposerClient> client = surfaceControl->getClient();
-    sp<IBinder> display(client->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
+
+    const sp<IBinder> display = client->getInternalDisplayToken();
+    if (display == nullptr) {
+        ALOGE("unable to get hdr capabilities for disconnected internal display");
+        return false;
+    }
 
     HdrCapabilities hdrCapabilities;
     status_t err = client->getHdrCapabilities(display, &hdrCapabilities);
diff --git a/packages/CaptivePortalLogin/res/values-gl/strings.xml b/packages/CaptivePortalLogin/res/values-gl/strings.xml
index f6f4aea..6419516 100644
--- a/packages/CaptivePortalLogin/res/values-gl/strings.xml
+++ b/packages/CaptivePortalLogin/res/values-gl/strings.xml
@@ -13,7 +13,7 @@
     <string name="ssl_error_mismatch" msgid="3060364165934822383">"O nome do sitio non coincide co nome que aparece no certificado."</string>
     <string name="ssl_error_expired" msgid="1501588340716182495">"Este certificado caducou."</string>
     <string name="ssl_error_not_yet_valid" msgid="8648649030525886924">"Este certificado aínda non é válido."</string>
-    <string name="ssl_error_date_invalid" msgid="88425990680059223">"Este certificado ten unha data non-válida."</string>
+    <string name="ssl_error_date_invalid" msgid="88425990680059223">"Este certificado ten unha data non válida."</string>
     <string name="ssl_error_invalid" msgid="2540546515565633432">"Este certificado non é válido."</string>
     <string name="ssl_error_unknown" msgid="4405203446079465859">"Produciuse un erro descoñecido relacionado co certificado."</string>
     <string name="ssl_security_warning_title" msgid="8768539813847504404">"Advertencia de seguranza"</string>
diff --git a/packages/CarSystemUI/res/values/colors_car.xml b/packages/CarSystemUI/res/values/colors_car.xml
index 2f720f5..08e16cd 100644
--- a/packages/CarSystemUI/res/values/colors_car.xml
+++ b/packages/CarSystemUI/res/values/colors_car.xml
@@ -26,6 +26,4 @@
     <color name="car_user_switcher_add_user_background_color">@color/car_dark_blue_grey_600</color>
     <color name="car_user_switcher_add_user_add_sign_color">@color/car_body1_light</color>
 
-    <!-- colors for volume dialog tint -->
-    <color name="car_volume_dialog_tint">@color/car_tint</color>
 </resources>
diff --git a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
index 85dab57..10a0ae5 100644
--- a/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
+++ b/packages/CarSystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
@@ -554,8 +554,7 @@
                 // Adding the items which are not coming from the default item.
                 VolumeItem volumeItem = mAvailableVolumeItems.get(groupId);
                 if (volumeItem.defaultItem) {
-                    // Set progress here due to the progress of seekbar may not be updated.
-                    volumeItem.listItem.setProgress(volumeItem.progress);
+                    updateDefaultVolumeItem(volumeItem.listItem);
                 } else {
                     addSeekbarListItem(volumeItem, groupId, 0, null);
                 }
@@ -572,8 +571,7 @@
                 if (!volumeItem.defaultItem) {
                     itr.remove();
                 } else {
-                    // Set progress here due to the progress of seekbar may not be updated.
-                    seekbarListItem.setProgress(volumeItem.progress);
+                    updateDefaultVolumeItem(seekbarListItem);
                 }
             }
             inAnimator = AnimatorInflater.loadAnimator(
@@ -595,6 +593,21 @@
         mPagedListAdapter.notifyDataSetChanged();
     }
 
+    private void updateDefaultVolumeItem(SeekbarListItem seekbarListItem){
+        VolumeItem volumeItem = findVolumeItem(seekbarListItem);
+
+        // When volume dialog is expanded or collapsed the default list item is never
+        // reset. Whereas all other list items are removed when the dialog is collapsed and then
+        // added when the dialog is expanded using {@link CarVolumeDialogImpl#addSeekbarListItem}.
+        // This sets the progressbar and the tint color of icons for all items other than default
+        // if they were changed. For default list item it should be done manually here.
+        int color = mContext.getResources().getColor(R.color.car_volume_dialog_tint);
+        Drawable primaryIcon = mContext.getResources().getDrawable(volumeItem.icon);
+        primaryIcon.mutate().setTint(color);
+        volumeItem.listItem.setPrimaryActionIcon(primaryIcon);
+        volumeItem.listItem.setProgress(volumeItem.progress);
+    }
+
     private final class VolumeSeekBarChangeListener implements OnSeekBarChangeListener {
 
         private final int mVolumeGroupId;
diff --git a/packages/ExtServices/src/android/ext/services/notification/Assistant.java b/packages/ExtServices/src/android/ext/services/notification/Assistant.java
index b6b229c..c5e598d 100644
--- a/packages/ExtServices/src/android/ext/services/notification/Assistant.java
+++ b/packages/ExtServices/src/android/ext/services/notification/Assistant.java
@@ -230,6 +230,10 @@
         NotificationEntry entry =
                 new NotificationEntry(mPackageManager, sbn, channel, mSmsHelper);
         SmartActionsHelper.SmartSuggestions suggestions = mSmartActionsHelper.suggest(entry);
+        if (DEBUG) {
+            Log.d(TAG, String.format("Creating Adjustment for %s, with %d actions, and %d replies.",
+                    sbn.getKey(), suggestions.actions.size(), suggestions.replies.size()));
+        }
         return createEnqueuedNotificationAdjustment(
                 entry, suggestions.actions, suggestions.replies);
     }
diff --git a/packages/ExtServices/src/android/ext/services/notification/NotificationCategorizer.java b/packages/ExtServices/src/android/ext/services/notification/NotificationCategorizer.java
index 7ba0f7a..f95891c 100644
--- a/packages/ExtServices/src/android/ext/services/notification/NotificationCategorizer.java
+++ b/packages/ExtServices/src/android/ext/services/notification/NotificationCategorizer.java
@@ -15,6 +15,7 @@
  */
 package android.ext.services.notification;
 
+import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
 import static android.app.NotificationManager.IMPORTANCE_HIGH;
 import static android.app.NotificationManager.IMPORTANCE_MIN;
 
@@ -91,7 +92,7 @@
         }
         // TODO: is from signature app
         if (entry.getSbn().getUid() < Process.FIRST_APPLICATION_UID) {
-            if (entry.getImportance() >= IMPORTANCE_HIGH) {
+            if (entry.getImportance() >= IMPORTANCE_DEFAULT) {
                 return CATEGORY_SYSTEM;
             } else {
                 return CATEGORY_SYSTEM_LOW;
diff --git a/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java b/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java
index c2fdf1e..f372fe5 100644
--- a/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java
+++ b/packages/ExtServices/src/android/ext/services/notification/SmartActionsHelper.java
@@ -21,6 +21,7 @@
 import android.app.Person;
 import android.app.RemoteAction;
 import android.content.Context;
+import android.graphics.drawable.Icon;
 import android.os.Bundle;
 import android.os.Parcelable;
 import android.os.Process;
@@ -237,8 +238,11 @@
 
     private Notification.Action createNotificationAction(
             RemoteAction remoteAction, String actionType) {
+        Icon icon = remoteAction.shouldShowIcon()
+                ? remoteAction.getIcon()
+                : Icon.createWithResource(mContext, com.android.internal.R.drawable.ic_action_open);
         return new Notification.Action.Builder(
-                remoteAction.getIcon(),
+                icon,
                 remoteAction.getTitle(),
                 remoteAction.getActionIntent())
                 .setContextual(true)
diff --git a/packages/ExtServices/tests/src/android/ext/services/notification/NotificationCategorizerTest.java b/packages/ExtServices/tests/src/android/ext/services/notification/NotificationCategorizerTest.java
index c59885e..05af6e7 100644
--- a/packages/ExtServices/tests/src/android/ext/services/notification/NotificationCategorizerTest.java
+++ b/packages/ExtServices/tests/src/android/ext/services/notification/NotificationCategorizerTest.java
@@ -18,6 +18,7 @@
 
 import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
 import static android.app.NotificationManager.IMPORTANCE_HIGH;
+import static android.app.NotificationManager.IMPORTANCE_LOW;
 import static android.app.NotificationManager.IMPORTANCE_MIN;
 import static android.os.Process.FIRST_APPLICATION_UID;
 
@@ -172,23 +173,23 @@
     public void testSystemCategory() {
         NotificationCategorizer nc = new NotificationCategorizer();
 
-        when(mEntry.getChannel()).thenReturn(new NotificationChannel("", "", IMPORTANCE_HIGH));
-        when(mEntry.getImportance()).thenReturn(IMPORTANCE_HIGH);
+        when(mEntry.getChannel()).thenReturn(new NotificationChannel("", "", IMPORTANCE_DEFAULT));
+        when(mEntry.getImportance()).thenReturn(IMPORTANCE_DEFAULT);
         when(mSbn.getUid()).thenReturn(FIRST_APPLICATION_UID - 1);
 
         assertEquals(NotificationCategorizer.CATEGORY_SYSTEM, nc.getCategory(mEntry));
         assertFalse(nc.shouldSilence(NotificationCategorizer.CATEGORY_SYSTEM));
 
         when(mSbn.getUid()).thenReturn(FIRST_APPLICATION_UID);
-        assertEquals(NotificationCategorizer.CATEGORY_HIGH, nc.getCategory(mEntry));
+        assertEquals(NotificationCategorizer.CATEGORY_EVERYTHING_ELSE, nc.getCategory(mEntry));
     }
 
     @Test
     public void testSystemLowCategory() {
         NotificationCategorizer nc = new NotificationCategorizer();
 
-        when(mEntry.getChannel()).thenReturn(new NotificationChannel("", "", IMPORTANCE_DEFAULT));
-        when(mEntry.getImportance()).thenReturn(IMPORTANCE_DEFAULT);
+        when(mEntry.getChannel()).thenReturn(new NotificationChannel("", "", IMPORTANCE_LOW));
+        when(mEntry.getImportance()).thenReturn(IMPORTANCE_LOW);
         when(mSbn.getUid()).thenReturn(FIRST_APPLICATION_UID - 1);
 
         assertEquals(NotificationCategorizer.CATEGORY_SYSTEM_LOW, nc.getCategory(mEntry));
diff --git a/packages/NetworkStack/src/android/net/apf/ApfFilter.java b/packages/NetworkStack/src/android/net/apf/ApfFilter.java
index 4fa7d64..923f162 100644
--- a/packages/NetworkStack/src/android/net/apf/ApfFilter.java
+++ b/packages/NetworkStack/src/android/net/apf/ApfFilter.java
@@ -23,6 +23,7 @@
 import static android.system.OsConstants.ETH_P_IP;
 import static android.system.OsConstants.ETH_P_IPV6;
 import static android.system.OsConstants.IPPROTO_ICMPV6;
+import static android.system.OsConstants.IPPROTO_TCP;
 import static android.system.OsConstants.IPPROTO_UDP;
 import static android.system.OsConstants.SOCK_RAW;
 
@@ -38,6 +39,7 @@
 import android.content.IntentFilter;
 import android.net.LinkAddress;
 import android.net.LinkProperties;
+import android.net.TcpKeepalivePacketDataParcelable;
 import android.net.apf.ApfGenerator.IllegalInstructionException;
 import android.net.apf.ApfGenerator.Register;
 import android.net.ip.IpClient.IpClientCallbacksWrapper;
@@ -55,6 +57,7 @@
 import android.text.format.DateUtils;
 import android.util.Log;
 import android.util.Pair;
+import android.util.SparseArray;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
@@ -149,7 +152,9 @@
         DROPPED_IPV6_NON_ICMP_MULTICAST,
         DROPPED_802_3_FRAME,
         DROPPED_ETHERTYPE_BLACKLISTED,
-        DROPPED_ARP_REPLY_SPA_NO_HOST;
+        DROPPED_ARP_REPLY_SPA_NO_HOST,
+        DROPPED_IPV4_KEEPALIVE_ACK,
+        DROPPED_IPV6_KEEPALIVE_ACK;
 
         // Returns the negative byte offset from the end of the APF data segment for
         // a given counter.
@@ -285,6 +290,7 @@
     private static final int IPV4_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 16;
     private static final int IPV4_ANY_HOST_ADDRESS = 0;
     private static final int IPV4_BROADCAST_ADDRESS = -1; // 255.255.255.255
+    private static final int IPV4_HEADER_LEN = 20; // Without options
 
     // Traffic class and Flow label are not byte aligned. Luckily we
     // don't care about either value so we'll consider bytes 1-3 of the
@@ -305,6 +311,8 @@
     private static final int UDP_DESTINATION_PORT_OFFSET = ETH_HEADER_LEN + 2;
     private static final int UDP_HEADER_LEN = 8;
 
+    private static final int TCP_HEADER_SIZE_OFFSET = 12;
+
     private static final int DHCP_CLIENT_PORT = 68;
     // NOTE: this must be added to the IPv4 header length in IPV4_HEADER_SIZE_MEMORY_SLOT
     private static final int DHCP_CLIENT_MAC_OFFSET = ETH_HEADER_LEN + UDP_HEADER_LEN + 28;
@@ -788,7 +796,7 @@
 
         boolean isExpired() {
             // TODO: We may want to handle 0 lifetime RAs differently, if they are common. We'll
-            // have to calculte the filter lifetime specially as a fraction of 0 is still 0.
+            // have to calculate the filter lifetime specially as a fraction of 0 is still 0.
             return currentLifetime() <= 0;
         }
 
@@ -847,11 +855,147 @@
         }
     }
 
+    // A class to hold keepalive ack information.
+    private abstract static class TcpKeepaliveAck {
+        // Note that the offset starts from IP header.
+        // These must be added ether header length when generating program.
+        static final int IP_HEADER_OFFSET = 0;
+
+        protected static class TcpKeepaliveAckData {
+            public final byte[] srcAddress;
+            public final int srcPort;
+            public final byte[] dstAddress;
+            public final int dstPort;
+            public final int seq;
+            public final int ack;
+            // Create the characteristics of the ack packet from the sent keepalive packet.
+            TcpKeepaliveAckData(final TcpKeepalivePacketDataParcelable sentKeepalivePacket) {
+                srcAddress = sentKeepalivePacket.dstAddress;
+                srcPort = sentKeepalivePacket.dstPort;
+                dstAddress = sentKeepalivePacket.srcAddress;
+                dstPort = sentKeepalivePacket.srcPort;
+                seq = sentKeepalivePacket.ack;
+                ack = sentKeepalivePacket.seq + 1;
+            }
+        }
+
+        protected final TcpKeepaliveAckData mPacket;
+        protected final byte[] mSrcDstAddr;
+
+        TcpKeepaliveAck(final TcpKeepaliveAckData packet, final byte[] srcDstAddr) {
+            mPacket = packet;
+            mSrcDstAddr = srcDstAddr;
+        }
+
+        static byte[] concatArrays(final byte[]... arr) {
+            int size = 0;
+            for (byte[] a : arr) {
+                size += a.length;
+            }
+            final byte[] result = new byte[size];
+            int offset = 0;
+            for (byte[] a : arr) {
+                System.arraycopy(a, 0, result, offset, a.length);
+                offset += a.length;
+            }
+            return result;
+        }
+
+        public String toString() {
+            return String.format("%s(%d) -> %s(%d), seq=%d, ack=%d",
+                    mPacket.srcAddress,
+                    mPacket.srcPort,
+                    mPacket.dstAddress,
+                    mPacket.dstPort,
+                    mPacket.seq,
+                    mPacket.ack);
+        }
+
+        // Append a filter for this keepalive ack to {@code gen}.
+        // Jump to drop if it matches the keepalive ack.
+        // Jump to the next filter if packet doesn't match the keepalive ack.
+        abstract void generateFilterLocked(ApfGenerator gen) throws IllegalInstructionException;
+    }
+
+    private class TcpKeepaliveAckV4 extends TcpKeepaliveAck {
+        private static final int IPV4_SRC_ADDR_OFFSET = IP_HEADER_OFFSET + 12;
+        private static final int IPV4_TCP_SRC_PORT_OFFSET = 0;
+        private static final int IPV4_TCP_DST_PORT_OFFSET = 2;
+        private static final int IPV4_TCP_SEQ_OFFSET = 4;
+        private static final int IPV4_TCP_ACK_OFFSET = 8;
+
+        TcpKeepaliveAckV4(final TcpKeepalivePacketDataParcelable sentKeepalivePacket) {
+            this(new TcpKeepaliveAckData(sentKeepalivePacket));
+        }
+        TcpKeepaliveAckV4(final TcpKeepaliveAckData packet) {
+            super(packet, concatArrays(packet.srcAddress, packet.dstAddress) /* srcDstAddr */);
+        }
+
+        @Override
+        void generateFilterLocked(ApfGenerator gen) throws IllegalInstructionException {
+            final String nextFilterLabel = "keepalive_ack" + getUniqueNumberLocked();
+            gen.addLoad8(Register.R0, IPV4_PROTOCOL_OFFSET);
+            gen.addJumpIfR0NotEquals(IPPROTO_TCP, nextFilterLabel);
+            gen.addLoadImmediate(Register.R0, ETH_HEADER_LEN + IPV4_SRC_ADDR_OFFSET);
+            gen.addJumpIfBytesNotEqual(Register.R0, mSrcDstAddr, nextFilterLabel);
+
+            // Pass the packet if it's not zero-sized :
+            // Load the IP header size into R1
+            gen.addLoadFromMemory(Register.R1, gen.IPV4_HEADER_SIZE_MEMORY_SLOT);
+            // Load the TCP header size into R0 (it's indexed by R1)
+            gen.addLoad8Indexed(Register.R0, ETH_HEADER_LEN + TCP_HEADER_SIZE_OFFSET);
+            // Size offset is in the top nibble, but it must be multiplied by 4, and the two
+            // top bits of the low nibble are guaranteed to be zeroes. Right-shift R0 by 2.
+            gen.addRightShift(2);
+            // R0 += R1 -> R0 contains TCP + IP headers lenght
+            gen.addAddR1();
+            // Add the Ethernet header length to R0.
+            gen.addLoadImmediate(Register.R1, ETH_HEADER_LEN);
+            gen.addAddR1();
+            // Compare total length of headers to the size of the packet.
+            gen.addLoadFromMemory(Register.R1, gen.PACKET_SIZE_MEMORY_SLOT);
+            gen.addNeg(Register.R0);
+            gen.addAddR1();
+            gen.addJumpIfR0NotEquals(0, nextFilterLabel);
+
+            // Add IPv4 header length
+            gen.addLoadFromMemory(Register.R1, gen.IPV4_HEADER_SIZE_MEMORY_SLOT);
+            gen.addLoad16Indexed(Register.R0, ETH_HEADER_LEN + IPV4_TCP_SRC_PORT_OFFSET);
+            gen.addJumpIfR0NotEquals(mPacket.srcPort, nextFilterLabel);
+            gen.addLoad16Indexed(Register.R0, ETH_HEADER_LEN + IPV4_TCP_DST_PORT_OFFSET);
+            gen.addJumpIfR0NotEquals(mPacket.dstPort, nextFilterLabel);
+            gen.addLoad32Indexed(Register.R0, ETH_HEADER_LEN + IPV4_TCP_SEQ_OFFSET);
+            gen.addJumpIfR0NotEquals(mPacket.seq, nextFilterLabel);
+            gen.addLoad32Indexed(Register.R0, ETH_HEADER_LEN + IPV4_TCP_ACK_OFFSET);
+            gen.addJumpIfR0NotEquals(mPacket.ack, nextFilterLabel);
+
+            maybeSetupCounter(gen, Counter.DROPPED_IPV4_KEEPALIVE_ACK);
+            gen.addJump(mCountAndDropLabel);
+            gen.defineLabel(nextFilterLabel);
+        }
+    }
+
+    private class TcpKeepaliveAckV6 extends TcpKeepaliveAck {
+        TcpKeepaliveAckV6(final TcpKeepalivePacketDataParcelable sentKeepalivePacket) {
+            this(new TcpKeepaliveAckData(sentKeepalivePacket));
+        }
+        TcpKeepaliveAckV6(final TcpKeepaliveAckData packet) {
+            super(packet, concatArrays(packet.srcAddress, packet.dstAddress) /* srcDstAddr */);
+        }
+
+        @Override
+        void generateFilterLocked(ApfGenerator gen) throws IllegalInstructionException {
+            throw new UnsupportedOperationException("IPv6 Keepalive is not supported yet");
+        }
+    }
+
     // Maximum number of RAs to filter for.
     private static final int MAX_RAS = 10;
 
     @GuardedBy("this")
-    private ArrayList<Ra> mRas = new ArrayList<Ra>();
+    private ArrayList<Ra> mRas = new ArrayList<>();
+    @GuardedBy("this")
+    private SparseArray<TcpKeepaliveAck> mKeepaliveAcks = new SparseArray<>();
 
     // There is always some marginal benefit to updating the installed APF program when an RA is
     // seen because we can extend the program's lifetime slightly, but there is some cost to
@@ -980,6 +1124,8 @@
         //     drop
         //   if it's IPv4 broadcast:
         //     drop
+        // if keepalive ack
+        //   drop
         // pass
 
         if (mMulticastFilter) {
@@ -1023,6 +1169,9 @@
                 gen.addJumpIfR0Equals(broadcastAddr, mCountAndDropLabel);
             }
 
+            // If any keepalive filters,
+            generateKeepaliveFilter(gen);
+
             // If L2 broadcast packet, drop.
             // TODO: can we invert this condition to fall through to the common pass case below?
             maybeSetupCounter(gen, Counter.PASSED_IPV4_UNICAST);
@@ -1030,6 +1179,8 @@
             gen.addJumpIfBytesNotEqual(Register.R0, ETH_BROADCAST_MAC_ADDRESS, mCountAndPassLabel);
             maybeSetupCounter(gen, Counter.DROPPED_IPV4_L2_BROADCAST);
             gen.addJump(mCountAndDropLabel);
+        } else {
+            generateKeepaliveFilter(gen);
         }
 
         // Otherwise, pass
@@ -1037,6 +1188,13 @@
         gen.addJump(mCountAndPassLabel);
     }
 
+    private void generateKeepaliveFilter(ApfGenerator gen) throws IllegalInstructionException {
+        // Drop IPv4 Keepalive acks
+        for (int i = 0; i < mKeepaliveAcks.size(); ++i) {
+            final TcpKeepaliveAck ack = mKeepaliveAcks.valueAt(i);
+            if (ack instanceof TcpKeepaliveAckV4) ack.generateFilterLocked(gen);
+        }
+    }
 
     /**
      * Generate filter code to process IPv6 packets. Execution of this code ends in either the
@@ -1057,6 +1215,8 @@
         //   drop
         // if it's ICMPv6 NA to ff02::1:
         //   drop
+        // if keepalive ack
+        //   drop
 
         gen.addLoad8(Register.R0, IPV6_NEXT_HEADER_OFFSET);
 
@@ -1112,6 +1272,12 @@
         maybeSetupCounter(gen, Counter.DROPPED_IPV6_MULTICAST_NA);
         gen.addJump(mCountAndDropLabel);
         gen.defineLabel(skipUnsolicitedMulticastNALabel);
+
+        // Drop IPv6 Keepalive acks
+        for (int i = 0; i < mKeepaliveAcks.size(); ++i) {
+            final TcpKeepaliveAck ack = mKeepaliveAcks.valueAt(i);
+            if (ack instanceof TcpKeepaliveAckV6) ack.generateFilterLocked(gen);
+        }
     }
 
     /**
@@ -1489,6 +1655,36 @@
         installNewProgramLocked();
     }
 
+    /**
+     * Add keepalive ack packet filter.
+     * This will add a filter to drop acks to the keepalive packet passed as an argument.
+     *
+     * @param slot The index used to access the filter.
+     * @param sentKeepalivePacket The attributes of the sent keepalive packet.
+     */
+    public synchronized void addKeepalivePacketFilter(final int slot,
+            final TcpKeepalivePacketDataParcelable sentKeepalivePacket) {
+        log("Adding keepalive ack(" + slot + ")");
+        if (null != mKeepaliveAcks.get(slot)) {
+            throw new IllegalArgumentException("Keepalive slot " + slot + " is occupied");
+        }
+        final int ipVersion = sentKeepalivePacket.srcAddress.length == 4 ? 4 : 6;
+        mKeepaliveAcks.put(slot, (ipVersion == 4)
+                ? new TcpKeepaliveAckV4(sentKeepalivePacket)
+                : new TcpKeepaliveAckV6(sentKeepalivePacket));
+        installNewProgramLocked();
+    }
+
+    /**
+     * Remove keepalive packet filter.
+     *
+     * @param slot The index used to access the filter.
+     */
+    public synchronized void removeKeepalivePacketFilter(int slot) {
+        mKeepaliveAcks.remove(slot);
+        installNewProgramLocked();
+    }
+
     static public long counterValue(byte[] data, Counter counter)
             throws ArrayIndexOutOfBoundsException {
         // Follow the same wrap-around addressing scheme of the interpreter.
@@ -1541,6 +1737,17 @@
         }
         pw.decreaseIndent();
 
+        pw.println("Keepalive filter:");
+        pw.increaseIndent();
+        for (int i = 0; i < mKeepaliveAcks.size(); ++i) {
+            final TcpKeepaliveAck keepaliveAck = mKeepaliveAcks.valueAt(i);
+            pw.print("Slot ");
+            pw.print(mKeepaliveAcks.keyAt(i));
+            pw.print(" : ");
+            pw.println(keepaliveAck);
+        }
+        pw.decreaseIndent();
+
         if (DBG) {
             pw.println("Last program:");
             pw.increaseIndent();
diff --git a/packages/NetworkStack/src/android/net/apf/ApfGenerator.java b/packages/NetworkStack/src/android/net/apf/ApfGenerator.java
index 87a1b5e..809327a 100644
--- a/packages/NetworkStack/src/android/net/apf/ApfGenerator.java
+++ b/packages/NetworkStack/src/android/net/apf/ApfGenerator.java
@@ -476,7 +476,7 @@
 
     /**
      * Add an instruction to the end of the program to load 16-bits from the packet into
-     * {@code register}. The offset of the loaded 16-bits from the begining of the packet is
+     * {@code register}. The offset of the loaded 16-bits from the beginning of the packet is
      * the sum of {@code offset} and the value in register R1.
      */
     public ApfGenerator addLoad16Indexed(Register register, int offset) {
@@ -488,7 +488,7 @@
 
     /**
      * Add an instruction to the end of the program to load 32-bits from the packet into
-     * {@code register}. The offset of the loaded 32-bits from the begining of the packet is
+     * {@code register}. The offset of the loaded 32-bits from the beginning of the packet is
      * the sum of {@code offset} and the value in register R1.
      */
     public ApfGenerator addLoad32Indexed(Register register, int offset) {
diff --git a/packages/NetworkStack/src/android/net/ip/IpClient.java b/packages/NetworkStack/src/android/net/ip/IpClient.java
index 12fe8c5..9e59912 100644
--- a/packages/NetworkStack/src/android/net/ip/IpClient.java
+++ b/packages/NetworkStack/src/android/net/ip/IpClient.java
@@ -23,6 +23,7 @@
 
 import static com.android.server.util.PermissionUtil.checkNetworkStackCallingPermission;
 
+import android.annotation.NonNull;
 import android.content.Context;
 import android.net.ConnectivityManager;
 import android.net.DhcpResults;
@@ -34,6 +35,7 @@
 import android.net.ProxyInfo;
 import android.net.ProxyInfoParcelable;
 import android.net.RouteInfo;
+import android.net.TcpKeepalivePacketDataParcelable;
 import android.net.apf.ApfCapabilities;
 import android.net.apf.ApfFilter;
 import android.net.dhcp.DhcpClient;
@@ -292,6 +294,8 @@
     private static final int EVENT_PROVISIONING_TIMEOUT           = 10;
     private static final int EVENT_DHCPACTION_TIMEOUT             = 11;
     private static final int EVENT_READ_PACKET_FILTER_COMPLETE    = 12;
+    private static final int CMD_ADD_KEEPALIVE_PACKET_FILTER_TO_APF = 13;
+    private static final int CMD_REMOVE_KEEPALIVE_PACKET_FILTER_FROM_APF = 14;
 
     // Internal commands to use instead of trying to call transitionTo() inside
     // a given State's enter() method. Calling transitionTo() from enter/exit
@@ -522,6 +526,16 @@
             checkNetworkStackCallingPermission();
             IpClient.this.setMulticastFilter(enabled);
         }
+        @Override
+        public void addKeepalivePacketFilter(int slot, TcpKeepalivePacketDataParcelable pkt) {
+            checkNetworkStackCallingPermission();
+            IpClient.this.addKeepalivePacketFilter(slot, pkt);
+        }
+        @Override
+        public void removeKeepalivePacketFilter(int slot) {
+            checkNetworkStackCallingPermission();
+            IpClient.this.removeKeepalivePacketFilter(slot);
+        }
     }
 
     public String getInterfaceName() {
@@ -644,6 +658,22 @@
     }
 
     /**
+     * Called by WifiStateMachine to add keepalive packet filter before setting up
+     * keepalive offload.
+     */
+    public void addKeepalivePacketFilter(int slot, @NonNull TcpKeepalivePacketDataParcelable pkt) {
+        sendMessage(CMD_ADD_KEEPALIVE_PACKET_FILTER_TO_APF, slot, 0 /* Unused */, pkt);
+    }
+
+    /**
+     * Called by WifiStateMachine to remove keepalive packet filter after stopping keepalive
+     * offload.
+     */
+    public void removeKeepalivePacketFilter(int slot) {
+        sendMessage(CMD_REMOVE_KEEPALIVE_PACKET_FILTER_FROM_APF, slot, 0 /* Unused */);
+    }
+
+    /**
      * Dump logs of this IpClient.
      */
     public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
@@ -1512,6 +1542,23 @@
                     break;
                 }
 
+                case CMD_ADD_KEEPALIVE_PACKET_FILTER_TO_APF: {
+                    final int slot = msg.arg1;
+                    if (mApfFilter != null) {
+                        mApfFilter.addKeepalivePacketFilter(slot,
+                                (TcpKeepalivePacketDataParcelable) msg.obj);
+                    }
+                    break;
+                }
+
+                case CMD_REMOVE_KEEPALIVE_PACKET_FILTER_FROM_APF: {
+                    final int slot = msg.arg1;
+                    if (mApfFilter != null) {
+                        mApfFilter.removeKeepalivePacketFilter(slot);
+                    }
+                    break;
+                }
+
                 case EVENT_DHCPACTION_TIMEOUT:
                     stopDhcpAction();
                     break;
diff --git a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
index dbffa6d..0d6d080 100644
--- a/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
+++ b/packages/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java
@@ -61,6 +61,7 @@
 import android.net.util.Stopwatch;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
+import android.os.Bundle;
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.SystemClock;
@@ -674,11 +675,11 @@
         public boolean processMessage(Message message) {
             switch (message.what) {
                 case CMD_LAUNCH_CAPTIVE_PORTAL_APP:
-                    final Intent intent = new Intent(
-                            ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN);
+                    final Bundle appExtras = new Bundle();
                     // OneAddressPerFamilyNetwork is not parcelable across processes.
-                    intent.putExtra(ConnectivityManager.EXTRA_NETWORK, new Network(mNetwork));
-                    intent.putExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL,
+                    appExtras.putParcelable(
+                            ConnectivityManager.EXTRA_NETWORK, new Network(mNetwork));
+                    appExtras.putParcelable(ConnectivityManager.EXTRA_CAPTIVE_PORTAL,
                             new CaptivePortal(new ICaptivePortal.Stub() {
                                 @Override
                                 public void appResponse(int response) {
@@ -700,16 +701,14 @@
                                 }
                             }));
                     final CaptivePortalProbeResult probeRes = mLastPortalProbeResult;
-                    intent.putExtra(EXTRA_CAPTIVE_PORTAL_URL, probeRes.detectUrl);
+                    appExtras.putString(EXTRA_CAPTIVE_PORTAL_URL, probeRes.detectUrl);
                     if (probeRes.probeSpec != null) {
                         final String encodedSpec = probeRes.probeSpec.getEncodedSpec();
-                        intent.putExtra(EXTRA_CAPTIVE_PORTAL_PROBE_SPEC, encodedSpec);
+                        appExtras.putString(EXTRA_CAPTIVE_PORTAL_PROBE_SPEC, encodedSpec);
                     }
-                    intent.putExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL_USER_AGENT,
+                    appExtras.putString(ConnectivityManager.EXTRA_CAPTIVE_PORTAL_USER_AGENT,
                             mCaptivePortalUserAgent);
-                    intent.setFlags(
-                            Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK);
-                    mContext.startActivityAsUser(intent, UserHandle.CURRENT);
+                    mCm.startCaptivePortalApp(appExtras);
                     return HANDLED;
                 default:
                     return NOT_HANDLED;
diff --git a/packages/NetworkStack/tests/Android.bp b/packages/NetworkStack/tests/Android.bp
index 45fa2dc..4a09b3e 100644
--- a/packages/NetworkStack/tests/Android.bp
+++ b/packages/NetworkStack/tests/Android.bp
@@ -49,6 +49,7 @@
         "libhidlbase",
         "libhidltransport",
         "libhwbinder",
+        "libjsoncpp",
         "liblog",
         "liblzma",
         "libnativehelper",
diff --git a/packages/NetworkStack/tests/src/android/net/apf/ApfTest.java b/packages/NetworkStack/tests/src/android/net/apf/ApfTest.java
index f76e412..a4a1000 100644
--- a/packages/NetworkStack/tests/src/android/net/apf/ApfTest.java
+++ b/packages/NetworkStack/tests/src/android/net/apf/ApfTest.java
@@ -39,13 +39,14 @@
 import android.content.Context;
 import android.net.LinkAddress;
 import android.net.LinkProperties;
+import android.net.SocketKeepalive;
+import android.net.TcpKeepalivePacketData;
+import android.net.TcpKeepalivePacketData.TcpSocketInfo;
 import android.net.apf.ApfFilter.ApfConfiguration;
 import android.net.apf.ApfGenerator.IllegalInstructionException;
 import android.net.apf.ApfGenerator.Register;
 import android.net.ip.IIpClientCallbacks;
-import android.net.ip.IpClient;
 import android.net.ip.IpClient.IpClientCallbacksWrapper;
-import android.net.ip.IpClientCallbacks;
 import android.net.metrics.IpConnectivityLog;
 import android.net.metrics.RaEvent;
 import android.net.util.InterfaceParams;
@@ -1003,15 +1004,31 @@
     private static final byte[] ETH_BROADCAST_MAC_ADDRESS =
             {(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
 
+    private static final int IPV4_HEADER_LEN = 20;
     private static final int IPV4_VERSION_IHL_OFFSET = ETH_HEADER_LEN + 0;
+    private static final int IPV4_TOTAL_LENGTH_OFFSET  = ETH_HEADER_LEN + 2;
     private static final int IPV4_PROTOCOL_OFFSET = ETH_HEADER_LEN + 9;
+    private static final int IPV4_SRC_ADDR_OFFSET = ETH_HEADER_LEN + 12;
     private static final int IPV4_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 16;
+    private static final int IPV4_TCP_HEADER_LEN = 20;
+    private static final int IPV4_TCP_HEADER_OFFSET = ETH_HEADER_LEN + IPV4_HEADER_LEN;
+    private static final int IPV4_TCP_SRC_PORT_OFFSET = IPV4_TCP_HEADER_OFFSET + 0;
+    private static final int IPV4_TCP_DEST_PORT_OFFSET = IPV4_TCP_HEADER_OFFSET + 2;
+    private static final int IPV4_TCP_SEQ_NUM_OFFSET = IPV4_TCP_HEADER_OFFSET + 4;
+    private static final int IPV4_TCP_ACK_NUM_OFFSET = IPV4_TCP_HEADER_OFFSET + 8;
+    private static final int IPV4_TCP_HEADER_LENGTH_OFFSET = IPV4_TCP_HEADER_OFFSET + 12;
     private static final byte[] IPV4_BROADCAST_ADDRESS =
             {(byte) 255, (byte) 255, (byte) 255, (byte) 255};
 
     private static final int IPV6_NEXT_HEADER_OFFSET = ETH_HEADER_LEN + 6;
     private static final int IPV6_HEADER_LEN = 40;
+    private static final int IPV6_SRC_ADDR_OFFSET = ETH_HEADER_LEN + 8;
     private static final int IPV6_DEST_ADDR_OFFSET = ETH_HEADER_LEN + 24;
+    private static final int IPV6_TCP_HEADER_OFFSET = ETH_HEADER_LEN + IPV6_HEADER_LEN;
+    private static final int IPV6_TCP_SRC_PORT_OFFSET = IPV6_TCP_HEADER_OFFSET + 0;
+    private static final int IPV6_TCP_DEST_PORT_OFFSET = IPV6_TCP_HEADER_OFFSET + 2;
+    private static final int IPV6_TCP_SEQ_NUM_OFFSET = IPV6_TCP_HEADER_OFFSET + 4;
+    private static final int IPV6_TCP_ACK_NUM_OFFSET = IPV6_TCP_HEADER_OFFSET + 8;
     // The IPv6 all nodes address ff02::1
     private static final byte[] IPV6_ALL_NODES_ADDRESS =
             { (byte) 0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 };
@@ -1491,6 +1508,200 @@
         return packet.array();
     }
 
+    private static final byte[] IPV4_KEEPALIVE_SRC_ADDR = {10, 0, 0, 5};
+    private static final byte[] IPV4_KEEPALIVE_DST_ADDR = {10, 0, 0, 6};
+    private static final byte[] IPV4_ANOTHER_ADDR = {10, 0 , 0, 7};
+    private static final byte[] IPV6_KEEPALIVE_SRC_ADDR =
+            {(byte) 0x24, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (byte) 0xfa, (byte) 0xf1};
+    private static final byte[] IPV6_KEEPALIVE_DST_ADDR =
+            {(byte) 0x24, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (byte) 0xfa, (byte) 0xf2};
+    private static final byte[] IPV6_ANOTHER_ADDR =
+            {(byte) 0x24, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, (byte) 0xfa, (byte) 0xf5};
+
+    @Test
+    public void testApfFilterKeepaliveAck() throws Exception {
+        final MockIpClientCallback cb = new MockIpClientCallback();
+        final ApfConfiguration config = getDefaultConfig();
+        config.multicastFilter = DROP_MULTICAST;
+        config.ieee802_3Filter = DROP_802_3_FRAMES;
+        final TestApfFilter apfFilter = new TestApfFilter(mContext, config, cb, mLog);
+        byte[] program;
+        final int srcPort = 12345;
+        final int dstPort = 54321;
+        final int seqNum = 2123456789;
+        final int ackNum = 1234567890;
+        final int anotherSrcPort = 23456;
+        final int anotherDstPort = 65432;
+        final int anotherSeqNum = 2123456780;
+        final int anotherAckNum = 1123456789;
+        final int slot1 = 1;
+        final int slot2 = 2;
+        final int window = 14480;
+        final int windowScale = 4;
+
+        // src: 10.0.0.5, port: 12345
+        // dst: 10.0.0.6, port: 54321
+        InetAddress srcAddr = InetAddress.getByAddress(IPV4_KEEPALIVE_SRC_ADDR);
+        InetAddress dstAddr = InetAddress.getByAddress(IPV4_KEEPALIVE_DST_ADDR);
+
+        final TcpSocketInfo v4Tsi = new TcpSocketInfo(
+                srcAddr, srcPort, dstAddr, dstPort, seqNum, ackNum, window, windowScale);
+        final TcpKeepalivePacketData ipv4TcpKeepalivePacket =
+                TcpKeepalivePacketData.tcpKeepalivePacket(v4Tsi);
+
+        apfFilter.addKeepalivePacketFilter(slot1, ipv4TcpKeepalivePacket.toStableParcelable());
+        program = cb.getApfProgram();
+
+        // Verify IPv4 keepalive ack packet is dropped
+        // src: 10.0.0.6, port: 54321
+        // dst: 10.0.0.5, port: 12345
+        assertDrop(program,
+                ipv4Packet(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR,
+                        dstPort, srcPort, ackNum, seqNum + 1, 0 /* dataLength */));
+        // Verify IPv4 non-keepalive ack packet from the same source address is passed
+        assertPass(program,
+                ipv4Packet(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR,
+                        dstPort, srcPort, ackNum + 100, seqNum, 0 /* dataLength */));
+        assertPass(program,
+                ipv4Packet(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR,
+                        dstPort, srcPort, ackNum, seqNum + 1, 10 /* dataLength */));
+        // Verify IPv4 packet from another address is passed
+        assertPass(program,
+                ipv4Packet(IPV4_ANOTHER_ADDR, IPV4_KEEPALIVE_SRC_ADDR, anotherSrcPort,
+                        anotherDstPort, anotherSeqNum, anotherAckNum));
+
+        // Remove IPv4 keepalive filter
+        apfFilter.removeKeepalivePacketFilter(slot1);
+
+        try {
+            // src: 2404:0:0:0:0:0:faf1, port: 12345
+            // dst: 2404:0:0:0:0:0:faf2, port: 54321
+            srcAddr = InetAddress.getByAddress(IPV6_KEEPALIVE_SRC_ADDR);
+            dstAddr = InetAddress.getByAddress(IPV6_KEEPALIVE_DST_ADDR);
+            final TcpSocketInfo v6Tsi = new TcpSocketInfo(
+                    srcAddr, srcPort, dstAddr, dstPort, seqNum, ackNum, window, windowScale);
+            final TcpKeepalivePacketData ipv6TcpKeepalivePacket =
+                    TcpKeepalivePacketData.tcpKeepalivePacket(v6Tsi);
+            apfFilter.addKeepalivePacketFilter(slot1, ipv6TcpKeepalivePacket.toStableParcelable());
+            program = cb.getApfProgram();
+
+            // Verify IPv6 keepalive ack packet is dropped
+            // src: 2404:0:0:0:0:0:faf2, port: 54321
+            // dst: 2404:0:0:0:0:0:faf1, port: 12345
+            assertDrop(program,
+                    ipv6Packet(IPV6_KEEPALIVE_DST_ADDR, IPV6_KEEPALIVE_SRC_ADDR,
+                            dstPort, srcPort, ackNum, seqNum + 1));
+            // Verify IPv6 non-keepalive ack packet from the same source address is passed
+            assertPass(program,
+                    ipv6Packet(IPV6_KEEPALIVE_DST_ADDR, IPV6_KEEPALIVE_SRC_ADDR,
+                            dstPort, srcPort, ackNum + 100, seqNum));
+            // Verify IPv6 packet from another address is passed
+            assertPass(program,
+                    ipv6Packet(IPV6_ANOTHER_ADDR, IPV6_KEEPALIVE_SRC_ADDR, anotherSrcPort,
+                            anotherDstPort, anotherSeqNum, anotherAckNum));
+
+            // Remove IPv6 keepalive filter
+            apfFilter.removeKeepalivePacketFilter(slot1);
+
+            // Verify multiple filters
+            apfFilter.addKeepalivePacketFilter(slot1, ipv4TcpKeepalivePacket.toStableParcelable());
+            apfFilter.addKeepalivePacketFilter(slot2, ipv6TcpKeepalivePacket.toStableParcelable());
+            program = cb.getApfProgram();
+
+            // Verify IPv4 keepalive ack packet is dropped
+            // src: 10.0.0.6, port: 54321
+            // dst: 10.0.0.5, port: 12345
+            assertDrop(program,
+                    ipv4Packet(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR,
+                            dstPort, srcPort, ackNum, seqNum + 1));
+            // Verify IPv4 non-keepalive ack packet from the same source address is passed
+            assertPass(program,
+                    ipv4Packet(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR,
+                            dstPort, srcPort, ackNum + 100, seqNum));
+            // Verify IPv4 packet from another address is passed
+            assertPass(program,
+                    ipv4Packet(IPV4_ANOTHER_ADDR, IPV4_KEEPALIVE_SRC_ADDR, anotherSrcPort,
+                            anotherDstPort, anotherSeqNum, anotherAckNum));
+
+            // Verify IPv6 keepalive ack packet is dropped
+            // src: 2404:0:0:0:0:0:faf2, port: 54321
+            // dst: 2404:0:0:0:0:0:faf1, port: 12345
+            assertDrop(program,
+                    ipv6Packet(IPV6_KEEPALIVE_DST_ADDR, IPV6_KEEPALIVE_SRC_ADDR,
+                            dstPort, srcPort, ackNum, seqNum + 1));
+            // Verify IPv6 non-keepalive ack packet from the same source address is passed
+            assertPass(program,
+                    ipv6Packet(IPV6_KEEPALIVE_DST_ADDR, IPV6_KEEPALIVE_SRC_ADDR,
+                            dstPort, srcPort, ackNum + 100, seqNum));
+            // Verify IPv6 packet from another address is passed
+            assertPass(program,
+                    ipv6Packet(IPV6_ANOTHER_ADDR, IPV6_KEEPALIVE_SRC_ADDR, anotherSrcPort,
+                            anotherDstPort, anotherSeqNum, anotherAckNum));
+
+            // Remove keepalive filters
+            apfFilter.removeKeepalivePacketFilter(slot1);
+            apfFilter.removeKeepalivePacketFilter(slot2);
+        } catch (SocketKeepalive.InvalidPacketException e) {
+            // TODO: support V6 packets
+        }
+
+        program = cb.getApfProgram();
+
+        // Verify IPv4, IPv6 packets are passed
+        assertPass(program,
+                ipv4Packet(IPV4_KEEPALIVE_DST_ADDR, IPV4_KEEPALIVE_SRC_ADDR,
+                        dstPort, srcPort, ackNum, seqNum + 1));
+        assertPass(program,
+                ipv6Packet(IPV6_KEEPALIVE_DST_ADDR, IPV6_KEEPALIVE_SRC_ADDR,
+                        dstPort, srcPort, ackNum, seqNum + 1));
+        assertPass(program,
+                ipv4Packet(IPV4_ANOTHER_ADDR, IPV4_KEEPALIVE_SRC_ADDR, srcPort,
+                        dstPort, anotherSeqNum, anotherAckNum));
+        assertPass(program,
+                ipv6Packet(IPV6_ANOTHER_ADDR, IPV6_KEEPALIVE_SRC_ADDR, srcPort,
+                        dstPort, anotherSeqNum, anotherAckNum));
+
+        apfFilter.shutdown();
+    }
+
+    private static byte[] ipv4Packet(byte[] sip, byte[] tip, int sport,
+            int dport, int seq, int ack) {
+        ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
+        packet.putShort(ETH_ETHERTYPE_OFFSET, (short) ETH_P_IP);
+        packet.put(IPV4_VERSION_IHL_OFFSET, (byte) 0x45);
+        put(packet, IPV4_SRC_ADDR_OFFSET, sip);
+        put(packet, IPV4_DEST_ADDR_OFFSET, tip);
+        packet.putShort(IPV4_TCP_SRC_PORT_OFFSET, (short) sport);
+        packet.putShort(IPV4_TCP_DEST_PORT_OFFSET, (short) dport);
+        packet.putInt(IPV4_TCP_SEQ_NUM_OFFSET, seq);
+        packet.putInt(IPV4_TCP_ACK_NUM_OFFSET, ack);
+        return packet.array();
+    }
+
+    private static byte[] ipv4Packet(byte[] sip, byte[] tip, int sport,
+            int dport, int seq, int ack, int dataLength) {
+        final int totalLength = dataLength + IPV4_HEADER_LEN + IPV4_TCP_HEADER_LEN;
+
+        ByteBuffer packet = ByteBuffer.wrap(ipv4Packet(sip, tip, sport, dport, seq, ack));
+        packet.putShort(IPV4_TOTAL_LENGTH_OFFSET, (short) totalLength);
+        // TCP header length 5, reserved 3 bits, NS=0
+        packet.put(IPV4_TCP_HEADER_LENGTH_OFFSET, (byte) 0x50);
+        return packet.array();
+    }
+
+    private static byte[] ipv6Packet(byte[] sip, byte[] tip, int sport,
+            int dport, int seq, int ack) {
+        ByteBuffer packet = ByteBuffer.wrap(new byte[100]);
+        packet.putShort(ETH_ETHERTYPE_OFFSET, (short) ETH_P_IPV6);
+        put(packet, IPV6_SRC_ADDR_OFFSET, sip);
+        put(packet, IPV6_DEST_ADDR_OFFSET, tip);
+        packet.putShort(IPV6_TCP_SRC_PORT_OFFSET, (short) sport);
+        packet.putShort(IPV6_TCP_DEST_PORT_OFFSET, (short) dport);
+        packet.putInt(IPV6_TCP_SEQ_NUM_OFFSET, seq);
+        packet.putInt(IPV6_TCP_ACK_NUM_OFFSET, ack);
+        return packet.array();
+    }
+
     // Verify that the last program pushed to the IpClient.Callback properly filters the
     // given packet for the given lifetime.
     private void verifyRaLifetime(byte[] program, ByteBuffer packet, int lifetime) {
diff --git a/packages/PrintSpooler/AndroidManifest.xml b/packages/PrintSpooler/AndroidManifest.xml
index 478ee54..cd6abb2 100644
--- a/packages/PrintSpooler/AndroidManifest.xml
+++ b/packages/PrintSpooler/AndroidManifest.xml
@@ -37,16 +37,8 @@
     <uses-permission android:name="android.permission.READ_PRINT_SERVICES" />
     <uses-permission android:name="android.permission.READ_PRINT_SERVICE_RECOMMENDATIONS" />
 
-    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"
-                     android:dataSentOffDevice="no"
-                     android:dataSharedWithThirdParty="no"
-                     android:dataUsedForMonetization="no"
-                     android:dataRetentionTime="unlimited"/>
-    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"
-                     android:dataSentOffDevice="no"
-                     android:dataSharedWithThirdParty="no"
-                     android:dataUsedForMonetization="no"
-                     android:dataRetentionTime="unlimited"/>
+    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
 
     <application
         android:allowClearUserData="true"
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index dbeee1c..26ea6ab 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -220,4 +220,7 @@
 
     <!-- Default for Settings.Secure.CHARGING_SOUNDS_ENABLED -->
     <bool name="def_charging_sounds_enabled">true</bool>
+
+    <!-- Default for Settings.Secure.NOTIFICATION_BUBBLES -->
+    <bool name="def_notification_bubbles">true</bool>
 </resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 479c964..6152b8c 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -457,6 +457,9 @@
         dumpSetting(s, p,
                 Settings.Global.DEBUG_VIEW_ATTRIBUTES,
                 GlobalSettingsProto.Debug.VIEW_ATTRIBUTES);
+        dumpSetting(s, p,
+                Settings.Global.DEBUG_VIEW_ATTRIBUTES_APPLICATION_PACKAGE,
+                GlobalSettingsProto.Debug.VIEW_ATTRIBUTES_APPLICATION_PACKAGE);
         p.end(debugToken);
 
         final long defaultToken = p.start(GlobalSettingsProto.DEFAULT);
@@ -2079,6 +2082,9 @@
                 Settings.Secure.NOTIFICATION_BADGING,
                 SecureSettingsProto.Notification.BADGING);
         dumpSetting(s, p,
+                Settings.Secure.NOTIFICATION_BUBBLES,
+                SecureSettingsProto.Notification.BUBBLES);
+        dumpSetting(s, p,
                 Settings.Secure.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING,
                 SecureSettingsProto.Notification.SHOW_NOTE_ABOUT_NOTIFICATION_HIDING);
         dumpSetting(s, p,
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 23e5f0e..a7ad223 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -3232,7 +3232,7 @@
         }
 
         private final class UpgradeController {
-            private static final int SETTINGS_VERSION = 173;
+            private static final int SETTINGS_VERSION = 174;
 
             private final int mUserId;
 
@@ -4252,6 +4252,24 @@
                     currentVersion = 173;
                 }
 
+                if (currentVersion == 173) {
+                    // Version 173: Set the default value for Secure Settings: NOTIFICATION_BUBBLES
+
+                    final SettingsState secureSettings = getSecureSettingsLocked(userId);
+
+                    final Setting bubblesSetting = secureSettings.getSettingLocked(
+                            Secure.NOTIFICATION_BUBBLES);
+
+                    if (bubblesSetting.isNull()) {
+                        secureSettings.insertSettingLocked(Secure.NOTIFICATION_BUBBLES,
+                                getContext().getResources().getBoolean(
+                                        R.bool.def_notification_bubbles) ? "1" : "0", null,
+                                true, SettingsState.SYSTEM_PACKAGE_NAME);
+                    }
+
+                    currentVersion = 174;
+                }
+
                 // vXXX: Add new settings above this point.
 
                 if (currentVersion != newVersion) {
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 866b46f..3778a9c 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -22,11 +22,6 @@
         android:sharedUserId="android.uid.systemui"
         coreApp="true">
 
-    <!-- Using OpenGL ES 2.0 -->
-    <uses-feature
-        android:glEsVersion="0x00020000"
-        android:required="true" />
-
     <!-- SysUI must be the one to define this permission; its name is
          referenced by the core OS. -->
     <permission android:name="android.permission.systemui.IDENTITY"
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java
index ac69043..38bf77d 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/ClockPlugin.java
@@ -55,9 +55,16 @@
     void setTextColor(int color);
 
     /**
+     * Sets the color palette for the clock face.
+     * @param supportsDarkText Whether dark text can be displayed.
+     * @param colors Colors that should be used on the clock face, ordered from darker to lighter.
+     */
+    default void setColorPalette(boolean supportsDarkText, int[] colors) {}
+
+    /**
      * Notifies that time tick alarm from doze service fired.
      */
-    default void dozeTimeTick() { }
+    default void dozeTimeTick() {}
 
     /**
      * Set the amount (ratio) that the device has transitioned to doze.
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java
new file mode 100644
index 0000000..3ee69b4
--- /dev/null
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/statusbar/StatusBarStateController.java
@@ -0,0 +1,98 @@
+/*
+ * 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.systemui.plugins.statusbar;
+
+import com.android.systemui.plugins.annotations.DependsOn;
+import com.android.systemui.plugins.annotations.ProvidesInterface;
+import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
+
+
+/**
+ * Sends updates to {@link StateListener}s about changes to the status bar state and dozing state
+ */
+@ProvidesInterface(version = StatusBarStateController.VERSION)
+@DependsOn(target = StatusBarStateController.StateListener.class)
+public interface StatusBarStateController {
+    int VERSION = 1;
+
+    /**
+     * Current status bar state
+     */
+    int getState();
+
+    /**
+     * Is device dozing
+     */
+    boolean isDozing();
+
+    /**
+     * Adds a state listener
+     */
+    void addCallback(StateListener listener);
+
+    /**
+     * Removes callback from listeners
+     */
+    void removeCallback(StateListener listener);
+
+    /**
+     * Get amount of doze
+     */
+    float getDozeAmount();
+
+    /**
+     * Listener for StatusBarState updates
+     */
+    @ProvidesInterface(version = StateListener.VERSION)
+    public interface StateListener {
+        int VERSION = 1;
+
+        /**
+         * Callback before the new state is applied, for those who need to preempt the change.
+         */
+        default void onStatePreChange(int oldState, int newState) {
+        }
+
+        /**
+         * Callback after all listeners have had a chance to update based on the state change
+         */
+        default void onStatePostChange() {
+        }
+
+        /**
+         * Required callback. Get the new state and do what you will with it. Keep in mind that
+         * other listeners are typically unordered and don't rely on your work being done before
+         * other peers.
+         *
+         * Only called if the state is actually different.
+         */
+        default void onStateChanged(int newState) {
+        }
+
+        /**
+         * Callback to be notified when Dozing changes. Dozing is stored separately from state.
+         */
+        default void onDozingChanged(boolean isDozing) {}
+
+        /**
+         * Callback to be notified when the doze amount changes. Useful for animations.
+         * Note: this will be called for each animation frame. Please be careful to avoid
+         * performance regressions.
+         */
+        default void onDozeAmountChanged(float linear, float eased) {}
+    }
+}
diff --git a/packages/SystemUI/res-keyguard/values-af/strings.xml b/packages/SystemUI/res-keyguard/values-af/strings.xml
index da11db3..54537e5 100644
--- a/packages/SystemUI/res-keyguard/values-af/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-af/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="other">SIM is nou gedeaktiveer. Voer PUK-kode in om voort te gaan. Jy het <xliff:g id="_NUMBER_1">%d</xliff:g> pogings oor voordat die SIM permanent onbruikbaar word. Kontak die diensverskaffer vir besonderhede.</item>
       <item quantity="one">SIM is nou gedeaktiveer. Voer PUK-kode in om voort te gaan. Jy het <xliff:g id="_NUMBER_0">%d</xliff:g> poging oor voordat die SIM permanent onbruikbaar word. Kontak die diensverskaffer vir besonderhede.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"Dit is"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"Twaalf"</item>
     <item msgid="7389464214252023751">"Een"</item>
diff --git a/packages/SystemUI/res-keyguard/values-am/strings.xml b/packages/SystemUI/res-keyguard/values-am/strings.xml
index 0d154f5..379838d 100644
--- a/packages/SystemUI/res-keyguard/values-am/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-am/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="one">ሲም አሁን ተሰናክሏል። ለመቀጠል የPUK ኮድ ያስገቡ። ሲም እስከመጨረሻው መጠቀም የማይቻል ከመሆኑ በፊት <xliff:g id="_NUMBER_1">%d</xliff:g> ሙከራዎች ይቀረዎታል። ዝርዝሮችን ለማግኘት የአገልግሎት አቅራቢን ያነጋግሩ።</item>
       <item quantity="other">ሲም አሁን ተሰናክሏል። ለመቀጠል የPUK ኮድ ያስገቡ። ሲም እስከመጨረሻው መጠቀም የማይቻል ከመሆኑ በፊት <xliff:g id="_NUMBER_1">%d</xliff:g> ሙከራዎች ይቀረዎታል። ዝርዝሮችን ለማግኘት የአገልግሎት አቅራቢን ያነጋግሩ።</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"ነው"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"አስራ ሁለት"</item>
     <item msgid="7389464214252023751">"አንድ"</item>
diff --git a/packages/SystemUI/res-keyguard/values-ar/strings.xml b/packages/SystemUI/res-keyguard/values-ar/strings.xml
index 826f2f0..2fef027 100644
--- a/packages/SystemUI/res-keyguard/values-ar/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ar/strings.xml
@@ -182,7 +182,7 @@
       <item quantity="other">‏تم إيقاف شريحة SIM الآن. أدخل رمز PUK للمتابعة، وتتبقى لديك <xliff:g id="_NUMBER_1">%d</xliff:g> محاولة قبل أن تصبح شريحة SIM غير صالحة للاستخدام نهائيًا. ويمكنك الاتصال بمشغل شبكة الجوّال لمعرفة التفاصيل.</item>
       <item quantity="one">‏تم إيقاف شريحة SIM الآن. أدخل رمز PUK للمتابعة، وتتبقى لديك محاولة واحدة (<xliff:g id="_NUMBER_0">%d</xliff:g>) قبل أن تصبح شريحة SIM غير صالحة للاستخدام نهائيًا. ويمكنك الاتصال بمشغل شبكة الجوّال لمعرفة التفاصيل.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"الساعة"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"الثانية عشرة"</item>
     <item msgid="7389464214252023751">"الواحدة"</item>
diff --git a/packages/SystemUI/res-keyguard/values-as/strings.xml b/packages/SystemUI/res-keyguard/values-as/strings.xml
index f67e009..63d0512 100644
--- a/packages/SystemUI/res-keyguard/values-as/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-as/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="one">ছিমখন অক্ষম হ’ল। অব্যাহত ৰাখিবলৈ PUK দিয়ক। ছিমখন স্থায়ীভাৱে ব্যৱহাৰৰ অনুপযোগী হোৱাৰ পূৰ্বে আপোনাৰ হাতত <xliff:g id="_NUMBER_1">%d</xliff:g>টা প্ৰয়াস বাকী আছে। সবিশেষ জানিবলৈ বাহকৰ সৈতে যোগাযোগ কৰক।</item>
       <item quantity="other">ছিমখন অক্ষম হ’ল। অব্যাহত ৰাখিবলৈ PUK দিয়ক। ছিমখন স্থায়ীভাৱে ব্যৱহাৰৰ অনুপযোগী হোৱাৰ পূৰ্বে আপোনাৰ হাতত <xliff:g id="_NUMBER_1">%d</xliff:g>টা প্ৰয়াস বাকী আছে। সবিশেষ জানিবলৈ বাহকৰ সৈতে যোগাযোগ কৰক।</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"সময়"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"বাৰ"</item>
     <item msgid="7389464214252023751">"এক"</item>
diff --git a/packages/SystemUI/res-keyguard/values-az/strings.xml b/packages/SystemUI/res-keyguard/values-az/strings.xml
index 50f1b1f..3714ec6e 100644
--- a/packages/SystemUI/res-keyguard/values-az/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-az/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="other">SIM indi deaktivdir. Davam etmək üçün PUK kodunu daxil edin. SIM birdəfəlik yararsız olmadan öncə <xliff:g id="_NUMBER_1">%d</xliff:g> cəhdiniz qalır. Ətraflı məlumat üçün operatorla əlaqə saxlayın.</item>
       <item quantity="one">SIM indi deaktivdir. Davam etmək üçün PUK kodunu daxil edin. SIM birdəfəlik yararsız olmadan öncə <xliff:g id="_NUMBER_0">%d</xliff:g> cəhdiniz qalır. Ətraflı məlumat üçün operatorla əlaqə saxlayın.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"Saat"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"On iki"</item>
     <item msgid="7389464214252023751">"Bir"</item>
diff --git a/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml b/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml
index a5fceef..3272313 100644
--- a/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-b+sr+Latn/strings.xml
@@ -158,7 +158,7 @@
       <item quantity="few">SIM je sada onemogućen. Unesite PUK kôd da biste nastavili. Imate još <xliff:g id="_NUMBER_1">%d</xliff:g> pokušaja pre nego što SIM postane trajno neupotrebljiv. Detaljne informacije potražite od mobilnog operatera.</item>
       <item quantity="other">SIM je sada onemogućen. Unesite PUK kôd da biste nastavili. Imate još <xliff:g id="_NUMBER_1">%d</xliff:g> pokušaja pre nego što SIM postane trajno neupotrebljiv. Detaljne informacije potražite od mobilnog operatera.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"Sada je"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"dvanaest"</item>
     <item msgid="7389464214252023751">"jedan"</item>
diff --git a/packages/SystemUI/res-keyguard/values-be/strings.xml b/packages/SystemUI/res-keyguard/values-be/strings.xml
index 872cd7b..aaa4cb6 100644
--- a/packages/SystemUI/res-keyguard/values-be/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-be/strings.xml
@@ -166,7 +166,7 @@
       <item quantity="many">SIM-карта заблакіравана. Каб працягнуць, увядзіце PUK-код. У вас ёсць яшчэ <xliff:g id="_NUMBER_1">%d</xliff:g> спроб, пасля чаго SIM-карта будзе заблакіравана назаўсёды. Звярніцеся да аператара, каб даведацца больш.</item>
       <item quantity="other">SIM-карта заблакіравана. Каб працягнуць, увядзіце PUK-код. У вас ёсць яшчэ <xliff:g id="_NUMBER_1">%d</xliff:g> спробы, пасля чаго SIM-карта будзе заблакіравана назаўсёды. Звярніцеся да аператара, каб даведацца больш.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"Зараз"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"Дванаццаць"</item>
     <item msgid="7389464214252023751">"Адна"</item>
diff --git a/packages/SystemUI/res-keyguard/values-bg/strings.xml b/packages/SystemUI/res-keyguard/values-bg/strings.xml
index 741834f..d89dd41 100644
--- a/packages/SystemUI/res-keyguard/values-bg/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-bg/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="other">SIM картата вече е деактивирана. Въведете PUK кода, за да продължите. Остават ви <xliff:g id="_NUMBER_1">%d</xliff:g> опита, преди SIM картата да стане неизползваема завинаги. Свържете се с оператора за подробности.</item>
       <item quantity="one">SIM картата вече е деактивирана. Въведете PUK кода, за да продължите. Остава ви <xliff:g id="_NUMBER_0">%d</xliff:g> опит, преди SIM картата да стане неизползваема завинаги. Свържете се с оператора за подробности.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"Часът е"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"дванайсет"</item>
     <item msgid="7389464214252023751">"един"</item>
diff --git a/packages/SystemUI/res-keyguard/values-bn/strings.xml b/packages/SystemUI/res-keyguard/values-bn/strings.xml
index 25346a5..d0794c3 100644
--- a/packages/SystemUI/res-keyguard/values-bn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-bn/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="one">সিম অক্ষম করা হয়েছে। চালিয়ে যেতে PUK কোড লিখুন। আপনি আর <xliff:g id="_NUMBER_1">%d</xliff:g> বার চেষ্টা করতে পারবেন, তারপরে এই সিমটি আর একেবারেই ব্যবহার করা যাবে না। বিশদে জানতে পরিষেবা প্রদানকারীর সাথে যোগাযোগ করুন।</item>
       <item quantity="other">সিম অক্ষম করা হয়েছে। চালিয়ে যেতে PUK কোড লিখুন। আপনি আর <xliff:g id="_NUMBER_1">%d</xliff:g> বার চেষ্টা করতে পারবেন, তারপরে এই সিমটি আর একেবারেই ব্যবহার করা যাবে না। বিশদে জানতে পরিষেবা প্রদানকারীর সাথে যোগাযোগ করুন।</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"এখন"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"বারো"</item>
     <item msgid="7389464214252023751">"এক"</item>
diff --git a/packages/SystemUI/res-keyguard/values-bs/strings.xml b/packages/SystemUI/res-keyguard/values-bs/strings.xml
index 9396ef1..72e4603 100644
--- a/packages/SystemUI/res-keyguard/values-bs/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-bs/strings.xml
@@ -158,7 +158,7 @@
       <item quantity="few">SIM kartica je onemogućena. Unesite PUK kôd da nastavite. Imate još <xliff:g id="_NUMBER_1">%d</xliff:g> pokušaja prije nego što SIM kartica postane trajno neupotrebljiva. Za više informacija kontaktirajte mobilnog operatera.</item>
       <item quantity="other">SIM kartica je onemogućena. Unesite PUK kôd da nastavite. Imate još <xliff:g id="_NUMBER_1">%d</xliff:g> pokušaja prije nego što SIM kartica postane trajno neupotrebljiva. Za više informacija kontaktirajte mobilnog operatera.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"Sada je"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"Dvanaest"</item>
     <item msgid="7389464214252023751">"Jedan"</item>
diff --git a/packages/SystemUI/res-keyguard/values-ca/strings.xml b/packages/SystemUI/res-keyguard/values-ca/strings.xml
index 2fa0897..185a3f3 100644
--- a/packages/SystemUI/res-keyguard/values-ca/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ca/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="other">La targeta SIM s\'ha desactivat. Introdueix el codi PUK per continuar. Et queden <xliff:g id="_NUMBER_1">%d</xliff:g> intents; si no l\'encertes, la SIM no es podrà tornar a fer servir. Contacta amb l\'operador de telefonia mòbil per obtenir-ne més informació.</item>
       <item quantity="one">La targeta SIM s\'ha desactivat. Introdueix el codi PUK per continuar. Et queda <xliff:g id="_NUMBER_0">%d</xliff:g> intent; si no l\'encertes, la SIM no es podrà tornar a fer servir. Contacta amb l\'operador de telefonia mòbil per obtenir-ne més informació.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"Són les"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"i dotze"</item>
     <item msgid="7389464214252023751">"Una"</item>
diff --git a/packages/SystemUI/res-keyguard/values-cs/strings.xml b/packages/SystemUI/res-keyguard/values-cs/strings.xml
index 2708f8f..bb01b7e 100644
--- a/packages/SystemUI/res-keyguard/values-cs/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-cs/strings.xml
@@ -166,7 +166,7 @@
       <item quantity="other">SIM karta je teď zablokována. Chcete-li pokračovat, zadejte kód PUK. Máte ještě <xliff:g id="_NUMBER_1">%d</xliff:g> pokusů, poté bude SIM karta natrvalo zablokována. Podrobnosti vám poskytne operátor.</item>
       <item quantity="one">SIM karta je teď zablokována. Chcete-li pokračovat, zadejte kód PUK. Máte ještě <xliff:g id="_NUMBER_0">%d</xliff:g> pokus, poté bude SIM karta natrvalo zablokována. Podrobnosti vám poskytne operátor.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"Je"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"Dvanáct"</item>
     <item msgid="7389464214252023751">"Jedna"</item>
diff --git a/packages/SystemUI/res-keyguard/values-da/strings.xml b/packages/SystemUI/res-keyguard/values-da/strings.xml
index 34c248d..fbdaf0f 100644
--- a/packages/SystemUI/res-keyguard/values-da/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-da/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="one">SIM-kortet er nu deaktiveret. Angiv PUK-koden for at fortsætte. Du har <xliff:g id="_NUMBER_1">%d</xliff:g> forsøg tilbage, før SIM-kortet bliver permanent ubrugeligt. Kontakt dit mobilselskab for at få flere oplysninger.</item>
       <item quantity="other">SIM-kortet er nu deaktiveret. Angiv PUK-koden for at fortsætte. Du har <xliff:g id="_NUMBER_1">%d</xliff:g> forsøg tilbage, før SIM-kortet bliver permanent ubrugeligt. Kontakt dit mobilselskab for at få flere oplysninger.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"Den er"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"Tolv"</item>
     <item msgid="7389464214252023751">"Et"</item>
diff --git a/packages/SystemUI/res-keyguard/values-de/strings.xml b/packages/SystemUI/res-keyguard/values-de/strings.xml
index d8daf83f..b6127df 100644
--- a/packages/SystemUI/res-keyguard/values-de/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-de/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="other">Die SIM-Karte ist jetzt deaktiviert. Gib den PUK-Code ein, um fortzufahren. Du hast noch <xliff:g id="_NUMBER_1">%d</xliff:g> Versuche, bevor die SIM-Karte endgültig gesperrt wird. Weitere Informationen erhältst du von deinem Mobilfunkanbieter.</item>
       <item quantity="one">Die SIM-Karte ist jetzt deaktiviert. Gib den PUK-Code ein, um fortzufahren. Du hast noch <xliff:g id="_NUMBER_0">%d</xliff:g> Versuch, bevor die SIM-Karte endgültig gesperrt wird. Weitere Informationen erhältst du von deinem Mobilfunkanbieter.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"Es ist"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"zwölf Uhr"</item>
     <item msgid="7389464214252023751">"ein Uhr"</item>
diff --git a/packages/SystemUI/res-keyguard/values-el/strings.xml b/packages/SystemUI/res-keyguard/values-el/strings.xml
index 6c0916c..402e297 100644
--- a/packages/SystemUI/res-keyguard/values-el/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-el/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="other">Η κάρτα SIM απενεργοποιήθηκε. Καταχωρίστε τον κωδικό PUK, για να συνεχίσετε. Απομένουν <xliff:g id="_NUMBER_1">%d</xliff:g> ακόμη προσπάθειες προτού να μην είναι πλέον δυνατή η χρήση της κάρτας SIM. Επικοινωνήστε με την εταιρεία κινητής τηλεφωνίας για λεπτομέρειες.</item>
       <item quantity="one">Η κάρτα SIM απενεργοποιήθηκε. Καταχωρίστε τον κωδικό PUK, για να συνεχίσετε. Απομένει <xliff:g id="_NUMBER_0">%d</xliff:g> ακόμη προσπάθεια προτού να μην είναι πλέον δυνατή η χρήση της κάρτας SIM. Επικοινωνήστε με την εταιρεία κινητής τηλεφωνίας για λεπτομέρειες.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"Είναι"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"Δώδεκα"</item>
     <item msgid="7389464214252023751">"Μία"</item>
diff --git a/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml b/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml
index 80c9b82..72b8085 100644
--- a/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rAU/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="other">SIM is now disabled. Enter PUK code to continue. You have <xliff:g id="_NUMBER_1">%d</xliff:g> remaining attempts before SIM becomes permanently unusable. Contact operator for details.</item>
       <item quantity="one">SIM is now disabled. Enter PUK code to continue. You have <xliff:g id="_NUMBER_0">%d</xliff:g> remaining attempt before SIM becomes permanently unusable. Contact operator for details.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"It’s"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"Twelve"</item>
     <item msgid="7389464214252023751">"One"</item>
diff --git a/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml b/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml
index 20c4d56..ecc0f71 100644
--- a/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rCA/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="other">SIM is now disabled. Enter PUK code to continue. You have <xliff:g id="_NUMBER_1">%d</xliff:g> remaining attempts before SIM becomes permanently unusable. Contact operator for details.</item>
       <item quantity="one">SIM is now disabled. Enter PUK code to continue. You have <xliff:g id="_NUMBER_0">%d</xliff:g> remaining attempt before SIM becomes permanently unusable. Contact operator for details.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"It’s"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"Twelve"</item>
     <item msgid="7389464214252023751">"One"</item>
diff --git a/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml b/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml
index 80c9b82..72b8085 100644
--- a/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rGB/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="other">SIM is now disabled. Enter PUK code to continue. You have <xliff:g id="_NUMBER_1">%d</xliff:g> remaining attempts before SIM becomes permanently unusable. Contact operator for details.</item>
       <item quantity="one">SIM is now disabled. Enter PUK code to continue. You have <xliff:g id="_NUMBER_0">%d</xliff:g> remaining attempt before SIM becomes permanently unusable. Contact operator for details.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"It’s"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"Twelve"</item>
     <item msgid="7389464214252023751">"One"</item>
diff --git a/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml b/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml
index 80c9b82..72b8085 100644
--- a/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rIN/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="other">SIM is now disabled. Enter PUK code to continue. You have <xliff:g id="_NUMBER_1">%d</xliff:g> remaining attempts before SIM becomes permanently unusable. Contact operator for details.</item>
       <item quantity="one">SIM is now disabled. Enter PUK code to continue. You have <xliff:g id="_NUMBER_0">%d</xliff:g> remaining attempt before SIM becomes permanently unusable. Contact operator for details.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"It’s"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"Twelve"</item>
     <item msgid="7389464214252023751">"One"</item>
diff --git a/packages/SystemUI/res-keyguard/values-en-rXC/strings.xml b/packages/SystemUI/res-keyguard/values-en-rXC/strings.xml
index a33d817..501dcb7 100644
--- a/packages/SystemUI/res-keyguard/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-en-rXC/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="other">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‏‏‎‏‎‎‏‏‎‏‎‎‎‎‏‏‎‎‏‎‏‎‎‏‎‏‎‎‏‎‎‏‎‎‎‎‎‎‎‏‎‏‎‎‎‏‏‎‏‎‎‎‎‎SIM is now disabled. Enter PUK code to continue. You have ‎‏‎‎‏‏‎<xliff:g id="_NUMBER_1">%d</xliff:g>‎‏‎‎‏‏‏‎ remaining attempts before SIM becomes permanently unusable. Contact carrier for details.‎‏‎‎‏‎</item>
       <item quantity="one">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‏‏‎‏‎‎‏‏‎‏‎‎‎‎‏‏‎‎‏‎‏‎‎‏‎‏‎‎‏‎‎‏‎‎‎‎‎‎‎‏‎‏‎‎‎‏‏‎‏‎‎‎‎‎SIM is now disabled. Enter PUK code to continue. You have ‎‏‎‎‏‏‎<xliff:g id="_NUMBER_0">%d</xliff:g>‎‏‎‎‏‏‏‎ remaining attempt before SIM becomes permanently unusable. Contact carrier for details.‎‏‎‎‏‎</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‎‎‏‏‎‏‏‎‏‎‎‏‏‏‎‎‏‏‎‏‏‏‎‎‎‎‎‎‏‏‏‎‏‏‏‎‏‏‏‎‎‎‏‎‎‏‏‎‎‎‎‎‏‎‏‎‎‎It’s‎‏‎‎‏‎"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‏‎‎‎‏‎‎‏‎‏‎‏‏‏‎‎‎‎‏‏‏‏‏‎‎‎‏‎‏‎‎‎‏‎‏‎‏‎‎‎‏‏‎‏‎‎‏‎‎‏‏‏‎‏‏‏‏‎‏‏‎‎Twelve‎‏‎‎‏‎"</item>
     <item msgid="7389464214252023751">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‎‏‏‎‏‎‎‎‏‏‎‎‏‎‏‎‎‏‏‎‏‎‎‎‏‏‎‏‎‏‎‎‎‎‏‎‏‏‏‏‎‎‏‏‏‏‏‎‏‏‏‏‏‏‎‎‎‏‏‏‎One‎‏‎‎‏‎"</item>
diff --git a/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml b/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml
index 98453a7..f93d933 100644
--- a/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-es-rUS/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="other">Se inhabilitó la SIM. Para continuar, ingresa el código PUK. Te quedan <xliff:g id="_NUMBER_1">%d</xliff:g> intentos más antes de que la SIM quede inutilizable permanentemente. Comunícate con tu proveedor para obtener más detalles.</item>
       <item quantity="one">Se inhabilitó la SIM. Para continuar, ingresa el código PUK. Te queda <xliff:g id="_NUMBER_0">%d</xliff:g> intento más antes de que la SIM quede inutilizable permanentemente. Comunícate con tu proveedor para obtener más detalles.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"Son las"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"Doce"</item>
     <item msgid="7389464214252023751">"Una"</item>
diff --git a/packages/SystemUI/res-keyguard/values-es/strings.xml b/packages/SystemUI/res-keyguard/values-es/strings.xml
index 00bdd91..9c189d9 100644
--- a/packages/SystemUI/res-keyguard/values-es/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-es/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="other">La tarjeta SIM está inhabilitada. Introduce el código PUK para continuar. Te quedan <xliff:g id="_NUMBER_1">%d</xliff:g> intentos para que la tarjeta SIM quede inservible de forma permanente. Ponte en contacto con tu operador para obtener más información.</item>
       <item quantity="one">La tarjeta SIM está inhabilitada. Introduce el código PUK para continuar. Te queda <xliff:g id="_NUMBER_0">%d</xliff:g> intento para que la tarjeta SIM quede inservible de forma permanente. Ponte en contacto con tu operador para obtener más información.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"Son las"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"Doce"</item>
     <item msgid="7389464214252023751">"Uno"</item>
diff --git a/packages/SystemUI/res-keyguard/values-et/strings.xml b/packages/SystemUI/res-keyguard/values-et/strings.xml
index e778804..7594537 100644
--- a/packages/SystemUI/res-keyguard/values-et/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-et/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="other">SIM-kaart on nüüd keelatud. Jätkamiseks sisestage PUK-kood. Teil on jäänud veel <xliff:g id="_NUMBER_1">%d</xliff:g> katset enne, kui SIM-kaart püsivalt lukustatakse. Lisateavet küsige operaatorilt.</item>
       <item quantity="one">SIM-kaart on nüüd keelatud. Jätkamiseks sisestage PUK-kood. Teil on jäänud veel <xliff:g id="_NUMBER_0">%d</xliff:g> katse enne, kui SIM-kaart püsivalt lukustatakse. Lisateavet küsige operaatorilt.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"Kell on"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"Kaksteist"</item>
     <item msgid="7389464214252023751">"Üks"</item>
diff --git a/packages/SystemUI/res-keyguard/values-eu/strings.xml b/packages/SystemUI/res-keyguard/values-eu/strings.xml
index 3ebb536..8b1284d 100644
--- a/packages/SystemUI/res-keyguard/values-eu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-eu/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="other">Desgaitu egin da SIM txartela. Aurrera egiteko, idatzi PUK kodea. <xliff:g id="_NUMBER_1">%d</xliff:g> saiakera geratzen zaizkizu SIM txartela betiko erabilgaitz geratu aurretik. Xehetasunak lortzeko, jarri operadorearekin harremanetan.</item>
       <item quantity="one">Desgaitu egin da SIM txartela. Aurrera egiteko, idatzi PUK kodea. <xliff:g id="_NUMBER_0">%d</xliff:g> saiakera geratzen zaizu SIM txartela betiko erabilgaitz geratu aurretik. Xehetasunak lortzeko, jarri operadorearekin harremanetan.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"Ordua:"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"Hamabiak"</item>
     <item msgid="7389464214252023751">"Ordu bata"</item>
diff --git a/packages/SystemUI/res-keyguard/values-fa/strings.xml b/packages/SystemUI/res-keyguard/values-fa/strings.xml
index 0c30d03..183152e 100644
--- a/packages/SystemUI/res-keyguard/values-fa/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fa/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="one">‏سیم‌کارت اکنون غیرفعال است. برای ادامه دادن کد PUK را وارد کنید. <xliff:g id="_NUMBER_1">%d</xliff:g> تلاش دیگر باقی مانده است و پس از آن سیم‌کارت برای همیشه غیرقابل‌استفاده می‌شود. برای اطلاع از جزئیات با شرکت مخابراتی تماس بگیرید.</item>
       <item quantity="other">‏سیم‌کارت اکنون غیرفعال است. برای ادامه دادن کد PUK را وارد کنید. <xliff:g id="_NUMBER_1">%d</xliff:g> تلاش دیگر باقی مانده است و پس از آن سیم‌کارت برای همیشه غیرقابل‌استفاده می‌شود. برای اطلاع از جزئیات با شرکت مخابراتی تماس بگیرید.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"ساعت:"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"دوازده"</item>
     <item msgid="7389464214252023751">"یک"</item>
diff --git a/packages/SystemUI/res-keyguard/values-fi/strings.xml b/packages/SystemUI/res-keyguard/values-fi/strings.xml
index 6092372..ec3c596 100644
--- a/packages/SystemUI/res-keyguard/values-fi/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fi/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="other">SIM-kortti on nyt lukittu. Anna PUK-koodi, niin voit jatkaa. Sinulla on <xliff:g id="_NUMBER_1">%d</xliff:g> yritystä jäljellä, ennen kuin SIM-kortti poistuu pysyvästi käytöstä. Pyydä lisätietoja operaattoriltasi.</item>
       <item quantity="one">SIM-kortti on nyt lukittu. Anna PUK-koodi, niin voit jatkaa. Sinulla on <xliff:g id="_NUMBER_0">%d</xliff:g> yritys jäljellä, ennen kuin SIM-kortti poistuu pysyvästi käytöstä. Pyydä lisätietoja operaattoriltasi.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"Kello on"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"Kaksitoista"</item>
     <item msgid="7389464214252023751">"Yksi"</item>
diff --git a/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml b/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml
index 8e92ffc..73705c8 100644
--- a/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fr-rCA/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="one">La carte SIM est maintenant désactivée. Entrez le code PUK pour continuer. Il vous reste <xliff:g id="_NUMBER_1">%d</xliff:g> tentative avant que votre carte SIM devienne définitivement inutilisable. Pour obtenir plus de détails, communiquez avec votre fournisseur de services.</item>
       <item quantity="other">La carte SIM est maintenant désactivée. Entrez le code PUK pour continuer. Il vous reste <xliff:g id="_NUMBER_1">%d</xliff:g> tentatives avant que votre carte SIM devienne définitivement inutilisable. Pour obtenir plus de détails, communiquez avec votre fournisseur de services.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"Il est"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"douze h."</item>
     <item msgid="7389464214252023751">"Une h."</item>
diff --git a/packages/SystemUI/res-keyguard/values-fr/strings.xml b/packages/SystemUI/res-keyguard/values-fr/strings.xml
index cde5e68..cf4f2d0 100644
--- a/packages/SystemUI/res-keyguard/values-fr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-fr/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="one">La carte SIM est maintenant désactivée. Saisissez le code PUK pour continuer. Il vous reste <xliff:g id="_NUMBER_1">%d</xliff:g> tentative avant que votre carte SIM ne devienne définitivement inutilisable. Pour de plus amples informations, veuillez contacter votre opérateur.</item>
       <item quantity="other">La carte SIM est maintenant désactivée. Saisissez le code PUK pour continuer. Il vous reste <xliff:g id="_NUMBER_1">%d</xliff:g> tentatives avant que votre carte SIM ne devienne définitivement inutilisable. Pour de plus amples informations, veuillez contacter votre opérateur.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"Il est"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"douze heures"</item>
     <item msgid="7389464214252023751">"une heure"</item>
diff --git a/packages/SystemUI/res-keyguard/values-gl/strings.xml b/packages/SystemUI/res-keyguard/values-gl/strings.xml
index 6d85cdb..810a75b 100644
--- a/packages/SystemUI/res-keyguard/values-gl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-gl/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="other">A SIM está desactivada. Introduce o código PUK para continuar. Quédanche <xliff:g id="_NUMBER_1">%d</xliff:g> intentos antes de que a SIM quede inutilizable para sempre. Contacta co operador para obter información.</item>
       <item quantity="one">A SIM está desactivada. Introduce o código PUK para continuar. Quédache <xliff:g id="_NUMBER_0">%d</xliff:g> intento antes de que a SIM quede inutilizable para sempre. Contacta co operador para obter información.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"Hora:"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"Doce"</item>
     <item msgid="7389464214252023751">"Unha"</item>
diff --git a/packages/SystemUI/res-keyguard/values-gu/strings.xml b/packages/SystemUI/res-keyguard/values-gu/strings.xml
index d9fdf03..538b100 100644
--- a/packages/SystemUI/res-keyguard/values-gu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-gu/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="one">સિમ હવે બંધ કરેલ છે. ચાલુ રાખવા માટે PUK કોડ દાખલ કરો. સિમ કાયમીરૂપે બિનઉપયોગી બની જાય એ પહેલાં તમારી પાસે <xliff:g id="_NUMBER_1">%d</xliff:g> પ્રયાસ બાકી છે. વિગતો માટે કૅરિઅરનો સંપર્ક કરો.</item>
       <item quantity="other">સિમ હવે બંધ કરેલ છે. ચાલુ રાખવા માટે PUK કોડ દાખલ કરો. સિમ કાયમીરૂપે બિનઉપયોગી બની જાય એ પહેલાં તમારી પાસે <xliff:g id="_NUMBER_1">%d</xliff:g> પ્રયાસો બાકી છે. વિગતો માટે કૅરિઅરનો સંપર્ક કરો.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"સમય છે"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"બાર"</item>
     <item msgid="7389464214252023751">"એક"</item>
diff --git a/packages/SystemUI/res-keyguard/values-hi/strings.xml b/packages/SystemUI/res-keyguard/values-hi/strings.xml
index b004cde..f03ddd4 100644
--- a/packages/SystemUI/res-keyguard/values-hi/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hi/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="one">सिम बंद कर दिया गया है. जारी रखने के लिए PUK कोड डालें. आपके पास <xliff:g id="_NUMBER_1">%d</xliff:g> मौके बचे हैं, उसके बाद, सिम हमेशा के लिए काम करना बंद कर देगा. जानकारी के लिए, मोबाइल और इंटरनेट सेवा देने वाली कंपनी से संपर्क करें.</item>
       <item quantity="other">सिम बंद कर दिया गया है. जारी रखने के लिए PUK कोड डालें. आपके पास <xliff:g id="_NUMBER_1">%d</xliff:g> मौके बचे हैं, उसके बाद, सिम हमेशा के लिए काम करना बंद कर देगा. जानकारी के लिए, मोबाइल और इंटरनेट सेवा देने वाली कंपनी से संपर्क करें.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"यह"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"बारह"</item>
     <item msgid="7389464214252023751">"एक"</item>
diff --git a/packages/SystemUI/res-keyguard/values-hr/strings.xml b/packages/SystemUI/res-keyguard/values-hr/strings.xml
index c99b646..2839453 100644
--- a/packages/SystemUI/res-keyguard/values-hr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hr/strings.xml
@@ -158,7 +158,7 @@
       <item quantity="few">SIM je sada onemogućen. Unesite PUK kôd da biste nastavili. Imate još <xliff:g id="_NUMBER_1">%d</xliff:g> pokušaja prije nego što SIM kartica postane trajno neupotrebljiva. Više informacija zatražite od mobilnog operatera.</item>
       <item quantity="other">SIM je sada onemogućen. Unesite PUK kôd da biste nastavili. Imate još <xliff:g id="_NUMBER_1">%d</xliff:g> pokušaja prije nego što SIM kartica postane trajno neupotrebljiva. Više informacija zatražite od mobilnog operatera.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"Sada je"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"Dvanaest"</item>
     <item msgid="7389464214252023751">"Jedan"</item>
diff --git a/packages/SystemUI/res-keyguard/values-hu/strings.xml b/packages/SystemUI/res-keyguard/values-hu/strings.xml
index 4eb8bc8..de22c02 100644
--- a/packages/SystemUI/res-keyguard/values-hu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hu/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="other">A SIM-kártya le van tiltva. A folytatáshoz adja meg a PUK-kódot. Még <xliff:g id="_NUMBER_1">%d</xliff:g> próbálkozása van, mielőtt végleg használhatatlanná válik a SIM-kártya. További információért forduljon a szolgáltatóhoz.</item>
       <item quantity="one">A SIM-kártya le van tiltva. A folytatáshoz adja meg a PUK-kódot. Még <xliff:g id="_NUMBER_0">%d</xliff:g> próbálkozása van, mielőtt végleg használhatatlanná válik a SIM-kártya. További információért forduljon a szolgáltatóhoz.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"Az idő:"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"Tizenkettő"</item>
     <item msgid="7389464214252023751">"Egy"</item>
diff --git a/packages/SystemUI/res-keyguard/values-hy/strings.xml b/packages/SystemUI/res-keyguard/values-hy/strings.xml
index 5d9a2c0..2c10437 100644
--- a/packages/SystemUI/res-keyguard/values-hy/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-hy/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="one">SIM քարտն անջատված է: Շարունակելու համար մուտքագրեք PUK կոդը: Մնացել է <xliff:g id="_NUMBER_1">%d</xliff:g> փորձ, որից հետո SIM քարտն այլևս հնարավոր չի լինի օգտագործել: Մանրամասների համար դիմեք օպերատորին:</item>
       <item quantity="other">SIM քարտն անջատված է: Շարունակելու համար մուտքագրեք PUK կոդը: Մնացել է <xliff:g id="_NUMBER_1">%d</xliff:g> փորձ, որից հետո SIM քարտն այլևս հնարավոր չի լինի օգտագործել: Մանրամասների համար դիմեք օպերատորին:</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"Ժամն է՝"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"տասներկու"</item>
     <item msgid="7389464214252023751">"մեկ"</item>
diff --git a/packages/SystemUI/res-keyguard/values-in/strings.xml b/packages/SystemUI/res-keyguard/values-in/strings.xml
index 603b4c2..0cd1382 100644
--- a/packages/SystemUI/res-keyguard/values-in/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-in/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="other">SIM kini dinonaktifkan. Masukkan kode PUK untuk melanjutkan. Tersisa <xliff:g id="_NUMBER_1">%d</xliff:g> percobaan sebelum SIM tidak dapat digunakan secara permanen. Hubungi operator untuk mengetahui detailnya.</item>
       <item quantity="one">SIM kini dinonaktifkan. Masukkan kode PUK untuk melanjutkan. Tersisa <xliff:g id="_NUMBER_0">%d</xliff:g> percobaan sebelum SIM tidak dapat digunakan secara permanen. Hubungi operator untuk mengetahui detailnya.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"Pukul"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"Dua Belas"</item>
     <item msgid="7389464214252023751">"Satu"</item>
diff --git a/packages/SystemUI/res-keyguard/values-is/strings.xml b/packages/SystemUI/res-keyguard/values-is/strings.xml
index 71f2078..dd9785d 100644
--- a/packages/SystemUI/res-keyguard/values-is/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-is/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="one">SIM-kortið er nú óvirkt. Sláðu inn PUK-númer til að halda áfram. Það er <xliff:g id="_NUMBER_1">%d</xliff:g> tilraun eftir þar til SIM-kortið verður ónothæft til frambúðar. Hafðu samband við símafyrirtækið til að fá upplýsingar.</item>
       <item quantity="other">SIM-kortið er nú óvirkt. Sláðu inn PUK-númer til að halda áfram. Það eru <xliff:g id="_NUMBER_1">%d</xliff:g> tilraunir eftir þar til SIM-kortið verður ónothæft til frambúðar. Hafðu samband við símafyrirtækið til að fá upplýsingar.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"Hún er"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"Tólf"</item>
     <item msgid="7389464214252023751">"Eitt"</item>
diff --git a/packages/SystemUI/res-keyguard/values-it/strings.xml b/packages/SystemUI/res-keyguard/values-it/strings.xml
index e0b55b3..ac2375f 100644
--- a/packages/SystemUI/res-keyguard/values-it/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-it/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="other">La scheda SIM è ora disattivata. Inserisci il codice PUK per continuare. Hai ancora <xliff:g id="_NUMBER_1">%d</xliff:g> tentativi a disposizione prima che la SIM diventi definitivamente inutilizzabile. Per informazioni dettagliate, contatta l\'operatore.</item>
       <item quantity="one">La scheda SIM è ora disattivata. Inserisci il codice PUK per continuare. Hai ancora <xliff:g id="_NUMBER_0">%d</xliff:g> tentativo a disposizione prima che la SIM diventi definitivamente inutilizzabile. Per informazioni dettagliate, contatta l\'operatore.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"Ora"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"Dodici"</item>
     <item msgid="7389464214252023751">"Una"</item>
diff --git a/packages/SystemUI/res-keyguard/values-iw/strings.xml b/packages/SystemUI/res-keyguard/values-iw/strings.xml
index 509c463..0fadaff 100644
--- a/packages/SystemUI/res-keyguard/values-iw/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-iw/strings.xml
@@ -166,7 +166,7 @@
       <item quantity="other">‏כרטיס ה-SIM מושבת כעת. יש להזין קוד PUK כדי להמשיך. נותרו לך <xliff:g id="_NUMBER_1">%d</xliff:g> ניסיונות נוספים לפני שכרטיס ה-SIM ינעל לצמיתות. למידע נוסף, ניתן לפנות לספק שלך.</item>
       <item quantity="one">‏כרטיס ה-SIM מושבת כעת. יש להזין קוד PUK כדי להמשיך. נותר לך <xliff:g id="_NUMBER_0">%d</xliff:g> ניסיון נוסף לפני שכרטיס ה-SIM ינעל לצמיתות. למידע נוסף, ניתן לפנות לספק שלך.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"השעה"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"שתים-עשרה"</item>
     <item msgid="7389464214252023751">"אחת"</item>
diff --git a/packages/SystemUI/res-keyguard/values-ja/strings.xml b/packages/SystemUI/res-keyguard/values-ja/strings.xml
index 343d557..b0514ef 100644
--- a/packages/SystemUI/res-keyguard/values-ja/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ja/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="other">SIM が無効になりました。続行するには PUK コードを入力してください。入力できるのはあと <xliff:g id="_NUMBER_1">%d</xliff:g> 回です。この回数を超えると SIM は完全に使用できなくなります。詳しくは携帯通信会社にお問い合わせください。</item>
       <item quantity="one">SIM が無効になりました。続行するには PUK コードを入力してください。入力できるのはあと <xliff:g id="_NUMBER_0">%d</xliff:g> 回です。この回数を超えると SIM は完全に使用できなくなります。詳しくは携帯通信会社にお問い合わせください。</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"時刻:"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"12"</item>
     <item msgid="7389464214252023751">"1"</item>
diff --git a/packages/SystemUI/res-keyguard/values-ka/strings.xml b/packages/SystemUI/res-keyguard/values-ka/strings.xml
index 9118e56..9290874 100644
--- a/packages/SystemUI/res-keyguard/values-ka/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ka/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="other">SIM ბარათი ახლა დეაქტივირებულია. გასაგრძელებლად შეიყვანეთ PUK-კოდი. თქვენ დაგრჩათ <xliff:g id="_NUMBER_1">%d</xliff:g> მცდელობა, სანამ SIM სამუდამოდ გამოუსადეგარი გახდება. დეტალური ინფორმაციისთვის დაუკავშირდით თქვენს ოპერატორს.</item>
       <item quantity="one">SIM ბარათი ახლა დეაქტივირებულია. გასაგრძელებლად შეიყვანეთ PUK-კოდი. თქვენ დაგრჩათ <xliff:g id="_NUMBER_0">%d</xliff:g> მცდელობა, სანამ SIM სამუდამოდ გამოუსადეგარი გახდება. დეტალური ინფორმაციისთვის დაუკავშირდით თქვენს ოპერატორს.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"ახლაა"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"თორმეტი"</item>
     <item msgid="7389464214252023751">"ერთი"</item>
diff --git a/packages/SystemUI/res-keyguard/values-kk/strings.xml b/packages/SystemUI/res-keyguard/values-kk/strings.xml
index 2270c92..f1d6449 100644
--- a/packages/SystemUI/res-keyguard/values-kk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-kk/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="other">SIM картасы өшірілді. Жалғастыру үшін PUK кодын енгізіңіз. <xliff:g id="_NUMBER_1">%d</xliff:g> мүмкіндік қалды, одан кейін SIM картасы біржола құлыпталады. Толығырақ мәліметті оператордан алыңыз.</item>
       <item quantity="one">SIM картасы өшірілді. Жалғастыру үшін PUK кодын енгізіңіз. <xliff:g id="_NUMBER_0">%d</xliff:g> мүмкіндік қалды, одан кейін SIM картасы біржола құлыпталады. Толығырақ мәліметті оператордан алыңыз.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"Қазір"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"Он екі"</item>
     <item msgid="7389464214252023751">"Бір"</item>
diff --git a/packages/SystemUI/res-keyguard/values-km/strings.xml b/packages/SystemUI/res-keyguard/values-km/strings.xml
index 80b124a..f4795b6 100644
--- a/packages/SystemUI/res-keyguard/values-km/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-km/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="other">ឥឡូវនេះស៊ីមត្រូវបានបិទ។ សូមបញ្ចូលកូដ PUK ដើម្បីបន្ត។ អ្នកនៅសល់ការព្យាយាម <xliff:g id="_NUMBER_1">%d</xliff:g> ដងទៀត​មុនពេល​ស៊ីម​មិនអាច​ប្រើបាន​ជា​អចិន្ត្រៃយ៍។ ទាក់ទង​ទៅ​ក្រុមហ៊ុន​សេវា​ទូរសព្ទ​សម្រាប់ព័ត៌មានលម្អិត។</item>
       <item quantity="one">ឥឡូវនេះស៊ីមត្រូវបានបិទ។ សូមបញ្ចូលកូដ PUK ដើម្បីបន្ត។ អ្នកនៅសល់ការព្យាយាម <xliff:g id="_NUMBER_0">%d</xliff:g> ដងទៀតមុនពេលស៊ីមមិនអាចប្រើបានជាអចិន្ត្រៃយ៍។ ទាក់ទង​ទៅ​ក្រុមហ៊ុន​សេវា​ទូរសព្ទ​សម្រាប់​ព័ត៌មាន​លម្អិត។</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"វា​ជា"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"ដប់ពីរ"</item>
     <item msgid="7389464214252023751">"មួយ"</item>
diff --git a/packages/SystemUI/res-keyguard/values-kn/strings.xml b/packages/SystemUI/res-keyguard/values-kn/strings.xml
index f48d606..6f83dde 100644
--- a/packages/SystemUI/res-keyguard/values-kn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-kn/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="one">ಸಿಮ್ ಅನ್ನು ಈಗ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ. ಮುಂದುವರಿಸಲು PUK ಕೋಡ್ ನಮೂದಿಸಿ. ಸಿಮ್ ಶಾಶ್ವತವಾಗಿ ನಿಷ್ಪ್ರಯೋಜಕವಾಗುವ ಮುನ್ನ ನಿಮ್ಮಲ್ಲಿ <xliff:g id="_NUMBER_1">%d</xliff:g> ಪ್ರಯತ್ನಗಳು ಬಾಕಿ ಉಳಿದಿವೆ. ವಿವರಗಳಿಗಾಗಿ ವಾಹಕವನ್ನು ಸಂಪರ್ಕಿಸಿ.</item>
       <item quantity="other">ಸಿಮ್ ಅನ್ನು ಈಗ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ. ಮುಂದುವರಿಸಲು PUK ಕೋಡ್ ನಮೂದಿಸಿ. ಸಿಮ್ ಶಾಶ್ವತವಾಗಿ ನಿಷ್ಪ್ರಯೋಜಕವಾಗುವ ಮುನ್ನ ನಿಮ್ಮಲ್ಲಿ <xliff:g id="_NUMBER_1">%d</xliff:g> ಪ್ರಯತ್ನಗಳು ಬಾಕಿ ಉಳಿದಿವೆ. ವಿವರಗಳಿಗಾಗಿ ವಾಹಕವನ್ನು ಸಂಪರ್ಕಿಸಿ.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"ಇದು"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"ಹನ್ನೆರಡು"</item>
     <item msgid="7389464214252023751">"ಒಂದು"</item>
diff --git a/packages/SystemUI/res-keyguard/values-ko/strings.xml b/packages/SystemUI/res-keyguard/values-ko/strings.xml
index 0466009..1651be7 100644
--- a/packages/SystemUI/res-keyguard/values-ko/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ko/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="other">SIM이 사용 중지되었습니다. 계속하려면 PUK 코드를 입력하세요. <xliff:g id="_NUMBER_1">%d</xliff:g>번 더 실패하면 SIM을 완전히 사용할 수 없게 됩니다. 자세한 내용은 이동통신사에 문의하세요.</item>
       <item quantity="one">SIM이 사용 중지되었습니다. 계속하려면 PUK 코드를 입력하세요. <xliff:g id="_NUMBER_0">%d</xliff:g>번 더 실패하면 SIM을 완전히 사용할 수 없게 됩니다. 자세한 내용은 이동통신사에 문의하세요.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"현재 시각:"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"열두 시"</item>
     <item msgid="7389464214252023751">"한 시"</item>
diff --git a/packages/SystemUI/res-keyguard/values-ky/strings.xml b/packages/SystemUI/res-keyguard/values-ky/strings.xml
index eca9b22..6d0f2ff 100644
--- a/packages/SystemUI/res-keyguard/values-ky/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ky/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="other">SIM-карта азыр жарактан чыкты. Улантуу үчүн PUK-кодду киргизиңиз. SIM-картанын биротоло жарактан чыгарына <xliff:g id="_NUMBER_1">%d</xliff:g> аракет калды. Чоо-жайын билүү үчүн байланыш операторуна кайрылыңыз.</item>
       <item quantity="one">SIM-карта азыр жарактан чыкты. Улантуу үчүн PUK-кодду киргизиңиз. SIM-картанын биротоло жарактан чыгаарына <xliff:g id="_NUMBER_0">%d</xliff:g> аракет калды. Чоо-жайын билүү үчүн байланыш операторуна кайрылыңыз.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"Саат"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"Он эки"</item>
     <item msgid="7389464214252023751">"Бир"</item>
diff --git a/packages/SystemUI/res-keyguard/values-lo/strings.xml b/packages/SystemUI/res-keyguard/values-lo/strings.xml
index bd6e53d..23f179e 100644
--- a/packages/SystemUI/res-keyguard/values-lo/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-lo/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="other">ຕອນນີ້ປິດການນຳໃຊ້ SIM ແລ້ວ. ໃສ່ລະຫັດ PUK ເພື່ອດຳເນີນການຕໍ່. ທ່ານສາມາດລອງໄດ້ອີກ <xliff:g id="_NUMBER_1">%d</xliff:g> ເທື່ອກ່ອນທີ່ SIM ຈະບໍ່ສາມາດໃຊ້ໄດ້ຖາວອນ. ກະລຸນາຕິດຕໍ່ຜູ້ໃຫ້ບໍລິການສຳລັບລາຍລະອຽດ.</item>
       <item quantity="one">ຕອນນີ້ປິດການນຳໃຊ້ SIM ແລ້ວ. ໃສ່ລະຫັດ PUK ເພື່ອດຳເນີນການຕໍ່. ທ່ານສາມາດລອງໄດ້ອີກ <xliff:g id="_NUMBER_0">%d</xliff:g> ເທື່ອກ່ອນທີ່ SIM ຈະບໍ່ສາມາດໃຊ້ໄດ້ຖາວອນ. ກະລຸນາຕິດຕໍ່ຜູ້ໃຫ້ບໍລິການສຳລັບລາຍລະອຽດ.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"ມັນແມ່ນ"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"ສິບສອງ"</item>
     <item msgid="7389464214252023751">"ໜຶ່ງ"</item>
diff --git a/packages/SystemUI/res-keyguard/values-lt/strings.xml b/packages/SystemUI/res-keyguard/values-lt/strings.xml
index 6df93d8..9e4d169 100644
--- a/packages/SystemUI/res-keyguard/values-lt/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-lt/strings.xml
@@ -166,7 +166,7 @@
       <item quantity="many">SIM kortelė dabar yra išjungta. Jei norite tęsti, įveskite PUK kodą. Jums liko <xliff:g id="_NUMBER_1">%d</xliff:g> bandymo. Paskui visiškai nebegalėsite naudoti SIM kortelės. Jei reikia išsamios informacijos, susisiekite su operatoriumi.</item>
       <item quantity="other">SIM kortelė dabar yra išjungta. Jei norite tęsti, įveskite PUK kodą. Jums liko <xliff:g id="_NUMBER_1">%d</xliff:g> bandymų. Paskui visiškai nebegalėsite naudoti SIM kortelės. Jei reikia išsamios informacijos, susisiekite su operatoriumi.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"Dabar"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"Dvylika"</item>
     <item msgid="7389464214252023751">"Pirma"</item>
diff --git a/packages/SystemUI/res-keyguard/values-lv/strings.xml b/packages/SystemUI/res-keyguard/values-lv/strings.xml
index d906176..9ea4143 100644
--- a/packages/SystemUI/res-keyguard/values-lv/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-lv/strings.xml
@@ -158,7 +158,7 @@
       <item quantity="one">SIM karte tagad ir atspējota. Ievadiet PUK kodu, lai turpinātu. Varat mēģināt vēl <xliff:g id="_NUMBER_1">%d</xliff:g> reizi. Kļūdas gadījumā SIM karti vairs nevarēs izmantot. Lai iegūtu detalizētu informāciju, sazinieties ar mobilo sakaru operatoru.</item>
       <item quantity="other">SIM karte tagad ir atspējota. Ievadiet PUK kodu, lai turpinātu. Varat mēģināt vēl <xliff:g id="_NUMBER_1">%d</xliff:g> reizes. Kļūdas gadījumā SIM karti vairs nevarēs izmantot. Lai iegūtu detalizētu informāciju, sazinieties ar mobilo sakaru operatoru.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"Laiks:"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"Divpadsmit"</item>
     <item msgid="7389464214252023751">"Viens"</item>
diff --git a/packages/SystemUI/res-keyguard/values-mk/strings.xml b/packages/SystemUI/res-keyguard/values-mk/strings.xml
index 221b997..e48b93d 100644
--- a/packages/SystemUI/res-keyguard/values-mk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-mk/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="one">SIM-картичката сега е оневозможена. Внесете PUK-код за да продолжите. Ви преостанува уште <xliff:g id="_NUMBER_1">%d</xliff:g> обид пред SIM-картичката да стане трајно неупотреблива. Контактирајте го операторот за детали.</item>
       <item quantity="other">SIM-картичката сега е оневозможена. Внесете PUK-код за да продолжите. Ви преостануваат уште <xliff:g id="_NUMBER_1">%d</xliff:g> обиди пред SIM-картичката да стане трајно неупотреблива. Контактирајте го операторот за детали.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"Сега е"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"Дванаесет"</item>
     <item msgid="7389464214252023751">"Еден"</item>
diff --git a/packages/SystemUI/res-keyguard/values-ml/strings.xml b/packages/SystemUI/res-keyguard/values-ml/strings.xml
index e664288..37ce007 100644
--- a/packages/SystemUI/res-keyguard/values-ml/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ml/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="other">സിം ഇപ്പോൾ പ്രവർത്തനരഹിതമാക്കി. തുടരുന്നതിന് PUK കോഡ് നൽകുക. സിം ശാശ്വതമായി ഉപയോഗശൂന്യമാകുന്നതിന് മുമ്പായി <xliff:g id="_NUMBER_1">%d</xliff:g> ശ്രമങ്ങൾ കൂടി ശേഷിക്കുന്നു. വിശദാംശങ്ങൾക്ക് കാരിയറുമായി ബന്ധപ്പെടുക.</item>
       <item quantity="one">സിം ഇപ്പോൾ പ്രവർത്തനരഹിതമാക്കി. തുടരുന്നതിന് PUK കോഡ് നൽകുക. സിം ശാശ്വതമായി ഉപയോഗശൂന്യമാകുന്നതിന് മുമ്പായി <xliff:g id="_NUMBER_0">%d</xliff:g> ശ്രമം കൂടി ശേഷിക്കുന്നു. വിശദാംശങ്ങൾക്ക് കാരിയറുമായി ബന്ധപ്പെടുക.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"സമയം"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"പന്ത്രണ്ട്"</item>
     <item msgid="7389464214252023751">"ഒന്ന്"</item>
diff --git a/packages/SystemUI/res-keyguard/values-mn/strings.xml b/packages/SystemUI/res-keyguard/values-mn/strings.xml
index e418731..86da688 100644
--- a/packages/SystemUI/res-keyguard/values-mn/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-mn/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="other">SIM-г идэвхгүй болголоо. Үргэлжлүүлэхийн тулд PUK кодыг оруулна уу. Таны SIM бүрмөсөн хүчингүй болох хүртэл <xliff:g id="_NUMBER_1">%d</xliff:g> оролдлого үлдлээ. Дэлгэрэнгүй мэдээлэл авахын тулд оператор компанитайгаа холбогдоно уу.</item>
       <item quantity="one">SIM-г идэвхгүй болголоо. Үргэлжлүүлэхийн тулд PUK кодыг оруулна уу. Таны SIM бүрмөсөн хүчингүй болох хүртэл <xliff:g id="_NUMBER_0">%d</xliff:g> оролдлого үлдлээ. Дэлгэрэнгүй мэдээлэл авахын тулд оператор компанитайгаа холбогдоно уу.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"Одоо"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"Арван хоёр"</item>
     <item msgid="7389464214252023751">"Нэг"</item>
diff --git a/packages/SystemUI/res-keyguard/values-mr/strings.xml b/packages/SystemUI/res-keyguard/values-mr/strings.xml
index 9d83e93..ea0c0bb 100644
--- a/packages/SystemUI/res-keyguard/values-mr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-mr/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="one">सिम आता बंद केलेले आहे. सुरू ठेवण्यासाठी PUK कोड टाका. सिम कायमचे बंद होण्याआधी तुमच्याकडे <xliff:g id="_NUMBER_1">%d</xliff:g> प्रयत्न शिल्लक आहे. तपशीलांसाठी वाहकाशी संपर्क साधा.</item>
       <item quantity="other">सिम आता बंद केलेले आहे. सुरू ठेवण्यासाठी PUK कोड टाका. सिम कायमचे बंद होण्याआधी तुमच्याकडे <xliff:g id="_NUMBER_1">%d</xliff:g> प्रयत्न शिल्लक आहेत. तपशीलांसाठी वाहकाशी संपर्क साधा.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"हे आहे"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"बारा"</item>
     <item msgid="7389464214252023751">"एक"</item>
diff --git a/packages/SystemUI/res-keyguard/values-ms/strings.xml b/packages/SystemUI/res-keyguard/values-ms/strings.xml
index 1c82f7c..03dca91 100644
--- a/packages/SystemUI/res-keyguard/values-ms/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ms/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="other">Kini SIM dilumpuhkan. Masukkan kod PUK untuk meneruskan. Tinggal <xliff:g id="_NUMBER_1">%d</xliff:g> percubaan sebelum SIM tidak boleh digunakan secara kekal. Hubungi pembawa untuk mendapatkan butiran.</item>
       <item quantity="one">Kini SIM dilumpuhkan. Masukkan kod PUK untuk meneruskan. Tinggal <xliff:g id="_NUMBER_0">%d</xliff:g> percubaan sebelum SIM tidak boleh digunakan secara kekal. Hubungi pembawa untuk mendapatkan butiran.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"Pukul"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"Dua bls"</item>
     <item msgid="7389464214252023751">"Satu"</item>
diff --git a/packages/SystemUI/res-keyguard/values-my/strings.xml b/packages/SystemUI/res-keyguard/values-my/strings.xml
index efdd779..a468a85 100644
--- a/packages/SystemUI/res-keyguard/values-my/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-my/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="other">ဆင်းမ်ကဒ်သည် ယခု ပိတ်သွားပါပြီ။ ရှေ့ဆက်ရန် PUK ကုဒ်ကို ထည့်ပါ။ ဆင်းမ်ကဒ် အပြီးပိတ်မသွားမီ သင့်တွင် <xliff:g id="_NUMBER_1">%d</xliff:g> ကြိမ် စမ်းသပ်ခွင့် ကျန်ပါသေးသည်။ အသေးစိတ်အချက်များအတွက် ဝန်ဆောင်မှုပေးသူကို ဆက်သွယ်ပါ။</item>
       <item quantity="one">ဆင်းမ်ကဒ်သည် ယခု ပိတ်သွားပါပြီ။ ရှေ့ဆက်ရန် PUK ကုဒ်ကို ထည့်ပါ။ ဆင်းမ်ကဒ် အပြီးပိတ်မသွားမီ သင့်တွင် <xliff:g id="_NUMBER_0">%d</xliff:g> ကြိမ် စမ်းသပ်ခွင့် ကျန်ပါသေးသည်။ အသေးစိတ်အချက်များအတွက် ဝန်ဆောင်မှုပေးသူကို ဆက်သွယ်ပါ။</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"ယခု"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"ဆယ့်နှစ်"</item>
     <item msgid="7389464214252023751">"တစ်"</item>
diff --git a/packages/SystemUI/res-keyguard/values-nb/strings.xml b/packages/SystemUI/res-keyguard/values-nb/strings.xml
index 17704c4..fcf06eb 100644
--- a/packages/SystemUI/res-keyguard/values-nb/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-nb/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="other">SIM-kortet er deaktivert nå. Skriv inn PUK-koden for å fortsette. Du har <xliff:g id="_NUMBER_1">%d</xliff:g> forsøk igjen før SIM-kortet blir permanent ubrukelig. Kontakt operatøren for å få vite mer.</item>
       <item quantity="one">SIM-kortet er deaktivert nå. Skriv inn PUK-koden for å fortsette. Du har <xliff:g id="_NUMBER_0">%d</xliff:g> forsøk igjen før SIM-kortet blir permanent ubrukelig. Kontakt operatøren for å få vite mer.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"Klokken"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"Tolv"</item>
     <item msgid="7389464214252023751">"Ett"</item>
diff --git a/packages/SystemUI/res-keyguard/values-ne/strings.xml b/packages/SystemUI/res-keyguard/values-ne/strings.xml
index 77bc113..c3d92ab 100644
--- a/packages/SystemUI/res-keyguard/values-ne/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ne/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="other">SIM लाई असक्षम पारिएको छ। जारी राख्न PUK कोड प्रविष्टि गर्नुहोस्। तपाईंसँग <xliff:g id="_NUMBER_1">%d</xliff:g> प्रयासहरू बाँकी छन्, त्यसपछि SIM सदाका लागि प्रयोग गर्न नमिल्ने हुन्छ। विवरणहरूका लागि सेवा प्रदायकलाई सम्पर्क गर्नुहोस्।</item>
       <item quantity="one">SIM लाई असक्षम पारिएको छ। जारी राख्न PUK कोड प्रविष्टि गर्नुहोस्। तपाईंसँग <xliff:g id="_NUMBER_0">%d</xliff:g> प्रयास बाँकी छ, त्यसपछि SIM सदाका लागि प्रयोग गर्न नमिल्ने हुन्छ। विवरणहरूका लागि सेवा प्रदायकलाई सम्पर्क गर्नुहोस्।</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"समय:"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"बाह्र"</item>
     <item msgid="7389464214252023751">"एक"</item>
diff --git a/packages/SystemUI/res-keyguard/values-nl/strings.xml b/packages/SystemUI/res-keyguard/values-nl/strings.xml
index 3bbbb53..b3d65bb7 100644
--- a/packages/SystemUI/res-keyguard/values-nl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-nl/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="other">De simkaart is nu uitgeschakeld. Geef de pukcode op om door te gaan. Je hebt nog <xliff:g id="_NUMBER_1">%d</xliff:g> pogingen over voordat de simkaart definitief onbruikbaar wordt. Neem contact op met je provider voor meer informatie.</item>
       <item quantity="one">De simkaart is nu uitgeschakeld. Geef de pukcode op om door te gaan. Je hebt nog <xliff:g id="_NUMBER_0">%d</xliff:g> poging over voordat de simkaart definitief onbruikbaar wordt. Neem contact op met je provider voor meer informatie.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"Het is"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"Twaalf"</item>
     <item msgid="7389464214252023751">"Eén"</item>
diff --git a/packages/SystemUI/res-keyguard/values-or/strings.xml b/packages/SystemUI/res-keyguard/values-or/strings.xml
index 0db20aa..94c42c4 100644
--- a/packages/SystemUI/res-keyguard/values-or/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-or/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="other">SIM କାର୍ଡକୁ ବର୍ତ୍ତମାନ ଅକ୍ଷମ କରିଦିଆଯାଇଛି। ଜାରି ରଖିବାକୁ PUK କୋଡ୍‍ ଲେଖନ୍ତୁ। ଆଉ <xliff:g id="_NUMBER_1">%d</xliff:g> ଥର ଭୁଲ କୋଡ୍‍ ଲେଖିବା ପରେ SIM କାର୍ଡ ସ୍ଥାୟୀ ଭାବେ ଅନୁପଯୋଗୀ ହୋଇଯିବ। ବିବରଣୀ ପାଇଁ କେରିଅର୍‌ର ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ।</item>
       <item quantity="one">SIM କାର୍ଡକୁ ବର୍ତ୍ତମାନ ଅକ୍ଷମ କରିଦିଆଯାଇଛି। ଜାରି ରଖିବାକୁ PUK କୋଡ୍‍ ଲେଖନ୍ତୁ। ଆଉ <xliff:g id="_NUMBER_0">%d</xliff:g> ଥର ଭୁଲ କୋଡ୍‍ ଲେଖିବା ପରେ SIM କାର୍ଡ ସ୍ଥାୟୀ ଭାବେ ଅନୁପଯୋଗୀ ହୋଇଯିବ। ବିବରଣୀ ପାଇଁ କେରିଅର୍‌ର ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ।</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"ଏବେ"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"ବାର"</item>
     <item msgid="7389464214252023751">"ଏକ"</item>
diff --git a/packages/SystemUI/res-keyguard/values-pa/strings.xml b/packages/SystemUI/res-keyguard/values-pa/strings.xml
index 9fd9b19..9b4e28d 100644
--- a/packages/SystemUI/res-keyguard/values-pa/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pa/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="one">ਸਿਮ ਹੁਣ ਬੰਦ ਹੋ ਗਿਆ ਹੈ। ਜਾਰੀ ਰੱਖਣ ਲਈ PUK ਕੋਡ ਦਾਖਲ ਕਰੋ। ਸਿਮ ਦੇ ਪੱਕੇ ਤੌਰ \'ਤੇ ਬੇਕਾਰ ਹੋ ਜਾਣ ਤੋਂ ਪਹਿਲਾਂ ਤੁਹਾਡੇ ਕੋਲ <xliff:g id="_NUMBER_1">%d</xliff:g> ਕੋਸ਼ਿਸ਼ ਬਾਕੀ ਹੈ। ਵੇਰਵਿਆਂ ਲਈ ਕੈਰੀਅਰ ਨੂੰ ਸੰਪਰਕ ਕਰੋ।</item>
       <item quantity="other">ਸਿਮ ਹੁਣ ਬੰਦ ਹੋ ਗਿਆ ਹੈ। ਜਾਰੀ ਰੱਖਣ ਲਈ PUK ਕੋਡ ਦਾਖਲ ਕਰੋ। ਸਿਮ ਦੇ ਪੱਕੇ ਤੌਰ \'ਤੇ ਬੇਕਾਰ ਹੋ ਜਾਣ ਤੋਂ ਪਹਿਲਾਂ ਤੁਹਾਡੇ ਕੋਲ <xliff:g id="_NUMBER_1">%d</xliff:g> ਕੋਸ਼ਿਸ਼ਾਂ ਬਾਕੀ ਹਨ। ਵੇਰਵਿਆਂ ਲਈ ਕੈਰੀਅਰ ਨੂੰ ਸੰਪਰਕ ਕਰੋ।</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"ਸਮਾਂ"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"ਬਾਰਾਂ"</item>
     <item msgid="7389464214252023751">"ਇੱਕ"</item>
diff --git a/packages/SystemUI/res-keyguard/values-pl/strings.xml b/packages/SystemUI/res-keyguard/values-pl/strings.xml
index 106fab3..2294430 100644
--- a/packages/SystemUI/res-keyguard/values-pl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pl/strings.xml
@@ -166,7 +166,7 @@
       <item quantity="other">Karta SIM została wyłączona. Wpisz kod PUK, by przejść dalej. Masz jeszcze <xliff:g id="_NUMBER_1">%d</xliff:g> próby, zanim karta SIM zostanie trwale zablokowana. Aby uzyskać szczegółowe informacje, skontaktuj się z operatorem.</item>
       <item quantity="one">Karta SIM została wyłączona. Wpisz kod PUK, by przejść dalej. Masz jeszcze <xliff:g id="_NUMBER_0">%d</xliff:g> próbę, zanim karta SIM zostanie trwale zablokowana. Aby uzyskać szczegółowe informacje, skontaktuj się z operatorem.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"Jest"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"Dwanaście"</item>
     <item msgid="7389464214252023751">"Jeden"</item>
diff --git a/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml b/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml
index 3c6a372..56815ca 100644
--- a/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt-rBR/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="one">O chip agora está desativado. Informe o código PUK para continuar. Você tem <xliff:g id="_NUMBER_1">%d</xliff:g> tentativa restante antes de o chip se tornar permanentemente inutilizável. Entre em contato com a operadora para saber mais detalhes.</item>
       <item quantity="other">O chip agora está desativado. Informe o código PUK para continuar. Você tem <xliff:g id="_NUMBER_1">%d</xliff:g> tentativas restantes antes de o chip se tornar permanentemente inutilizável. Entre em contato com a operadora para saber mais detalhes.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"São"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"Doze"</item>
     <item msgid="7389464214252023751">"Uma"</item>
diff --git a/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml b/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
index 4f60187..4e09dc7 100644
--- a/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt-rPT/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="other">O SIM encontra-se desativado. Introduza o código PUK para continuar. Tem mais <xliff:g id="_NUMBER_1">%d</xliff:g> tentativas antes de o cartão SIM ficar permanentemente inutilizável. Contacte o operador para obter mais detalhes.</item>
       <item quantity="one">O SIM encontra-se desativado. Introduza o código PUK para continuar. Tem mais <xliff:g id="_NUMBER_0">%d</xliff:g> tentativa antes de o cartão SIM ficar permanentemente inutilizável. Contacte o operador para obter mais detalhes.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"São"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"Doze"</item>
     <item msgid="7389464214252023751">"Google One"</item>
diff --git a/packages/SystemUI/res-keyguard/values-pt/strings.xml b/packages/SystemUI/res-keyguard/values-pt/strings.xml
index 3c6a372..56815ca 100644
--- a/packages/SystemUI/res-keyguard/values-pt/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-pt/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="one">O chip agora está desativado. Informe o código PUK para continuar. Você tem <xliff:g id="_NUMBER_1">%d</xliff:g> tentativa restante antes de o chip se tornar permanentemente inutilizável. Entre em contato com a operadora para saber mais detalhes.</item>
       <item quantity="other">O chip agora está desativado. Informe o código PUK para continuar. Você tem <xliff:g id="_NUMBER_1">%d</xliff:g> tentativas restantes antes de o chip se tornar permanentemente inutilizável. Entre em contato com a operadora para saber mais detalhes.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"São"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"Doze"</item>
     <item msgid="7389464214252023751">"Uma"</item>
diff --git a/packages/SystemUI/res-keyguard/values-ro/strings.xml b/packages/SystemUI/res-keyguard/values-ro/strings.xml
index 9e4170e..23be62c 100644
--- a/packages/SystemUI/res-keyguard/values-ro/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ro/strings.xml
@@ -158,7 +158,7 @@
       <item quantity="other">Cardul SIM este dezactivat acum. Introduceți codul PUK pentru a continua. V-au mai rămas <xliff:g id="_NUMBER_1">%d</xliff:g> de încercări până când cardul SIM va deveni inutilizabil definitiv. Contactați operatorul pentru detalii.</item>
       <item quantity="one">Cardul SIM este dezactivat acum. Introduceți codul PUK pentru a continua. V-a mai rămas <xliff:g id="_NUMBER_0">%d</xliff:g> încercare până când cardul SIM va deveni inutilizabil definitiv. Contactați operatorul pentru detalii.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"Este"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"Douăsprezece"</item>
     <item msgid="7389464214252023751">"Unu"</item>
diff --git a/packages/SystemUI/res-keyguard/values-ru/strings.xml b/packages/SystemUI/res-keyguard/values-ru/strings.xml
index dd9bc6a..f093748 100644
--- a/packages/SystemUI/res-keyguard/values-ru/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ru/strings.xml
@@ -166,7 +166,7 @@
       <item quantity="many">SIM-карта отключена. Чтобы продолжить, введите PUK-код. Осталось <xliff:g id="_NUMBER_1">%d</xliff:g> попыток. После этого SIM-карта будет заблокирована навсегда. За подробной информацией обратитесь к оператору связи.</item>
       <item quantity="other">SIM-карта отключена. Чтобы продолжить, введите PUK-код. Осталось <xliff:g id="_NUMBER_1">%d</xliff:g> попытки. После этого SIM-карта будет заблокирована навсегда. За подробной информацией обратитесь к оператору связи.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"Сейчас"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"двенадцать"</item>
     <item msgid="7389464214252023751">"один"</item>
diff --git a/packages/SystemUI/res-keyguard/values-si/strings.xml b/packages/SystemUI/res-keyguard/values-si/strings.xml
index 59d2a06..17122a5 100644
--- a/packages/SystemUI/res-keyguard/values-si/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-si/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="one">SIM දැන් අබල කර ඇත. දිගටම කරගෙන යාමට PUK කේතය ඇතුළු කරන්න. SIM ස්ථිරවම භාවිත කළ නොහැකි බවට පත් වීමට පෙර ඔබ සතුව උත්සාහයන් <xliff:g id="_NUMBER_1">%d</xliff:g>ක් ඉතිරිව ඇත. විස්තර සඳහා වාහක සම්බන්ධ කර ගන්න.</item>
       <item quantity="other">SIM දැන් අබල කර ඇත. දිගටම කරගෙන යාමට PUK කේතය ඇතුළු කරන්න. SIM ස්ථිරවම භාවිත කළ නොහැකි බවට පත් වීමට පෙර ඔබ සතුව උත්සාහයන් <xliff:g id="_NUMBER_1">%d</xliff:g>ක් ඉතිරිව ඇත. විස්තර සඳහා වාහක සම්බන්ධ කර ගන්න.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"ඒ"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"දොළහ"</item>
     <item msgid="7389464214252023751">"එක"</item>
diff --git a/packages/SystemUI/res-keyguard/values-sk/strings.xml b/packages/SystemUI/res-keyguard/values-sk/strings.xml
index 0cd5f78..c991903 100644
--- a/packages/SystemUI/res-keyguard/values-sk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sk/strings.xml
@@ -166,7 +166,7 @@
       <item quantity="other">SIM karta je deaktivovaná. Pokračujte zadaním kódu PUK. Zostáva vám <xliff:g id="_NUMBER_1">%d</xliff:g> pokusov, potom sa SIM karta natrvalo zablokuje. Podrobnosti vám poskytne operátor.</item>
       <item quantity="one">SIM karta je deaktivovaná. Pokračujte zadaním kódu PUK. Zostáva vám <xliff:g id="_NUMBER_0">%d</xliff:g> pokus, potom sa SIM karta natrvalo zablokuje. Podrobnosti vám poskytne operátor.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"Práve je"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"Dvanásť"</item>
     <item msgid="7389464214252023751">"Jedna"</item>
diff --git a/packages/SystemUI/res-keyguard/values-sl/strings.xml b/packages/SystemUI/res-keyguard/values-sl/strings.xml
index 52b9d60..1aba2aa 100644
--- a/packages/SystemUI/res-keyguard/values-sl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sl/strings.xml
@@ -166,7 +166,7 @@
       <item quantity="few">Kartica SIM je zdaj onemogočena. Če želite nadaljevati, vnesite kodo PUK. Na voljo imate še <xliff:g id="_NUMBER_1">%d</xliff:g> poskuse. Potem bo kartica SIM postala trajno neuporabna. Za podrobnosti se obrnite na operaterja.</item>
       <item quantity="other">Kartica SIM je zdaj onemogočena. Če želite nadaljevati, vnesite kodo PUK. Na voljo imate še <xliff:g id="_NUMBER_1">%d</xliff:g> poskusov. Potem bo kartica SIM postala trajno neuporabna. Za podrobnosti se obrnite na operaterja.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"Ura je"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"Dvanajst"</item>
     <item msgid="7389464214252023751">"Ena"</item>
diff --git a/packages/SystemUI/res-keyguard/values-sq/strings.xml b/packages/SystemUI/res-keyguard/values-sq/strings.xml
index 1dfb8fd..29819e2 100644
--- a/packages/SystemUI/res-keyguard/values-sq/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sq/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="other">Karta SIM tani është çaktivizuar. Fut kodin PUK për të vazhduar. Të kanë mbetur edhe <xliff:g id="_NUMBER_1">%d</xliff:g> përpjekje përpara se karta SIM të bëhet përgjithmonë e papërdorshme. Kontakto me operatorin për detaje.</item>
       <item quantity="one">Karta SIM tani është çaktivizuar. Fut kodin PUK për të vazhduar. Të ka mbetur edhe <xliff:g id="_NUMBER_0">%d</xliff:g> përpjekje përpara se karta SIM të bëhet përgjithmonë e papërdorshme. Kontakto me operatorin për detaje.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"Ora është"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"Dymbëdhjetë"</item>
     <item msgid="7389464214252023751">"Një"</item>
diff --git a/packages/SystemUI/res-keyguard/values-sr/strings.xml b/packages/SystemUI/res-keyguard/values-sr/strings.xml
index 7bb41e9..d572f96 100644
--- a/packages/SystemUI/res-keyguard/values-sr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sr/strings.xml
@@ -158,7 +158,7 @@
       <item quantity="few">SIM је сада онемогућен. Унесите PUK кôд да бисте наставили. Имате још <xliff:g id="_NUMBER_1">%d</xliff:g> покушаја пре него што SIM постане трајно неупотребљив. Детаљне информације потражите од мобилног оператера.</item>
       <item quantity="other">SIM је сада онемогућен. Унесите PUK кôд да бисте наставили. Имате још <xliff:g id="_NUMBER_1">%d</xliff:g> покушаја пре него што SIM постане трајно неупотребљив. Детаљне информације потражите од мобилног оператера.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"Сада је"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"дванаест"</item>
     <item msgid="7389464214252023751">"један"</item>
diff --git a/packages/SystemUI/res-keyguard/values-sv/strings.xml b/packages/SystemUI/res-keyguard/values-sv/strings.xml
index 2475dc1..6608add 100644
--- a/packages/SystemUI/res-keyguard/values-sv/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sv/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="other">SIM-kortet är inaktiverat. Ange PUK-koden om du vill fortsätta. <xliff:g id="_NUMBER_1">%d</xliff:g> försök återstår innan SIM-kortet blir obrukbart. Kontakta operatören för mer information.</item>
       <item quantity="one">SIM-kortet är inaktiverat. Ange PUK-koden om du vill fortsätta. <xliff:g id="_NUMBER_0">%d</xliff:g> försök återstår innan SIM-kortet blir obrukbart. Kontakta operatören för mer information.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"Hon är"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"Tolv"</item>
     <item msgid="7389464214252023751">"En"</item>
diff --git a/packages/SystemUI/res-keyguard/values-sw/strings.xml b/packages/SystemUI/res-keyguard/values-sw/strings.xml
index 0a1acf2..102db535 100644
--- a/packages/SystemUI/res-keyguard/values-sw/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-sw/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="other">Sasa SIM imefungwa. Weka msimbo wa PUK ili uendelee. Umesalia na majaribio <xliff:g id="_NUMBER_1">%d</xliff:g> kabla ya SIM kuacha kufanya kazi kabisa. Wasiliana na mtoa huduma kwa maelezo.</item>
       <item quantity="one">Sasa SIM imefungwa. Weka msimbo wa PUK ili uendelee. Umesalia na jaribio <xliff:g id="_NUMBER_0">%d</xliff:g> kabla ya SIM kuacha kufanya kazi kabisa. Wasiliana na mtoa huduma kwa maelezo.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"Ni saa"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"Sita"</item>
     <item msgid="7389464214252023751">"Saba"</item>
diff --git a/packages/SystemUI/res-keyguard/values-ta/strings.xml b/packages/SystemUI/res-keyguard/values-ta/strings.xml
index 57a614a..009fb2d 100644
--- a/packages/SystemUI/res-keyguard/values-ta/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ta/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="other">சிம் தற்போது முடக்கப்பட்டுள்ளது. தொடர்வதற்கு, PUK குறியீட்டை உள்ளிடவும். நீங்கள் <xliff:g id="_NUMBER_1">%d</xliff:g> முறை மட்டுமே முயற்சிக்க முடியும். அதன்பிறகு சிம் நிரந்தரமாக முடக்கப்படும். விவரங்களுக்கு, மொபைல் நிறுவனத்தைத் தொடர்புகொள்ளவும்.</item>
       <item quantity="one">சிம் தற்போது முடக்கப்பட்டுள்ளது. தொடர்வதற்கு, PUK குறியீட்டை உள்ளிடவும். நீங்கள் <xliff:g id="_NUMBER_0">%d</xliff:g> முறை மட்டுமே முயற்சிக்க முடியும். அதன்பிறகு சிம் நிரந்தரமாக முடக்கப்படும். விவரங்களுக்கு, மொபைல் நிறுவனத்தைத் தொடர்புகொள்ளவும்.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"அதன்"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"பன்னிரண்டு"</item>
     <item msgid="7389464214252023751">"ஒன்று"</item>
diff --git a/packages/SystemUI/res-keyguard/values-te/strings.xml b/packages/SystemUI/res-keyguard/values-te/strings.xml
index 58880c4..8f4000f 100644
--- a/packages/SystemUI/res-keyguard/values-te/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-te/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="other">SIM ఇప్పుడు నిలిపివేయబడింది. PUK కోడ్‌ను నమోదు చేయండి. SIM శాశ్వతంగా నిరుపయోగం కాకుండా ఉండటానికి మీకు <xliff:g id="_NUMBER_1">%d</xliff:g> ప్రయత్నాలు మిగిలి ఉన్నాయి. వివరాల కోసం కారియర్‌ను సంప్రదించండి.</item>
       <item quantity="one">SIM ఇప్పుడు నిలిపివేయబడింది. PUK కోడ్‌ను నమోదు చేయండి. SIM శాశ్వతంగా నిరుపయోగం కాకుండా ఉండటానికి మీకు <xliff:g id="_NUMBER_0">%d</xliff:g> ప్రయత్నం మిగిలి ఉంది వివరాల కోసం కారియర్‌ను సంప్రదించండి.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"ఇప్పుడు"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"పన్నెండు"</item>
     <item msgid="7389464214252023751">"ఒకటి"</item>
diff --git a/packages/SystemUI/res-keyguard/values-th/strings.xml b/packages/SystemUI/res-keyguard/values-th/strings.xml
index bb52a7f..bb58e20 100644
--- a/packages/SystemUI/res-keyguard/values-th/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-th/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="other">ซิมถูกปิดใช้งานในขณะนี้ โปรดป้อนรหัส PUK เพื่อทำต่อ คุณพยายามได้อีก <xliff:g id="_NUMBER_1">%d</xliff:g> ครั้งก่อนที่ซิมจะไม่สามารถใช้งานได้อย่างถาวร โปรดติดต่อสอบถามรายละเอียดจากผู้ให้บริการ</item>
       <item quantity="one">ซิมถูกปิดใช้งานในขณะนี้ โปรดป้อนรหัส PUK เพื่อทำต่อ คุณพยายามได้อีก <xliff:g id="_NUMBER_0">%d</xliff:g> ครั้งก่อนที่ซิมจะไม่สามารถใช้งานได้อย่างถาวร โปรดติดต่อสอบถามรายละเอียดจากผู้ให้บริการ</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"เวลา"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"สิบสอง"</item>
     <item msgid="7389464214252023751">"หนึ่ง"</item>
diff --git a/packages/SystemUI/res-keyguard/values-tl/strings.xml b/packages/SystemUI/res-keyguard/values-tl/strings.xml
index 1f480f4..ec7b924 100644
--- a/packages/SystemUI/res-keyguard/values-tl/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-tl/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="one">Naka-disable na ang SIM. Ilagay ang PUK code upang magpatuloy. Mayroon kang <xliff:g id="_NUMBER_1">%d</xliff:g> natitirang pagsubok bago tuluyang hindi magamit ang SIM. Makipag-ugnayan sa carrier para sa mga detalye.</item>
       <item quantity="other">Naka-disable na ang SIM. Ilagay ang PUK code upang magpatuloy. Mayroon kang <xliff:g id="_NUMBER_1">%d</xliff:g> na natitirang pagsubok bago tuluyang hindi magamit ang SIM. Makipag-ugnayan sa carrier para sa mga detalye.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"Oras ay"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"Twelve"</item>
     <item msgid="7389464214252023751">"One"</item>
diff --git a/packages/SystemUI/res-keyguard/values-tr/strings.xml b/packages/SystemUI/res-keyguard/values-tr/strings.xml
index 8ff1d88..92b3fb3 100644
--- a/packages/SystemUI/res-keyguard/values-tr/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-tr/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="other">SIM artık devre dışı. Devam etmek için PUK kodunu girin. SIM kalıcı olarak kullanım dışı kalmadan önce <xliff:g id="_NUMBER_1">%d</xliff:g> deneme hakkınız kaldı. Ayrıntılı bilgi için operatörünüzle iletişim kurun.</item>
       <item quantity="one">SIM artık devre dışı. Devam etmek için PUK kodunu girin. SIM kalıcı olarak kullanım dışı kalmadan önce <xliff:g id="_NUMBER_0">%d</xliff:g> deneme hakkınız kaldı. Ayrıntılı bilgi için operatörünüzle iletişim kurun.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"Saat"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"On İki"</item>
     <item msgid="7389464214252023751">"Bir"</item>
diff --git a/packages/SystemUI/res-keyguard/values-uk/strings.xml b/packages/SystemUI/res-keyguard/values-uk/strings.xml
index 3f0982f..2772d07 100644
--- a/packages/SystemUI/res-keyguard/values-uk/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-uk/strings.xml
@@ -166,7 +166,7 @@
       <item quantity="many">SIM-карту заблоковано. Щоб продовжити, введіть PUK-код. Залишилося <xliff:g id="_NUMBER_1">%d</xliff:g> спроб. Після цього SIM-карту буде назавжди заблоковано. Щоб дізнатися більше, зверніться до свого оператора.</item>
       <item quantity="other">SIM-карту заблоковано. Щоб продовжити, введіть PUK-код. Залишилося <xliff:g id="_NUMBER_1">%d</xliff:g> спроби. Після цього SIM-карту буде назавжди заблоковано. Щоб дізнатися більше, зверніться до свого оператора.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"Зараз"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"дванадцята"</item>
     <item msgid="7389464214252023751">"перша"</item>
diff --git a/packages/SystemUI/res-keyguard/values-ur/strings.xml b/packages/SystemUI/res-keyguard/values-ur/strings.xml
index 3c520f9..e9e6709 100644
--- a/packages/SystemUI/res-keyguard/values-ur/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-ur/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="other">‏SIM اب غیر فعال ہے۔ جاری رکھنے کیلئے PUK کوڈ درج کریں۔ SIM کے مستقل طور پر ناقابل استعمال ہونے سے پہلے آپ کے پاس <xliff:g id="_NUMBER_1">%d</xliff:g> کوششیں بچی ہیں۔ تفصیلات کیلئے کیریئر سے رابطہ کریں۔</item>
       <item quantity="one">‏SIM اب غیر فعال ہے۔ جاری رکھنے کیلئے PUK کوڈ درج کریں۔ SIM کے مستقل طور پر ناقابل استعمال ہونے سے پہلے آپ کے پاس <xliff:g id="_NUMBER_0">%d</xliff:g> کوشش بچی ہے۔ تفصیلات کیلئے کیریئر سے رابطہ کریں۔</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"وقت/ابھی"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"بارہ"</item>
     <item msgid="7389464214252023751">"ایک"</item>
diff --git a/packages/SystemUI/res-keyguard/values-uz/strings.xml b/packages/SystemUI/res-keyguard/values-uz/strings.xml
index 640a987..676f7bb9 100644
--- a/packages/SystemUI/res-keyguard/values-uz/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-uz/strings.xml
@@ -152,7 +152,7 @@
       <item quantity="other">SIM karta faolsizlantirildi. Davom etish uchun PUK kodni kiriting. Yana <xliff:g id="_NUMBER_1">%d</xliff:g> marta xato qilsangiz, SIM kartangiz butunlay qulflanadi. Batafsil axborot olish uchun tarmoq operatoriga murojaat qiling.</item>
       <item quantity="one">SIM karta faolsizlantirildi. Davom etish uchun PUK kodni kiriting. Yana <xliff:g id="_NUMBER_0">%d</xliff:g> marta xato qilsangiz, SIM kartangiz butunlay qulflanadi. Batafsil axborot olish uchun tarmoq operatoriga murojaat qiling.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"Hozir"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"Oʻn ikki"</item>
     <item msgid="7389464214252023751">"Bir"</item>
diff --git a/packages/SystemUI/res-keyguard/values-vi/strings.xml b/packages/SystemUI/res-keyguard/values-vi/strings.xml
index 2a62fb8..f2cfb2a 100644
--- a/packages/SystemUI/res-keyguard/values-vi/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-vi/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="other">SIM hiện đã bị tắt. Hãy nhập mã PUK để tiếp tục. Bạn còn <xliff:g id="_NUMBER_1">%d</xliff:g> lần thử trước khi SIM vĩnh viễn không sử dụng được. Hãy liên hệ với nhà cung cấp dịch vụ để biết chi tiết.</item>
       <item quantity="one">SIM hiện đã bị tắt. Hãy nhập mã PUK để tiếp tục. Bạn còn <xliff:g id="_NUMBER_0">%d</xliff:g> lần thử trước khi SIM vĩnh viễn không thể sử dụng được. Hãy liên hệ với nhà cung cấp dịch vụ để biết chi tiết.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"Hiện là"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"Mười hai"</item>
     <item msgid="7389464214252023751">"Một"</item>
diff --git a/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml
index 80fac90..efa5fc3 100644
--- a/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zh-rCN/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="other">SIM 卡现已停用,请输入 PUK 码继续使用。您还可以尝试 <xliff:g id="_NUMBER_1">%d</xliff:g> 次。如果仍不正确,该 SIM 卡将永远无法使用。有关详情,请联系您的运营商。</item>
       <item quantity="one">SIM 卡现已停用,请输入 PUK 码继续使用。您还可以尝试 <xliff:g id="_NUMBER_0">%d</xliff:g> 次。如果仍不正确,该 SIM 卡将永远无法使用。有关详情,请联系您的运营商。</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"时间是"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"十二"</item>
     <item msgid="7389464214252023751">"一"</item>
diff --git a/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml
index 926d601..eeff66a 100644
--- a/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zh-rHK/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="other">SIM 卡已停用。請輸入 PUK 碼以繼續進行。您還可以再試 <xliff:g id="_NUMBER_1">%d</xliff:g> 次。如果仍然輸入錯誤,SIM 卡將永久無法使用。詳情請與流動網絡供應商聯絡。</item>
       <item quantity="one">SIM 卡已停用。請輸入 PUK 碼以繼續進行。您還可以再試 <xliff:g id="_NUMBER_0">%d</xliff:g> 次。如果仍然輸入錯誤,SIM 卡將永久無法使用。詳情請與流動網絡供應商聯絡。</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"現在是"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"十二"</item>
     <item msgid="7389464214252023751">"一"</item>
diff --git a/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml b/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml
index 728f1a9..961ef39 100644
--- a/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zh-rTW/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="other">SIM 卡現在已遭停用。請輸入 PUK 碼以繼續進行。你還可以再試 <xliff:g id="_NUMBER_1">%d</xliff:g> 次,如果仍然失敗,SIM 卡將永久無法使用。詳情請與電信業者聯絡。</item>
       <item quantity="one">SIM 卡現在已遭停用。請輸入 PUK 碼以繼續進行。你還可以再試 <xliff:g id="_NUMBER_0">%d</xliff:g> 次,如果仍然失敗,SIM 卡將永久無法使用。詳情請與電信業者聯絡。</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"時間是"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"十二"</item>
     <item msgid="7389464214252023751">"一"</item>
diff --git a/packages/SystemUI/res-keyguard/values-zu/strings.xml b/packages/SystemUI/res-keyguard/values-zu/strings.xml
index 7e0a03c..2e948b4 100644
--- a/packages/SystemUI/res-keyguard/values-zu/strings.xml
+++ b/packages/SystemUI/res-keyguard/values-zu/strings.xml
@@ -150,7 +150,7 @@
       <item quantity="one">I-SIM manje ikhutshaziwe. Faka ikhodi ye-PUK ukuze uqhubeke. Unemizamo engu-<xliff:g id="_NUMBER_1">%d</xliff:g> esele ngaphambi kokuthi i-SIM ingasebenziseki unaphakade. Xhumana nenkampani yenethiwekhi ngemininingwane.</item>
       <item quantity="other">I-SIM manje ikhutshaziwe. Faka ikhodi ye-PUK ukuze uqhubeke. Unemizamo engu-<xliff:g id="_NUMBER_1">%d</xliff:g> esele ngaphambi kokuthi i-SIM ingasebenziseki unaphakade. Xhumana nenkampani yenethiwekhi ngemininingwane.</item>
     </plurals>
-    <string name="type_clock_header" msgid="4786545441902447636">"Kuyi-"</string>
+    <!-- no translation found for type_clock_header (6782840450655632763) -->
   <string-array name="type_clock_hours">
     <item msgid="3543074812389379830">"Ishumi nambili"</item>
     <item msgid="7389464214252023751">"Kunye"</item>
diff --git a/packages/SystemUI/res/drawable/privacy_chip_bg.xml b/packages/SystemUI/res/drawable/privacy_chip_bg.xml
index 36d0659..f1158ef 100644
--- a/packages/SystemUI/res/drawable/privacy_chip_bg.xml
+++ b/packages/SystemUI/res/drawable/privacy_chip_bg.xml
@@ -17,6 +17,7 @@
 
 <shape xmlns:android="http://schemas.android.com/apk/res/android">
     <solid android:color="#4a4a4a" />
-    <padding android:padding="@dimen/ongoing_appops_chip_bg_padding" />
+    <padding android:paddingTop="@dimen/ongoing_appops_chip_bg_padding"
+        android:paddingBottom="@dimen/ongoing_appops_chip_bg_padding"/>
     <corners android:radius="@dimen/ongoing_appops_chip_bg_corner_radius" />
 </shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/bubble_expanded_view.xml b/packages/SystemUI/res/layout/bubble_expanded_view.xml
index 403d928..f664c05 100644
--- a/packages/SystemUI/res/layout/bubble_expanded_view.xml
+++ b/packages/SystemUI/res/layout/bubble_expanded_view.xml
@@ -14,7 +14,7 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License
   -->
-<com.android.systemui.bubbles.BubbleExpandedViewContainer
+<com.android.systemui.bubbles.BubbleExpandedView
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_height="wrap_content"
     android:layout_width="match_parent"
@@ -93,4 +93,4 @@
 
     </FrameLayout>
 
-</com.android.systemui.bubbles.BubbleExpandedViewContainer>
+</com.android.systemui.bubbles.BubbleExpandedView>
diff --git a/packages/SystemUI/res/layout/ongoing_privacy_chip.xml b/packages/SystemUI/res/layout/ongoing_privacy_chip.xml
index cbdd51b..58fe811 100644
--- a/packages/SystemUI/res/layout/ongoing_privacy_chip.xml
+++ b/packages/SystemUI/res/layout/ongoing_privacy_chip.xml
@@ -29,14 +29,25 @@
     android:orientation="horizontal"
     android:paddingStart="@dimen/ongoing_appops_chip_side_padding"
     android:paddingEnd="@dimen/ongoing_appops_chip_side_padding"
-    android:background="@drawable/privacy_chip_bg"
     android:focusable="true">
 
+        <TextView
+            android:id="@+id/in_use_text"
+            android:layout_height="match_parent"
+            android:layout_width="wrap_content"
+            android:layout_gravity="center_vertical|start"
+            android:layout_marginEnd="@dimen/ongoing_appops_chip_icon_margin_collapsed"
+            android:gravity="center_vertical"
+            android:textAppearance="@style/TextAppearance.StatusBar.Clock"
+            android:textColor="@color/status_bar_clock_color"
+            android:text="@string/ongoing_privacy_chip_in_use"
+            />
+
         <LinearLayout
             android:id="@+id/icons_container"
             android:layout_height="match_parent"
             android:layout_width="wrap_content"
-            android:layout_gravity="center_vertical|start"
+            android:layout_gravity="center_vertical"
             android:gravity="center_vertical"
             />
 
@@ -51,7 +62,7 @@
             android:gravity="center_vertical"
             android:textAppearance="@style/TextAppearance.StatusBar.Clock"
             android:textColor="@color/status_bar_clock_color"
-            android:layout_marginStart="@dimen/ongoing_appops_chip_icon_margin"
-            android:layout_marginEnd="@dimen/ongoing_appops_chip_icon_margin"
+            android:layout_marginStart="@dimen/ongoing_appops_chip_icon_margin_collapsed"
+            android:layout_marginEnd="@dimen/ongoing_appops_chip_icon_margin_collapsed"
         />
 </com.android.systemui.privacy.OngoingPrivacyChip>
\ No newline at end of file
diff --git a/packages/SystemUI/res/raw/image_wallpaper_fragment_shader.glsl b/packages/SystemUI/res/raw/image_wallpaper_fragment_shader.glsl
deleted file mode 100644
index 11d73a9..0000000
--- a/packages/SystemUI/res/raw/image_wallpaper_fragment_shader.glsl
+++ /dev/null
@@ -1,33 +0,0 @@
-precision mediump float;
-
-uniform sampler2D uTexture;
-uniform float uCenterReveal;
-uniform float uReveal;
-uniform float uAod2Opacity;
-uniform int uAodMode;
-varying vec2 vTextureCoordinates;
-
-vec3 luminosity(vec3 color) {
-    float lum = 0.2126 * color.r + 0.7152 * color.g + 0.0722 * color.b;
-    return vec3(lum);
-}
-
-vec4 transform(vec3 diffuse) {
-    // TODO: Add well comments here, tracking on b/123615467.
-    vec3 lum = luminosity(diffuse);
-    diffuse = mix(diffuse, lum, smoothstep(0., uCenterReveal, uReveal));
-    float val = mix(uReveal, uCenterReveal, step(uCenterReveal, uReveal));
-    diffuse = smoothstep(val, 1.0, diffuse);
-    diffuse *= uAod2Opacity * (1. - smoothstep(uCenterReveal, 1., uReveal));
-    return vec4(diffuse.r, diffuse.g, diffuse.b, 1.);
-}
-
-void main() {
-    vec4 fragColor = texture2D(uTexture, vTextureCoordinates);
-    // TODO: Remove the branch logic here, tracking on b/123615467.
-    if (uAodMode != 0) {
-        gl_FragColor = transform(fragColor.rgb);
-    } else {
-        gl_FragColor = fragColor;
-    }
-}
\ No newline at end of file
diff --git a/packages/SystemUI/res/raw/image_wallpaper_vertex_shader.glsl b/packages/SystemUI/res/raw/image_wallpaper_vertex_shader.glsl
deleted file mode 100644
index 4393e2b..0000000
--- a/packages/SystemUI/res/raw/image_wallpaper_vertex_shader.glsl
+++ /dev/null
@@ -1,8 +0,0 @@
-attribute vec4 aPosition;
-attribute vec2 aTextureCoordinates;
-varying vec2 vTextureCoordinates;
-
-void main() {
-    vTextureCoordinates = aTextureCoordinates;
-    gl_Position = aPosition;
-}
\ No newline at end of file
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 053371a..9b765f8 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -879,8 +879,7 @@
       <item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> program gebruik jou <xliff:g id="TYPE_1">%2$s</xliff:g>.</item>
     </plurals>
     <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Het dit"</string>
-    <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
-    <skip />
+    <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Privaatheidsinstellings"</string>
     <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Program wat jou <xliff:g id="TYPES_LIST">%s</xliff:g> gebruik"</string>
     <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Programme wat jou <xliff:g id="TYPES_LIST">%s</xliff:g> gebruik"</string>
     <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensors is af"</string>
     <string name="device_services" msgid="1191212554435440592">"Toesteldienste"</string>
     <string name="music_controls_no_title" msgid="5236895307087002011">"Titelloos"</string>
-    <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+    <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Maak <xliff:g id="APP_NAME">%1$s</xliff:g> oop"</string>
+    <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Maak kennisgewinginstellings oop vir <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
     <skip />
-    <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 8acd1b8..d12ba4c 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -879,8 +879,7 @@
       <item quantity="other"><xliff:g id="NUM_APPS_4">%1$d</xliff:g> መተግበሪያዎች የእርስዎን <xliff:g id="TYPE_5">%2$s</xliff:g> እየተጠቀሙ ነው።</item>
     </plurals>
     <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"ገባኝ"</string>
-    <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
-    <skip />
+    <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"የግላዊነት ቅንብሮች"</string>
     <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"የእርስዎን <xliff:g id="TYPES_LIST">%s</xliff:g> የሚጠቀሙ መተግበሪያዎች"</string>
     <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"የእርስዎን <xliff:g id="TYPES_LIST">%s</xliff:g> የሚጠቀሙ መተግበሪያዎች"</string>
     <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">"፣ "</string>
@@ -895,8 +894,12 @@
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"ዳሳሾች ጠፍተዋል"</string>
     <string name="device_services" msgid="1191212554435440592">"የመሣሪያ አገልግሎቶች"</string>
     <string name="music_controls_no_title" msgid="5236895307087002011">"ርዕስ የለም"</string>
-    <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+    <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"<xliff:g id="APP_NAME">%1$s</xliff:g> ክፈት"</string>
+    <string name="bubbles_settings_button_description" msgid="1940331766151865776">"የማስታወቂያ ቅንብሮች ለ <xliff:g id="APP_NAME">%1$s</xliff:g> ክፈት"</string>
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
     <skip />
-    <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 0312adf..7c08783 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -907,8 +907,7 @@
       <item quantity="one">هناك تطبيق واحد (<xliff:g id="NUM_APPS_0">%1$d</xliff:g>) يستخدِم <xliff:g id="TYPE_1">%2$s</xliff:g>.</item>
     </plurals>
     <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"حسنًا"</string>
-    <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
-    <skip />
+    <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"إعدادات الخصوصية"</string>
     <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"التطبيق الذي يستخدِم <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"التطبيقات التي تستخدِم <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">"، "</string>
@@ -927,8 +926,12 @@
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"إيقاف أجهزة الاستشعار"</string>
     <string name="device_services" msgid="1191212554435440592">"خدمات الأجهزة"</string>
     <string name="music_controls_no_title" msgid="5236895307087002011">"بلا عنوان"</string>
-    <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+    <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"فتح <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="bubbles_settings_button_description" msgid="1940331766151865776">"فتح إعدادات الإشعارات في <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
     <skip />
-    <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index fbaad96..c782d1b 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -899,4 +899,10 @@
     <skip />
     <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
     <skip />
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+    <skip />
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 70608a1..896fe34 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -879,8 +879,7 @@
       <item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> tətbiq <xliff:g id="TYPE_1">%2$s</xliff:g> tətbiqindən istifadə edir.</item>
     </plurals>
     <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Anladım"</string>
-    <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
-    <skip />
+    <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Məxfilik ayarları"</string>
     <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"<xliff:g id="TYPES_LIST">%s</xliff:g> tətbiqindən istifadə edən tətbiq"</string>
     <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"<xliff:g id="TYPES_LIST">%s</xliff:g> tətbiqindən istifadə edən tətbiqlər"</string>
     <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensorlar deaktivdir"</string>
     <string name="device_services" msgid="1191212554435440592">"Cihaz Xidmətləri"</string>
     <string name="music_controls_no_title" msgid="5236895307087002011">"Başlıq yoxdur"</string>
-    <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+    <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"<xliff:g id="APP_NAME">%1$s</xliff:g> tətbiqini açın"</string>
+    <string name="bubbles_settings_button_description" msgid="1940331766151865776">"<xliff:g id="APP_NAME">%1$s</xliff:g> üçün bildiriş ayarlarını açın"</string>
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
     <skip />
-    <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 8a754f3..14ab0a4 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -886,8 +886,7 @@
       <item quantity="other"><xliff:g id="NUM_APPS_4">%1$d</xliff:g> aplikacija koristi dozvolu <xliff:g id="TYPE_5">%2$s</xliff:g>.</item>
     </plurals>
     <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Važi"</string>
-    <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
-    <skip />
+    <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Podešav. privatnosti"</string>
     <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Aplikacija koja koristi dozvole <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Aplikacije koje koriste dozvole <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -903,8 +902,12 @@
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Senzori su isključeni"</string>
     <string name="device_services" msgid="1191212554435440592">"Usluge za uređaje"</string>
     <string name="music_controls_no_title" msgid="5236895307087002011">"Bez naslova"</string>
-    <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+    <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Otvorite <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Otvorite podešavanja obaveštenja za <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
     <skip />
-    <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 3390fcb..0e724fa 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -917,4 +917,10 @@
     <skip />
     <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
     <skip />
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+    <skip />
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 00454dd..c44b3ad 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -879,8 +879,7 @@
       <item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> приложение използва <xliff:g id="TYPE_1">%2$s</xliff:g>.</item>
     </plurals>
     <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Разбрах"</string>
-    <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
-    <skip />
+    <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Поверит.: Настройки"</string>
     <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Приложение, което използва <xliff:g id="TYPES_LIST">%s</xliff:g> ви"</string>
     <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Приложения, които използват <xliff:g id="TYPES_LIST">%s</xliff:g> ви"</string>
     <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Сензорите са изключени"</string>
     <string name="device_services" msgid="1191212554435440592">"Услуги за устройството"</string>
     <string name="music_controls_no_title" msgid="5236895307087002011">"Няма заглавие"</string>
-    <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+    <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Отваряне на „<xliff:g id="APP_NAME">%1$s</xliff:g>“"</string>
+    <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Отваряне на настройките за известията за „<xliff:g id="APP_NAME">%1$s</xliff:g>“"</string>
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
     <skip />
-    <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index b864206..ec7ff6d 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -899,4 +899,10 @@
     <skip />
     <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
     <skip />
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+    <skip />
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index d152831..77069b2 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -888,8 +888,7 @@
       <item quantity="other"><xliff:g id="NUM_APPS_4">%1$d</xliff:g> aplikacija koristi <xliff:g id="TYPE_5">%2$s</xliff:g>.</item>
     </plurals>
     <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Razumijem"</string>
-    <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
-    <skip />
+    <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Postavke privatnosti"</string>
     <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Aplikacija koristi odobrenja <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Aplikacije koriste odobrenja <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -905,8 +904,12 @@
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Senzori su isključeni"</string>
     <string name="device_services" msgid="1191212554435440592">"Usluge uređaja"</string>
     <string name="music_controls_no_title" msgid="5236895307087002011">"Bez naslova"</string>
-    <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+    <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Otvorite aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Otvorite postavke obavijesti za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
     <skip />
-    <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index f41ea3c..1c52610 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -899,4 +899,10 @@
     <skip />
     <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
     <skip />
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+    <skip />
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 4bdc271..735b476 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -915,4 +915,10 @@
     <skip />
     <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
     <skip />
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+    <skip />
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 0c3c253..615338d 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -879,8 +879,7 @@
       <item quantity="other"><xliff:g id="NUM_APPS_4">%1$d</xliff:g> apps anvender din/dit <xliff:g id="TYPE_5">%2$s</xliff:g>.</item>
     </plurals>
     <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"OK"</string>
-    <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
-    <skip />
+    <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Privatlivsindstill."</string>
     <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"App, der anvender din/dit <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Apps, der anvender din/dit <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Deaktiver sensorer"</string>
     <string name="device_services" msgid="1191212554435440592">"Enhedstjenester"</string>
     <string name="music_controls_no_title" msgid="5236895307087002011">"Ingen titel"</string>
-    <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+    <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Åbn <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Åbn notifikationsindstillingerne for <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
     <skip />
-    <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index c21288d..4e2e1e1 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -441,7 +441,7 @@
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Reduzierung der Leistung und Hintergrunddaten"</string>
     <string name="battery_saver_notification_action_text" msgid="132118784269455533">"Energiesparmodus deaktivieren"</string>
     <string name="media_projection_dialog_text" msgid="3071431025448218928">"<xliff:g id="APP_SEEKING_PERMISSION">%s</xliff:g> nimmt alle auf deinem Bildschirm angezeigten Aktivitäten auf."</string>
-    <string name="media_projection_remember_text" msgid="3103510882172746752">"Nicht erneut anzeigen"</string>
+    <string name="media_projection_remember_text" msgid="3103510882172746752">"Nicht mehr anzeigen"</string>
     <string name="clear_all_notifications_text" msgid="814192889771462828">"Alle löschen"</string>
     <string name="manage_notifications_text" msgid="2386728145475108753">"Verwalten"</string>
     <string name="dnd_suppressing_shade_text" msgid="1904574852846769301">"Benachrichtigungen durch \"Bitte nicht stören\" pausiert"</string>
@@ -883,8 +883,7 @@
       <item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> App verwendet gerade: <xliff:g id="TYPE_1">%2$s</xliff:g>.</item>
     </plurals>
     <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"OK"</string>
-    <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
-    <skip />
+    <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Datenschutzeinst."</string>
     <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"App, die <xliff:g id="TYPES_LIST">%s</xliff:g> verwendet"</string>
     <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Apps, die <xliff:g id="TYPES_LIST">%s</xliff:g> verwenden"</string>
     <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -899,8 +898,12 @@
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensoren aus"</string>
     <string name="device_services" msgid="1191212554435440592">"Gerätedienste"</string>
     <string name="music_controls_no_title" msgid="5236895307087002011">"Kein Titel"</string>
-    <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+    <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"<xliff:g id="APP_NAME">%1$s</xliff:g> öffnen"</string>
+    <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Benachrichtigungseinstellungen für <xliff:g id="APP_NAME">%1$s</xliff:g> öffnen"</string>
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
     <skip />
-    <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 23818956..1a0df6b 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -879,8 +879,7 @@
       <item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> εφαρμογή χρησιμοποιεί το <xliff:g id="TYPE_1">%2$s</xliff:g>.</item>
     </plurals>
     <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Κατάλαβα"</string>
-    <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
-    <skip />
+    <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Ρυθμίσεις απορρήτου"</string>
     <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Εφαρμογή που χρησιμοποιεί τις λειτουργίες <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Εφαρμογές που χρησιμοποιούν τις λειτουργίες <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Αισθητήρες ανενεργοί"</string>
     <string name="device_services" msgid="1191212554435440592">"Υπηρεσίες συσκευής"</string>
     <string name="music_controls_no_title" msgid="5236895307087002011">"Χωρίς τίτλο"</string>
-    <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+    <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Άνοιγμα <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Άνοιγμα ρυθμίσεων ειδοποιήσεων για την εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
     <skip />
-    <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index 63f6773..95c1349 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -879,8 +879,7 @@
       <item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> application is using your <xliff:g id="TYPE_1">%2$s</xliff:g>.</item>
     </plurals>
     <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Got it"</string>
-    <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
-    <skip />
+    <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Privacy settings"</string>
     <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"App using your <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Apps using your <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensors off"</string>
     <string name="device_services" msgid="1191212554435440592">"Device Services"</string>
     <string name="music_controls_no_title" msgid="5236895307087002011">"No title"</string>
-    <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+    <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Open <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Open notification settings for <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
     <skip />
-    <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index d6539e7..6d55c5a 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -879,8 +879,7 @@
       <item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> application is using your <xliff:g id="TYPE_1">%2$s</xliff:g>.</item>
     </plurals>
     <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Got it"</string>
-    <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
-    <skip />
+    <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Privacy settings"</string>
     <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"App using your <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Apps using your <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensors off"</string>
     <string name="device_services" msgid="1191212554435440592">"Device Services"</string>
     <string name="music_controls_no_title" msgid="5236895307087002011">"No title"</string>
-    <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+    <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Open <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Open notification settings for <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
     <skip />
-    <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 63f6773..95c1349 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -879,8 +879,7 @@
       <item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> application is using your <xliff:g id="TYPE_1">%2$s</xliff:g>.</item>
     </plurals>
     <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Got it"</string>
-    <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
-    <skip />
+    <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Privacy settings"</string>
     <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"App using your <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Apps using your <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensors off"</string>
     <string name="device_services" msgid="1191212554435440592">"Device Services"</string>
     <string name="music_controls_no_title" msgid="5236895307087002011">"No title"</string>
-    <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+    <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Open <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Open notification settings for <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
     <skip />
-    <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index 63f6773..95c1349 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -879,8 +879,7 @@
       <item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> application is using your <xliff:g id="TYPE_1">%2$s</xliff:g>.</item>
     </plurals>
     <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Got it"</string>
-    <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
-    <skip />
+    <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Privacy settings"</string>
     <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"App using your <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Apps using your <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensors off"</string>
     <string name="device_services" msgid="1191212554435440592">"Device Services"</string>
     <string name="music_controls_no_title" msgid="5236895307087002011">"No title"</string>
-    <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+    <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Open <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Open notification settings for <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
     <skip />
-    <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index 36ef647..266faa8 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -879,8 +879,7 @@
       <item quantity="one">‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‎‎‏‏‏‎‎‏‏‏‎‎‏‎‎‎‏‏‏‎‏‏‏‏‏‎‎‏‏‎‎‎‎‏‏‎‎‎‎‎‎‎‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‎‎‎‎‎‏‎‎‏‏‎<xliff:g id="NUM_APPS_0">%1$d</xliff:g>‎‏‎‎‏‏‏‎ application is using your ‎‏‎‎‏‏‎<xliff:g id="TYPE_1">%2$s</xliff:g>‎‏‎‎‏‏‏‎.‎‏‎‎‏‎</item>
     </plurals>
     <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‎‏‎‏‏‎‏‎‏‏‎‏‏‎‏‎‎‎‏‏‎‎‏‎‎‎‏‏‎‏‎‏‎‏‎‎‎‏‎‎‎‏‎‏‏‎‏‏‎‎‏‎‎‏‎‎‏‏‎‎‏‎‎‎Got it‎‏‎‎‏‎"</string>
-    <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
-    <skip />
+    <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‎‏‏‏‏‏‏‏‏‎‏‎‎‏‎‏‏‎‎‎‎‏‏‏‎‎‏‏‏‎‎‏‎‏‏‏‏‎‏‏‏‏‏‎‏‏‏‎‏‏‎‏‎‎‏‏‎‎‎Privacy settings‎‏‎‎‏‎"</string>
     <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‎‎‏‏‏‎‎‎‏‎‏‎‎‎‎‏‎‏‎‏‎‎‎‎‎‏‎‎‏‎‏‏‏‏‎‎‏‎‎‏‎‎‎‎‎‎‎‎‎‏‎‎‎‏‏‏‏‎‎‎‎App using your ‎‏‎‎‏‏‎<xliff:g id="TYPES_LIST">%s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‎‏‏‏‏‎‎‏‏‎‏‎‏‎‎‏‎‏‎‎‏‎‎‎‎‎‏‏‏‎‎‏‏‏‎‎‏‎‏‎‎‎‎‏‏‏‎‎‎‏‎‏‏‎‎‎‎‎‏‎‏‎Apps using your ‎‏‎‎‏‏‎<xliff:g id="TYPES_LIST">%s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
     <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‏‏‏‏‏‎‎‏‎‎‎‎‏‎‏‎‏‏‎‏‏‎‏‏‏‎‎‎‏‏‏‎‏‏‏‏‏‏‏‏‎‏‏‎‎‎‎‏‏‎‏‏‏‎‎‏‏‏‏‏‏‎, ‎‏‎‎‏‎ "</string>
@@ -895,8 +894,12 @@
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‏‎‏‎‎‏‎‎‏‏‎‏‏‎‏‏‎‏‏‏‎‎‏‎‏‎‎‎‏‎‏‏‏‎‎‏‎‎‏‎‏‏‏‏‎‏‎‎‏‏‏‏‏‎‎Sensors off‎‏‎‎‏‎"</string>
     <string name="device_services" msgid="1191212554435440592">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‎‎‎‎‏‎‎‎‏‎‎‎‎‎‎‎‏‎‎‏‏‎‎‎‎‎‎‏‏‏‎‎‎‏‏‏‎‎‎‏‏‏‎‎‎‎‏‎‏‏‏‏‏‏‎‏‎‎‎‎‎Device Services‎‏‎‎‏‎"</string>
     <string name="music_controls_no_title" msgid="5236895307087002011">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‎‎‏‎‎‎‏‎‏‎‏‏‎‏‎‎‏‏‎‎‎‎‏‎‎‎‏‎‎‏‎‎‎‏‏‎‎‎‏‏‎‏‎‏‎‎‏‎‏‏‏‎‎‏‏‎‎‏‏‎‏‏‎No title‎‏‎‎‏‎"</string>
-    <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+    <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‏‏‏‏‏‏‎‏‏‎‏‏‏‎‏‎‎‎‏‎‏‏‏‎‎‏‎‏‏‏‏‏‏‏‏‎‏‏‎‏‏‏‎‏‎‏‏‎‎‎‎‎‎‎‎‏‏‎‏‏‎‎‏‎‏‎Open ‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+    <string name="bubbles_settings_button_description" msgid="1940331766151865776">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‏‎‎‎‎‏‏‏‏‏‎‏‏‏‎‏‎‏‏‏‎‏‏‎‏‎‏‏‏‎‎‎‏‎‏‏‏‎‏‏‎‎‎‎‎‎‎‏‏‏‏‏‎‎‎‏‏‎‏‏‎‎‏‎‏‏‎‏‏‎‎‎‎‎Open notification settings for ‎‏‎‎‏‏‎<xliff:g id="APP_NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎‎‏‎‎‏‎"</string>
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
     <skip />
-    <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 81cd300..b1f7068 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -879,8 +879,7 @@
       <item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> aplicación está usando tu <xliff:g id="TYPE_1">%2$s</xliff:g>.</item>
     </plurals>
     <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Entendido"</string>
-    <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
-    <skip />
+    <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Config. privacidad"</string>
     <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Una app está usando tu <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Apps que están usando tu <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Se desactivaron los sensores"</string>
     <string name="device_services" msgid="1191212554435440592">"Servicios del dispositivo"</string>
     <string name="music_controls_no_title" msgid="5236895307087002011">"Sin título"</string>
-    <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+    <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Abrir <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Abrir la configuración de notificaciones de <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
     <skip />
-    <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 16c182b..b1947fd 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -899,4 +899,10 @@
     <skip />
     <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
     <skip />
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+    <skip />
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index b02e457..8085224 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -879,8 +879,7 @@
       <item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> rakendus kasutab üksust <xliff:g id="TYPE_1">%2$s</xliff:g>.</item>
     </plurals>
     <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Selge"</string>
-    <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
-    <skip />
+    <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Privaatsusseaded"</string>
     <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Rakendus, mis kasutab üksusi <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Rakendused, mis kasutavad üksusi <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Andurid on välja lülitatud"</string>
     <string name="device_services" msgid="1191212554435440592">"Seadme teenused"</string>
     <string name="music_controls_no_title" msgid="5236895307087002011">"Pealkiri puudub"</string>
-    <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+    <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Ava <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Ava rakenduse <xliff:g id="APP_NAME">%1$s</xliff:g> märguandeseaded"</string>
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
     <skip />
-    <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index b2d29c1..7f9bffa 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -879,8 +879,7 @@
       <item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> aplikazio ari da <xliff:g id="TYPE_1">%2$s</xliff:g> erabiltzen.</item>
     </plurals>
     <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Ados"</string>
-    <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
-    <skip />
+    <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Pribatutasun-ezarpenak"</string>
     <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"<xliff:g id="TYPES_LIST">%s</xliff:g> erabiltzen ari den aplikazioa"</string>
     <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"<xliff:g id="TYPES_LIST">%s</xliff:g> erabiltzen ari diren aplikazioak"</string>
     <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sentsoreak desaktibatuta daude"</string>
     <string name="device_services" msgid="1191212554435440592">"Gailuetarako zerbitzuak"</string>
     <string name="music_controls_no_title" msgid="5236895307087002011">"Ez du izenik"</string>
-    <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+    <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Ireki <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Ireki <xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioaren jakinarazpen-ezarpenak"</string>
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
     <skip />
-    <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 4fb889b..018d6d1 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -879,8 +879,7 @@
       <item quantity="other"><xliff:g id="NUM_APPS_4">%1$d</xliff:g> برنامه درحال استفاده از <xliff:g id="TYPE_5">%2$s</xliff:g> شما است.</item>
     </plurals>
     <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"متوجه شدم"</string>
-    <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
-    <skip />
+    <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"تنظیمات حریم خصوصی"</string>
     <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"برنامه‌ای که از <xliff:g id="TYPES_LIST">%s</xliff:g> شما استفاده می‌کند"</string>
     <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"برنامه‌هایی که از <xliff:g id="TYPES_LIST">%s</xliff:g> شما استفاده می‌کنند"</string>
     <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">"، "</string>
@@ -895,8 +894,12 @@
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"حسگرها خاموش است"</string>
     <string name="device_services" msgid="1191212554435440592">"سرویس‌های دستگاه"</string>
     <string name="music_controls_no_title" msgid="5236895307087002011">"بدون عنوان"</string>
-    <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+    <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"باز کردن <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="bubbles_settings_button_description" msgid="1940331766151865776">"تنظیمات اعلان <xliff:g id="APP_NAME">%1$s</xliff:g> را باز کنید"</string>
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
     <skip />
-    <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 1ab48a0..0258ccb 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -879,8 +879,7 @@
       <item quantity="one"><xliff:g id="TYPE_1">%2$s</xliff:g> on <xliff:g id="NUM_APPS_0">%1$d</xliff:g> sovelluksen käytössä.</item>
     </plurals>
     <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Selvä"</string>
-    <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
-    <skip />
+    <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Tietosuoja-asetukset"</string>
     <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Sovellus, jolla on <xliff:g id="TYPES_LIST">%s</xliff:g> ‑käyttöoikeus"</string>
     <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Sovellukset, joilla on <xliff:g id="TYPES_LIST">%s</xliff:g> ‑käyttöoikeus"</string>
     <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Anturit pois päältä"</string>
     <string name="device_services" msgid="1191212554435440592">"Laitepalvelut"</string>
     <string name="music_controls_no_title" msgid="5236895307087002011">"Ei nimeä"</string>
-    <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+    <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Avaa <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Avaa ilmoitusasetukset (<xliff:g id="APP_NAME">%1$s</xliff:g>)"</string>
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
     <skip />
-    <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 554a222..a3a3135 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -899,4 +899,10 @@
     <skip />
     <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
     <skip />
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+    <skip />
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 2e47000..d1ce32e 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -899,4 +899,10 @@
     <skip />
     <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
     <skip />
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+    <skip />
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index 90b9f87..d76c34a 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -879,8 +879,7 @@
       <item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> aplicación utiliza o teu dispositivo (<xliff:g id="TYPE_1">%2$s</xliff:g>).</item>
     </plurals>
     <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"De acordo"</string>
-    <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
-    <skip />
+    <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Config. privacidade"</string>
     <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Aplicación que utiliza o seguinte: <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Aplicacións que utilizan o seguinte: <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Desactivar sensores"</string>
     <string name="device_services" msgid="1191212554435440592">"Servizos do dispositivo"</string>
     <string name="music_controls_no_title" msgid="5236895307087002011">"Sen título"</string>
-    <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+    <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Abre a aplicación <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Abre a configuración de notificacións para <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
     <skip />
-    <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 5717616..c84051c 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -899,4 +899,10 @@
     <skip />
     <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
     <skip />
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+    <skip />
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 20b9198..157f55c 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -899,4 +899,10 @@
     <skip />
     <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
     <skip />
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+    <skip />
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 79f410a..77c3ce3 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -886,8 +886,7 @@
       <item quantity="other"><xliff:g id="NUM_APPS_4">%1$d</xliff:g> aplikacija upotrebljava <xliff:g id="TYPE_5">%2$s</xliff:g>.</item>
     </plurals>
     <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Shvaćam"</string>
-    <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
-    <skip />
+    <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Postavke privatnosti"</string>
     <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Aplikacije koje upotrebljavaju <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Aplikacije koje upotrebljavaju <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -903,8 +902,12 @@
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Senzori su isključeni"</string>
     <string name="device_services" msgid="1191212554435440592">"Usluge uređaja"</string>
     <string name="music_controls_no_title" msgid="5236895307087002011">"Bez naslova"</string>
-    <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+    <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Otvorite aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Otvorite postavke obavijesti za aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
     <skip />
-    <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index d0cdfb4..308295a 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -879,8 +879,7 @@
       <item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> alkalmazás használja a következőt: <xliff:g id="TYPE_1">%2$s</xliff:g>.</item>
     </plurals>
     <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Értem"</string>
-    <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
-    <skip />
+    <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Adatvédelmi beállítások"</string>
     <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"A következőket használó alkalmazás: <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"A következőt használó alkalmazások: <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Érzékelők kikapcsolva"</string>
     <string name="device_services" msgid="1191212554435440592">"Eszközszolgáltatások"</string>
     <string name="music_controls_no_title" msgid="5236895307087002011">"Nincs cím"</string>
-    <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+    <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"<xliff:g id="APP_NAME">%1$s</xliff:g> megnyitása"</string>
+    <string name="bubbles_settings_button_description" msgid="1940331766151865776">"<xliff:g id="APP_NAME">%1$s</xliff:g> – az alkalmazás értesítési beállításainak megnyitása"</string>
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
     <skip />
-    <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index 41bd378..a3e05ad 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -899,4 +899,10 @@
     <skip />
     <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
     <skip />
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+    <skip />
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 98e1c4b..2bad55e0 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -879,8 +879,7 @@
       <item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> aplikasi menggunakan <xliff:g id="TYPE_1">%2$s</xliff:g> Anda.</item>
     </plurals>
     <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Oke"</string>
-    <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
-    <skip />
+    <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Setelan privasi"</string>
     <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Aplikasi yang menggunakan <xliff:g id="TYPES_LIST">%s</xliff:g> Anda"</string>
     <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Aplikasi yang menggunakan <xliff:g id="TYPES_LIST">%s</xliff:g> Anda"</string>
     <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensor nonaktif"</string>
     <string name="device_services" msgid="1191212554435440592">"Layanan Perangkat"</string>
     <string name="music_controls_no_title" msgid="5236895307087002011">"Tanpa judul"</string>
-    <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+    <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Buka <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Buka setelan notifikasi untuk <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
     <skip />
-    <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index d1ea979..3502613 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -879,8 +879,7 @@
       <item quantity="other"><xliff:g id="NUM_APPS_4">%1$d</xliff:g> forrit eru að nota <xliff:g id="TYPE_5">%2$s</xliff:g>.</item>
     </plurals>
     <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Ég skil"</string>
-    <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
-    <skip />
+    <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Persónuvernd"</string>
     <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Forrit sem nota <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Forrit sem nota <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Slökkt á skynjurum"</string>
     <string name="device_services" msgid="1191212554435440592">"Tækjaþjónusta"</string>
     <string name="music_controls_no_title" msgid="5236895307087002011">"Enginn titill"</string>
-    <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+    <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Opna <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Opna tilkynningastillingar fyrir <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
     <skip />
-    <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index af22c6d..42ff72a 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -879,8 +879,7 @@
       <item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> applicazione sta utilizzando <xliff:g id="TYPE_1">%2$s</xliff:g>.</item>
     </plurals>
     <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"OK"</string>
-    <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
-    <skip />
+    <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Impostazioni privacy"</string>
     <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"App che usa <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"App che utilizzano <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensori disattivati"</string>
     <string name="device_services" msgid="1191212554435440592">"Servizi del dispositivo"</string>
     <string name="music_controls_no_title" msgid="5236895307087002011">"Senza titolo"</string>
-    <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+    <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Apri <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Apri le impostazioni di notifica dell\'app <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
     <skip />
-    <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index a7d5138..036b0df 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -519,9 +519,9 @@
     <string name="accessibility_volume_collapse" msgid="3609549593031810875">"כווץ"</string>
     <string name="accessibility_output_chooser" msgid="8185317493017988680">"החלפת מכשיר פלט"</string>
     <string name="screen_pinning_title" msgid="3273740381976175811">"המסך מוצמד"</string>
-    <string name="screen_pinning_description" msgid="8909878447196419623">"נשאר בתצוגה עד לביטול ההצמדה. גע בלחצנים \'הקודם\' ו\'סקירה\' והחזק כדי לבטל את ההצמדה."</string>
+    <string name="screen_pinning_description" msgid="8909878447196419623">"נשאר בתצוגה עד לביטול ההצמדה. יש ללחוץ לחיצה ארוכה על הלחצנים \'הקודם\' ו\'סקירה\' כדי לבטל את ההצמדה."</string>
     <string name="screen_pinning_description_recents_invisible" msgid="8281145542163727971">"נשאר בתצוגה עד לביטול ההצמדה. יש ללחוץ לחיצה ארוכה על הלחצנים \'הקודם\' ו\'דף הבית\' כדי לבטל את ההצמדה."</string>
-    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"נשאר בתצוגה עד לביטול ההצמדה. גע בלחצן \'סקירה\' והחזק כדי לבטל את ההצמדה."</string>
+    <string name="screen_pinning_description_accessible" msgid="426190689254018656">"נשאר בתצוגה עד לביטול ההצמדה. יש ללחוץ לחיצה ארוכה על הלחצן \'סקירה\' כדי לבטל את ההצמדה."</string>
     <string name="screen_pinning_description_recents_invisible_accessible" msgid="6134833683151189507">"נשאר בתצוגה עד לביטול ההצמדה. יש ללחוץ לחיצה ארוכה על הלחצן \'דף הבית\' כדי לבטל את ההצמדה."</string>
     <string name="screen_pinning_toast" msgid="2266705122951934150">"כדי לבטל את ההצמדה של מסך זה, יש ללחוץ לחיצה ארוכה על הלחצנים \'הקודם\' ו\'סקירה\'"</string>
     <string name="screen_pinning_toast_recents_invisible" msgid="8252402309499161281">"כדי לבטל את ההצמדה של מסך זה, יש ללחוץ לחיצה ארוכה על הלחצנים \'הקודם\' ו\'דף הבית\'"</string>
@@ -915,4 +915,10 @@
     <skip />
     <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
     <skip />
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+    <skip />
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 9095fd1..7aa7fbf 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -879,8 +879,7 @@
       <item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> 個のアプリが <xliff:g id="TYPE_1">%2$s</xliff:g> を使用しています。</item>
     </plurals>
     <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"OK"</string>
-    <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
-    <skip />
+    <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"プライバシー設定"</string>
     <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"<xliff:g id="TYPES_LIST">%s</xliff:g>を使用しているアプリ"</string>
     <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"<xliff:g id="TYPES_LIST">%s</xliff:g>を使用しているアプリ"</string>
     <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">"、 "</string>
@@ -895,8 +894,12 @@
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"センサー OFF"</string>
     <string name="device_services" msgid="1191212554435440592">"デバイス サービス"</string>
     <string name="music_controls_no_title" msgid="5236895307087002011">"タイトルなし"</string>
-    <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+    <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"<xliff:g id="APP_NAME">%1$s</xliff:g> を開く"</string>
+    <string name="bubbles_settings_button_description" msgid="1940331766151865776">"<xliff:g id="APP_NAME">%1$s</xliff:g> の通知設定を開く"</string>
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
     <skip />
-    <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 9236830..4fec284 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -879,8 +879,7 @@
       <item quantity="one">თქვენი <xliff:g id="TYPE_1">%2$s</xliff:g> გამოიყენება <xliff:g id="NUM_APPS_0">%1$d</xliff:g> აპლიკაციის მიერ.</item>
     </plurals>
     <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"გასაგებია"</string>
-    <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
-    <skip />
+    <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"კონფიდ. პარამეტრები"</string>
     <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"აპი, რომლის მიერაც გამოიყენება თქვენი <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"აპები, რომელთა მიერაც გამოიყენება თქვენი <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"სენსორების გამორთვა"</string>
     <string name="device_services" msgid="1191212554435440592">"მოწყობილობის სერვისები"</string>
     <string name="music_controls_no_title" msgid="5236895307087002011">"უსათაურო"</string>
-    <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+    <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ის გახსნა"</string>
+    <string name="bubbles_settings_button_description" msgid="1940331766151865776">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ის შეტყობინების პარამეტრების გახსნა"</string>
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
     <skip />
-    <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 3b46364..c5022b5 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -899,4 +899,10 @@
     <skip />
     <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
     <skip />
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+    <skip />
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 6811072..c03dddd 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -899,4 +899,10 @@
     <skip />
     <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
     <skip />
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+    <skip />
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 273470a..aa0e63f 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -899,4 +899,10 @@
     <skip />
     <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
     <skip />
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+    <skip />
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index ca45e4d..eb94903 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -899,4 +899,10 @@
     <skip />
     <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
     <skip />
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+    <skip />
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 82d709b..14d93e4 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -899,4 +899,10 @@
     <skip />
     <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
     <skip />
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+    <skip />
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index ed05407..467a2dc 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -899,4 +899,10 @@
     <skip />
     <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
     <skip />
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+    <skip />
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index a136772..c79743f 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -893,8 +893,7 @@
       <item quantity="other"><xliff:g id="NUM_APPS_4">%1$d</xliff:g> programų naudoja jūsų <xliff:g id="TYPE_5">%2$s</xliff:g>.</item>
     </plurals>
     <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Supratau"</string>
-    <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
-    <skip />
+    <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Privatumo nustatymai"</string>
     <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Programa, kuri naudoja: <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Programos, kurios naudoja: <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -911,8 +910,12 @@
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Jutikliai išjungti"</string>
     <string name="device_services" msgid="1191212554435440592">"Įrenginio paslaugos"</string>
     <string name="music_controls_no_title" msgid="5236895307087002011">"Nėra pavadinimo"</string>
-    <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+    <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Atidaryti „<xliff:g id="APP_NAME">%1$s</xliff:g>“"</string>
+    <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Atidaryti „<xliff:g id="APP_NAME">%1$s</xliff:g>“ pranešimų nustatymus"</string>
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
     <skip />
-    <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index fec4fe8..d6dc8f3 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -886,8 +886,7 @@
       <item quantity="other"><xliff:g id="NUM_APPS_4">%1$d</xliff:g> lietojumprogrammās tiek izmantots: <xliff:g id="TYPE_5">%2$s</xliff:g>.</item>
     </plurals>
     <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Labi"</string>
-    <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
-    <skip />
+    <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Konfidencialitāte"</string>
     <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Lietotne, kurā tiek izmantots: <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Lietotnes, kurās tiek izmantots: <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -903,8 +902,12 @@
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensori izslēgti"</string>
     <string name="device_services" msgid="1191212554435440592">"Ierīces pakalpojumi"</string>
     <string name="music_controls_no_title" msgid="5236895307087002011">"Nav nosaukuma"</string>
-    <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+    <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Atvērt lietotni <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Atvērt paziņojumu iestatījumus lietotnei <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
     <skip />
-    <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 6b3e8cc..03e31f74 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -899,4 +899,10 @@
     <skip />
     <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
     <skip />
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+    <skip />
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 37d4b8c..f25ae1d 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -899,4 +899,10 @@
     <skip />
     <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
     <skip />
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+    <skip />
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 42cb765..0e5dbb7 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -879,8 +879,7 @@
       <item quantity="one">Таны <xliff:g id="TYPE_1">%2$s</xliff:g>-г <xliff:g id="NUM_APPS_0">%1$d</xliff:g> апп ашиглаж байна.</item>
     </plurals>
     <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Ойлголоо"</string>
-    <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
-    <skip />
+    <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Нууцлалын тохиргоо"</string>
     <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Апп таны <xliff:g id="TYPES_LIST">%s</xliff:g>-г ашиглаж байна"</string>
     <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Аппууд таны <xliff:g id="TYPES_LIST">%s</xliff:g>-г ашиглаж байна"</string>
     <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Мэдрэгчийг унтраах"</string>
     <string name="device_services" msgid="1191212554435440592">"Төхөөрөмжийн үйлчилгээ"</string>
     <string name="music_controls_no_title" msgid="5236895307087002011">"Гарчиггүй"</string>
-    <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+    <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"<xliff:g id="APP_NAME">%1$s</xliff:g>-г нээх"</string>
+    <string name="bubbles_settings_button_description" msgid="1940331766151865776">"<xliff:g id="APP_NAME">%1$s</xliff:g>-н мэдэгдлийн тохиргоог нээх"</string>
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
     <skip />
-    <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 44d8c4e..1b81062 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -899,4 +899,10 @@
     <skip />
     <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
     <skip />
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+    <skip />
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index eee6b25..df10b2f 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -899,4 +899,10 @@
     <skip />
     <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
     <skip />
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+    <skip />
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index b341bea..f827805 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -684,7 +684,7 @@
     <string name="keyboard_key_numpad_template" msgid="8729216555174634026">"ဂဏန်းကွက်<xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="keyboard_shortcut_group_system" msgid="6472647649616541064">"စနစ်"</string>
     <string name="keyboard_shortcut_group_system_home" msgid="3054369431319891965">"ပင်မ"</string>
-    <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"မကြာသေးခင်က"</string>
+    <string name="keyboard_shortcut_group_system_recents" msgid="3154851905021926744">"လတ်တလော"</string>
     <string name="keyboard_shortcut_group_system_back" msgid="2207004531216446378">"နောက်သို့"</string>
     <string name="keyboard_shortcut_group_system_notifications" msgid="8366964080041773224">"အကြောင်းကြားချက်များ"</string>
     <string name="keyboard_shortcut_group_system_shortcuts_helper" msgid="4892255911160332762">"ကီးဘုတ် ဖြတ်လမ်းများ"</string>
@@ -879,8 +879,7 @@
       <item quantity="one">အပလီကေးရှင်း <xliff:g id="NUM_APPS_0">%1$d</xliff:g> ခုက သင်၏ <xliff:g id="TYPE_1">%2$s</xliff:g> ကို အသုံးပြုနေသည်။</item>
     </plurals>
     <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"ရပါပြီ"</string>
-    <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
-    <skip />
+    <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"ကန့်သတ်ဆက်တင်များ"</string>
     <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"သင့် <xliff:g id="TYPES_LIST">%s</xliff:g> ကို အသုံးပြုနေသော အက်ပ်"</string>
     <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"သင့် <xliff:g id="TYPES_LIST">%s</xliff:g> ကို အသုံးပြုနေသော အက်ပ်များ"</string>
     <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">"၊ "</string>
@@ -895,8 +894,12 @@
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"အာရုံခံကိရိယာများ ပိတ်ထားသည်"</string>
     <string name="device_services" msgid="1191212554435440592">"စက်ပစ္စည်းဝန်ဆောင်မှုများ"</string>
     <string name="music_controls_no_title" msgid="5236895307087002011">"ခေါင်းစဉ် မရှိပါ"</string>
-    <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+    <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"<xliff:g id="APP_NAME">%1$s</xliff:g> ကိုဖွင့်ရန်"</string>
+    <string name="bubbles_settings_button_description" msgid="1940331766151865776">"<xliff:g id="APP_NAME">%1$s</xliff:g> အတွက် အကြောင်းကြားချက်ဆက်တင်များကို ဖွင့်ရန်"</string>
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
     <skip />
-    <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index a27addb..1370468 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -899,4 +899,10 @@
     <skip />
     <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
     <skip />
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+    <skip />
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 1bb3664..08f3cef 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -899,4 +899,10 @@
     <skip />
     <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
     <skip />
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+    <skip />
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 8075ef4..7cb4b5a 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -792,7 +792,7 @@
     <string name="accessibility_quick_settings_open_settings" msgid="7806613775728380737">"<xliff:g id="ID_1">%s</xliff:g>-instellingen openen."</string>
     <string name="accessibility_quick_settings_edit" msgid="7839992848995240393">"Volgorde van instellingen bewerken."</string>
     <string name="accessibility_quick_settings_page" msgid="5032979051755200721">"Pagina <xliff:g id="ID_1">%1$d</xliff:g> van <xliff:g id="ID_2">%2$d</xliff:g>"</string>
-    <string name="tuner_lock_screen" msgid="5755818559638850294">"Scherm vergrendelen"</string>
+    <string name="tuner_lock_screen" msgid="5755818559638850294">"Vergrendelingsscherm"</string>
     <string name="pip_phone_expand" msgid="5889780005575693909">"Uitvouwen"</string>
     <string name="pip_phone_minimize" msgid="1079119422589131792">"Minimaliseren"</string>
     <string name="pip_phone_close" msgid="8416647892889710330">"Sluiten"</string>
@@ -879,8 +879,7 @@
       <item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> app gebruikt je <xliff:g id="TYPE_1">%2$s</xliff:g>.</item>
     </plurals>
     <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"OK"</string>
-    <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
-    <skip />
+    <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Privacyinstellingen"</string>
     <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"App die je <xliff:g id="TYPES_LIST">%s</xliff:g> gebruikt"</string>
     <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Apps die je <xliff:g id="TYPES_LIST">%s</xliff:g> gebruiken"</string>
     <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensoren uit"</string>
     <string name="device_services" msgid="1191212554435440592">"Apparaatservices"</string>
     <string name="music_controls_no_title" msgid="5236895307087002011">"Geen titel"</string>
-    <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+    <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"<xliff:g id="APP_NAME">%1$s</xliff:g> openen"</string>
+    <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Instellingen voor meldingen voor <xliff:g id="APP_NAME">%1$s</xliff:g> openen"</string>
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
     <skip />
-    <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 337b15d..b9b4ea8 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -899,4 +899,10 @@
     <skip />
     <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
     <skip />
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+    <skip />
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 4d8e3f1..5432975 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -899,4 +899,10 @@
     <skip />
     <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
     <skip />
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+    <skip />
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index d955236..b692045 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -893,8 +893,7 @@
       <item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> aplikacja używa: <xliff:g id="TYPE_1">%2$s</xliff:g>.</item>
     </plurals>
     <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"OK"</string>
-    <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
-    <skip />
+    <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Ustawienia prywatności"</string>
     <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Aplikacje, które używają: <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Aplikacje, które używają: <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -911,8 +910,12 @@
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Wyłącz czujniki"</string>
     <string name="device_services" msgid="1191212554435440592">"Usługi urządzenia"</string>
     <string name="music_controls_no_title" msgid="5236895307087002011">"Bez tytułu"</string>
-    <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+    <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Otwórz: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Otwórz ustawienia powiadomień z aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
     <skip />
-    <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index d2219d2..fcd7f85 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -879,8 +879,7 @@
       <item quantity="other"><xliff:g id="NUM_APPS_4">%1$d</xliff:g> aplicativos estão usando <xliff:g id="TYPE_5">%2$s</xliff:g>.</item>
     </plurals>
     <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Ok"</string>
-    <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
-    <skip />
+    <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Config. de privacidade"</string>
     <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"App usando <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Apps usando <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensores desativados"</string>
     <string name="device_services" msgid="1191212554435440592">"Serviços do dispositivo"</string>
     <string name="music_controls_no_title" msgid="5236895307087002011">"Sem título"</string>
-    <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+    <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Abrir <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Abra as configurações de notificação do <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
     <skip />
-    <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 0866ffc..6579645 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -879,8 +879,7 @@
       <item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> aplicação está a utilizar o(a) <xliff:g id="TYPE_1">%2$s</xliff:g>.</item>
     </plurals>
     <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Compreendi"</string>
-    <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
-    <skip />
+    <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Def. de privacidade"</string>
     <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Aplicações que utilizam o(a) <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Aplicações que utilizam o(a) <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensores desativados"</string>
     <string name="device_services" msgid="1191212554435440592">"Serviços do dispositivo"</string>
     <string name="music_controls_no_title" msgid="5236895307087002011">"Sem título"</string>
-    <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+    <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Abrir a aplicação <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Abrir as definições de notificação da aplicação <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
     <skip />
-    <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index d2219d2..fcd7f85 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -879,8 +879,7 @@
       <item quantity="other"><xliff:g id="NUM_APPS_4">%1$d</xliff:g> aplicativos estão usando <xliff:g id="TYPE_5">%2$s</xliff:g>.</item>
     </plurals>
     <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Ok"</string>
-    <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
-    <skip />
+    <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Config. de privacidade"</string>
     <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"App usando <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Apps usando <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensores desativados"</string>
     <string name="device_services" msgid="1191212554435440592">"Serviços do dispositivo"</string>
     <string name="music_controls_no_title" msgid="5236895307087002011">"Sem título"</string>
-    <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+    <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Abrir <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Abra as configurações de notificação do <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
     <skip />
-    <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index e040484..144bfc3 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -886,8 +886,7 @@
       <item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> aplicație folosește <xliff:g id="TYPE_1">%2$s</xliff:g>.</item>
     </plurals>
     <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"OK"</string>
-    <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
-    <skip />
+    <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Setări de confidențialitate"</string>
     <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Aplicație care folosește <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Aplicații care folosesc <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -903,8 +902,12 @@
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Senzori dezactivați"</string>
     <string name="device_services" msgid="1191212554435440592">"Servicii pentru dispozitiv"</string>
     <string name="music_controls_no_title" msgid="5236895307087002011">"Fără titlu"</string>
-    <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+    <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Accesați <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Deschideți setările pentru notificări pentru aplicația <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
     <skip />
-    <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 338ce14..6d65592 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -893,8 +893,7 @@
       <item quantity="other">Функцию \"<xliff:g id="TYPE_5">%2$s</xliff:g>\" используют <xliff:g id="NUM_APPS_4">%1$d</xliff:g> приложения.</item>
     </plurals>
     <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"ОК"</string>
-    <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
-    <skip />
+    <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Конфиденциальность"</string>
     <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Приложение, в котором используются операции <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Приложения, в которых используются операции <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -911,8 +910,12 @@
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Датчики отключены"</string>
     <string name="device_services" msgid="1191212554435440592">"Сервисы устройства"</string>
     <string name="music_controls_no_title" msgid="5236895307087002011">"Без названия"</string>
-    <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+    <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Открыть приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"."</string>
+    <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Настройки уведомлений приложения \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"."</string>
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
     <skip />
-    <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 3a0b3a4..2529f19 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -879,8 +879,7 @@
       <item quantity="other">යෙදුම් <xliff:g id="NUM_APPS_4">%1$d</xliff:g>ක් ඔබේ <xliff:g id="TYPE_5">%2$s</xliff:g> භාවිත කරමින් සිටිති.</item>
     </plurals>
     <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"තේරුණා"</string>
-    <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
-    <skip />
+    <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"පෞද්ගලිකත්ව සැකසීම්"</string>
     <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"ඔබගේ <xliff:g id="TYPES_LIST">%s</xliff:g> භාවිත කරන යෙදුම්"</string>
     <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"ඔබගේ <xliff:g id="TYPES_LIST">%s</xliff:g> භාවිත කරන යෙදුම්"</string>
     <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"සංවේදක ක්‍රියාවිරහිතයි"</string>
     <string name="device_services" msgid="1191212554435440592">"උපාංග සේවා"</string>
     <string name="music_controls_no_title" msgid="5236895307087002011">"මාතෘකාවක් නැත"</string>
-    <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+    <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"<xliff:g id="APP_NAME">%1$s</xliff:g> විවෘත කරන්න"</string>
+    <string name="bubbles_settings_button_description" msgid="1940331766151865776">"<xliff:g id="APP_NAME">%1$s</xliff:g> සඳහා දැනුම්දීම් සැකසීම් විවෘත කරන්න"</string>
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
     <skip />
-    <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 883243e..923384f 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -893,8 +893,7 @@
       <item quantity="one"><xliff:g id="TYPE_1">%2$s</xliff:g> používa <xliff:g id="NUM_APPS_0">%1$d</xliff:g> aplikácia.</item>
     </plurals>
     <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Dobre"</string>
-    <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
-    <skip />
+    <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Nastavenia ochrany súkromia"</string>
     <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Aplikácia používajúca <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Aplikácie používajúce <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -911,8 +910,12 @@
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Senzory sú vypnuté"</string>
     <string name="device_services" msgid="1191212554435440592">"Služby zariadenia"</string>
     <string name="music_controls_no_title" msgid="5236895307087002011">"Bez názvu"</string>
-    <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+    <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Otvoriť <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Otvoriť nastavenia upozornení pre <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
     <skip />
-    <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index db40b44..d497f26 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -915,4 +915,10 @@
     <skip />
     <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
     <skip />
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+    <skip />
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index ad6113e..db905ce 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -899,4 +899,10 @@
     <skip />
     <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
     <skip />
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+    <skip />
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 768ae7f..264698a 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -886,8 +886,7 @@
       <item quantity="other"><xliff:g id="NUM_APPS_4">%1$d</xliff:g> апликација користи дозволу <xliff:g id="TYPE_5">%2$s</xliff:g>.</item>
     </plurals>
     <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Важи"</string>
-    <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
-    <skip />
+    <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Подешав. приватности"</string>
     <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Апликација која користи дозволе <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Апликације које користе дозволе <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -903,8 +902,12 @@
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Сензори су искључени"</string>
     <string name="device_services" msgid="1191212554435440592">"Услуге за уређаје"</string>
     <string name="music_controls_no_title" msgid="5236895307087002011">"Без наслова"</string>
-    <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+    <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Отворите <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Отворите подешавања обавештења за <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
     <skip />
-    <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 0f36517..7e8446e 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -899,4 +899,10 @@
     <skip />
     <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
     <skip />
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+    <skip />
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index a11e4d4..eb658ff 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -899,4 +899,10 @@
     <skip />
     <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
     <skip />
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+    <skip />
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index a8587c1..5bcc6fe 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -899,4 +899,10 @@
     <skip />
     <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
     <skip />
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+    <skip />
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index a512c0c..cb9b70d 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -899,4 +899,10 @@
     <skip />
     <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
     <skip />
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+    <skip />
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index b8a840e..6a126ff 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -879,8 +879,7 @@
       <item quantity="one">มี <xliff:g id="NUM_APPS_0">%1$d</xliff:g> แอปพลิเคชันกำลังใช้<xliff:g id="TYPE_1">%2$s</xliff:g></item>
     </plurals>
     <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"รับทราบ"</string>
-    <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
-    <skip />
+    <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"การตั้งค่าความเป็นส่วนตัว"</string>
     <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"มีแอปกำลังใช้<xliff:g id="TYPES_LIST">%s</xliff:g>ของคุณ"</string>
     <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"มีหลายแอปกำลังใช้<xliff:g id="TYPES_LIST">%s</xliff:g>ของคุณ"</string>
     <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"เซ็นเซอร์ปิดอยู่"</string>
     <string name="device_services" msgid="1191212554435440592">"บริการของอุปกรณ์"</string>
     <string name="music_controls_no_title" msgid="5236895307087002011">"ไม่มีชื่อ"</string>
-    <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+    <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"เปิด <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="bubbles_settings_button_description" msgid="1940331766151865776">"เปิดการตั้งค่าการแจ้งเตือนสำหรับ <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
     <skip />
-    <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 72c5eac..1550787 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -879,8 +879,7 @@
       <item quantity="other">Ginagamit ng <xliff:g id="NUM_APPS_4">%1$d</xliff:g> na application ang iyong <xliff:g id="TYPE_5">%2$s</xliff:g>.</item>
     </plurals>
     <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"OK"</string>
-    <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
-    <skip />
+    <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Mga setting ng privacy"</string>
     <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"App na gumagamit ng iyong <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Mga app na gumagamit ng iyong <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Naka-off ang mga sensor"</string>
     <string name="device_services" msgid="1191212554435440592">"Mga Serbisyo ng Device"</string>
     <string name="music_controls_no_title" msgid="5236895307087002011">"Walang pamagat"</string>
-    <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+    <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Buksan ang <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Buksan ang mga setting ng notification para sa <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
     <skip />
-    <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 5cd4e4c..9367155 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -899,4 +899,10 @@
     <skip />
     <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
     <skip />
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+    <skip />
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index b231c58..a850f21 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -915,4 +915,10 @@
     <skip />
     <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
     <skip />
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+    <skip />
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index 90447d7..c7bf3b0 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -879,8 +879,7 @@
       <item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> ایپلیکیشن آپ کی <xliff:g id="TYPE_1">%2$s</xliff:g> کا استعمال کر رہی ہے۔</item>
     </plurals>
     <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"سمجھ آ گئی"</string>
-    <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
-    <skip />
+    <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"رازداری کی ترتیبات"</string>
     <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"ایپ آپ کی <xliff:g id="TYPES_LIST">%s</xliff:g> کا استعمال کر رہی ہیں"</string>
     <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"ایپس آپ کی <xliff:g id="TYPES_LIST">%s</xliff:g> کا استعمال کر رہی ہیں"</string>
     <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">"، "</string>
@@ -895,8 +894,12 @@
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"سینسرز آف ہیں"</string>
     <string name="device_services" msgid="1191212554435440592">"آلہ کی سروس"</string>
     <string name="music_controls_no_title" msgid="5236895307087002011">"کوئی عنوان نہیں ہے"</string>
-    <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+    <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"<xliff:g id="APP_NAME">%1$s</xliff:g> کھولیں"</string>
+    <string name="bubbles_settings_button_description" msgid="1940331766151865776">"<xliff:g id="APP_NAME">%1$s</xliff:g> کے لئے اطلاع کی ترتیبات کھولیں"</string>
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
     <skip />
-    <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 4a7af62..48532fa 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -879,8 +879,7 @@
       <item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> ta ilova <xliff:g id="TYPE_1">%2$s</xliff:g> ishlatmoqda.</item>
     </plurals>
     <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"OK"</string>
-    <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
-    <skip />
+    <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Maxfiylik sozlama-ri"</string>
     <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"<xliff:g id="TYPES_LIST">%s</xliff:g> ishlatayotgan ilova"</string>
     <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Ilovalar <xliff:g id="TYPES_LIST">%s</xliff:g> ishlatmoqda"</string>
     <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Sensorlar nofaol"</string>
     <string name="device_services" msgid="1191212554435440592">"Qurilma xizmatlari"</string>
     <string name="music_controls_no_title" msgid="5236895307087002011">"Nomsiz"</string>
-    <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+    <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Ochish: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="bubbles_settings_button_description" msgid="1940331766151865776">"<xliff:g id="APP_NAME">%1$s</xliff:g> bildirishnoma sozlamalarini ochish"</string>
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
     <skip />
-    <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index ad8d17c..b796503 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -879,8 +879,7 @@
       <item quantity="one"><xliff:g id="NUM_APPS_0">%1$d</xliff:g> ứng dụng đang dùng <xliff:g id="TYPE_1">%2$s</xliff:g> của bạn.</item>
     </plurals>
     <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"OK"</string>
-    <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
-    <skip />
+    <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Cài đặt quyền riêng tư"</string>
     <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Ứng dụng đang sử dụng <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Các ứng dụng đang sử dụng <xliff:g id="TYPES_LIST">%s</xliff:g>"</string>
     <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Tắt cảm biến"</string>
     <string name="device_services" msgid="1191212554435440592">"Dịch vụ cho thiết bị"</string>
     <string name="music_controls_no_title" msgid="5236895307087002011">"Không có tiêu đề"</string>
-    <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+    <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Mở <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="bubbles_settings_button_description" msgid="1940331766151865776">"Mở mục cài đặt thông báo dành cho <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
     <skip />
-    <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 0330edf..3a5dd5c 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -899,4 +899,10 @@
     <skip />
     <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
     <skip />
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
+    <skip />
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 01797fb..8d67f5c 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -879,8 +879,7 @@
       <item quantity="one">有 <xliff:g id="NUM_APPS_0">%1$d</xliff:g> 個應用程式正在使用您的<xliff:g id="TYPE_1">%2$s</xliff:g>。</item>
     </plurals>
     <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"知道了"</string>
-    <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
-    <skip />
+    <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"隱私權設定"</string>
     <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"使用<xliff:g id="TYPES_LIST">%s</xliff:g>的應用程式"</string>
     <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"使用<xliff:g id="TYPES_LIST">%s</xliff:g>的應用程式"</string>
     <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">"、 "</string>
@@ -895,8 +894,12 @@
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"感應器已關閉"</string>
     <string name="device_services" msgid="1191212554435440592">"裝置服務"</string>
     <string name="music_controls_no_title" msgid="5236895307087002011">"無標題"</string>
-    <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+    <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"開啟「<xliff:g id="APP_NAME">%1$s</xliff:g>」"</string>
+    <string name="bubbles_settings_button_description" msgid="1940331766151865776">"開啟「<xliff:g id="APP_NAME">%1$s</xliff:g>」的通知設定"</string>
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
     <skip />
-    <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 62b7cb6..d8d0c07 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -879,8 +879,7 @@
       <item quantity="one">有 <xliff:g id="NUM_APPS_0">%1$d</xliff:g> 個應用程式正在使用你的<xliff:g id="TYPE_1">%2$s</xliff:g>。</item>
     </plurals>
     <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"我知道了"</string>
-    <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
-    <skip />
+    <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"隱私權設定"</string>
     <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"使用<xliff:g id="TYPES_LIST">%s</xliff:g>的應用程式"</string>
     <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"使用<xliff:g id="TYPES_LIST">%s</xliff:g>的應用程式"</string>
     <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">"、 "</string>
@@ -895,8 +894,12 @@
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"已關閉感應器"</string>
     <string name="device_services" msgid="1191212554435440592">"裝置服務"</string>
     <string name="music_controls_no_title" msgid="5236895307087002011">"無標題"</string>
-    <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+    <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"開啟「<xliff:g id="APP_NAME">%1$s</xliff:g>」"</string>
+    <string name="bubbles_settings_button_description" msgid="1940331766151865776">"開啟「<xliff:g id="APP_NAME">%1$s</xliff:g>」的通知設定"</string>
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
     <skip />
-    <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index f8bf2e3..2e0efcc 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -879,8 +879,7 @@
       <item quantity="other"><xliff:g id="NUM_APPS_4">%1$d</xliff:g> izinhlelo zokusebenza zisebenzisa i-<xliff:g id="TYPE_5">%2$s</xliff:g> yakho.</item>
     </plurals>
     <string name="ongoing_privacy_dialog_ok" msgid="3273300106348958308">"Ngiyezwa"</string>
-    <!-- no translation found for ongoing_privacy_dialog_open_settings (6773015940472748876) -->
-    <skip />
+    <string name="ongoing_privacy_dialog_open_settings" msgid="6773015940472748876">"Izilungiselelo zobumfihlo"</string>
     <string name="ongoing_privacy_dialog_single_app_title" msgid="6019646962021696632">"Uhlelo lokusebenza olusebenzisa i-<xliff:g id="TYPES_LIST">%s</xliff:g> yakho"</string>
     <string name="ongoing_privacy_dialog_multiple_apps_title" msgid="8013356222977903365">"Izinhlelo zokusebenza ezisebenzisa i-<xliff:g id="TYPES_LIST">%s</xliff:g> yakho"</string>
     <string name="ongoing_privacy_dialog_separator" msgid="6854860652480837439">", "</string>
@@ -895,8 +894,12 @@
     <string name="sensor_privacy_mode" msgid="8982771253020769598">"Izinzwa zivaliwe"</string>
     <string name="device_services" msgid="1191212554435440592">"Amasevisi edivayisi"</string>
     <string name="music_controls_no_title" msgid="5236895307087002011">"Asikho isihloko"</string>
-    <!-- no translation found for bubbles_deep_link_button_description (8895837143057564517) -->
+    <string name="bubbles_deep_link_button_description" msgid="8895837143057564517">"Vula i-<xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="bubbles_settings_button_description" msgid="1940331766151865776">"VUla izilungiselelo zesaziso ze-<xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <!-- no translation found for bubbles_prompt (2684301469286150276) -->
     <skip />
-    <!-- no translation found for bubbles_settings_button_description (1940331766151865776) -->
+    <!-- no translation found for no_bubbles (7173621233904687258) -->
+    <skip />
+    <!-- no translation found for yes_bubbles (668809525728633841) -->
     <skip />
 </resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 0344535..1e1245f 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -967,7 +967,7 @@
     <!-- Height and width of App Opp icons in Ongoing App Ops dialog -->
     <dimen name="ongoing_appops_dialog_icon_size">24dp</dimen>
     <!-- Left margin of App Opp icons in Ongoing App Ops dialog -->
-    <dimen name="ongoing_appops_dialog_icon_margin">8dp</dimen>
+    <dimen name="ongoing_appops_dialog_icon_margin">12dp</dimen>
     <!-- Height and width of Application icons in Ongoing App Ops dialog -->
     <dimen name="ongoing_appops_dialog_app_icon_size">32dp</dimen>
     <!-- Height and width of Plus sign in Ongoing App Ops dialog -->
@@ -988,12 +988,14 @@
     <dimen name="ongoing_appops_chip_side_padding">6dp</dimen>
     <!-- Padding between background of Ongoing App Ops chip and content -->
     <dimen name="ongoing_appops_chip_bg_padding">0dp</dimen>
-    <!-- Margin between icons of Ongoing App Ops chip -->
-    <dimen name="ongoing_appops_chip_icon_margin">4dp</dimen>
+    <!-- Margin between icons of Ongoing App Ops chip when QQS-->
+    <dimen name="ongoing_appops_chip_icon_margin_collapsed">0dp</dimen>
+    <!-- Margin between icons of Ongoing App Ops chip when QS-->
+    <dimen name="ongoing_appops_chip_icon_margin_expanded">8dp</dimen>
     <!-- Icon size of Ongoing App Ops chip -->
     <dimen name="ongoing_appops_chip_icon_size">18dp</dimen>
     <!-- Radius of Ongoing App Ops chip corners -->
-    <dimen name="ongoing_appops_chip_bg_corner_radius">12dp</dimen>
+    <dimen name="ongoing_appops_chip_bg_corner_radius">4dp</dimen>
     <!-- Text size for Ongoing App Ops dialog title -->
     <dimen name="ongoing_appops_dialog_title_size">20sp</dimen>
     <!-- Text size for Ongoing App Ops dialog items -->
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index db4a6cc..89c6c8a 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2301,6 +2301,9 @@
     <!-- Content description for ongoing privacy chip. Use with multiple apps [CHAR LIMIT=NONE]-->
     <string name="ongoing_privacy_chip_content_multiple_apps">Applications are using your <xliff:g id="types_list" example="camera, location">%s</xliff:g>.</string>
 
+    <!-- Ongoing Privacy "Chip" in use text [CHAR LIMIT=10]-->
+    <string name="ongoing_privacy_chip_in_use">In use:</string>
+
     <!-- Content description for ongoing privacy chip. Use with multiple apps using same app op[CHAR LIMIT=NONE]-->
     <plurals name="ongoing_privacy_chip_content_multiple_apps_single_op">
         <item quantity="one"><xliff:g id="num_apps" example="1">%1$d</xliff:g> application is using your <xliff:g id="type" example="camera">%2$s</xliff:g>.</item>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputChannelCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputChannelCompat.java
new file mode 100644
index 0000000..f7ccb81
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputChannelCompat.java
@@ -0,0 +1,113 @@
+/**
+ * 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.systemui.shared.system;
+
+import android.os.Looper;
+import android.util.Pair;
+import android.view.BatchedInputEventReceiver;
+import android.view.Choreographer;
+import android.view.InputChannel;
+import android.view.InputEvent;
+import android.view.InputEventSender;
+
+/**
+ * @see android.view.InputChannel
+ */
+public class InputChannelCompat {
+
+    /**
+     * Callback for receiving event callbacks
+     */
+    public interface InputEventListener {
+        /**
+         * @param ev event to be handled
+         */
+        void onInputEvent(InputEvent ev);
+    }
+
+    /**
+     * Creates a dispatcher and receiver pair to better handle events across threads.
+     */
+    public static Pair<InputEventDispatcher, InputEventReceiver> createPair(String name,
+            Looper looper, Choreographer choreographer, InputEventListener listener) {
+        InputChannel[] channels = InputChannel.openInputChannelPair(name);
+
+        InputEventDispatcher dispatcher = new InputEventDispatcher(channels[0], looper);
+        InputEventReceiver receiver = new InputEventReceiver(channels[1], looper, choreographer,
+                listener);
+        return Pair.create(dispatcher, receiver);
+    }
+
+    /**
+     * @see BatchedInputEventReceiver
+     */
+    public static class InputEventReceiver {
+
+        private final BatchedInputEventReceiver mReceiver;
+        private final InputChannel mInputChannel;
+
+        public InputEventReceiver(InputChannel inputChannel, Looper looper,
+                Choreographer choreographer, final InputEventListener listener) {
+            mInputChannel = inputChannel;
+            mReceiver = new BatchedInputEventReceiver(inputChannel, looper, choreographer) {
+
+                @Override
+                public void onInputEvent(InputEvent event) {
+                    listener.onInputEvent(event);
+                    finishInputEvent(event, true /* handled */);
+                }
+            };
+        }
+
+        /**
+         * @see BatchedInputEventReceiver#dispose()
+         */
+        public void dispose() {
+            mReceiver.dispose();
+            mInputChannel.dispose();
+        }
+    }
+
+    /**
+     * @see InputEventSender
+     */
+    public static class InputEventDispatcher {
+
+        private final InputChannel mInputChannel;
+        private final InputEventSender mSender;
+
+        private InputEventDispatcher(InputChannel inputChannel, Looper looper) {
+            mInputChannel = inputChannel;
+            mSender = new InputEventSender(inputChannel, looper) { };
+        }
+
+        /**
+         * @see InputEventSender#sendInputEvent(int, InputEvent)
+         */
+        public void dispatch(InputEvent ev) {
+            mSender.sendInputEvent(ev.getSequenceNumber(), ev);
+        }
+
+        /**
+         * @see InputEventSender#dispose()
+         */
+        public void dispose() {
+            mSender.dispose();
+            mInputChannel.dispose();
+        }
+    }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
index 2bdbf0b..221782e 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
@@ -20,6 +20,7 @@
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.view.RemoteAnimationTarget;
+import android.view.SurfaceControl;
 
 /**
  * @see RemoteAnimationTarget
@@ -47,6 +48,8 @@
     public final boolean isNotInRecents;
     public final Rect contentInsets;
 
+    private final SurfaceControl mStartLeash;
+
     public RemoteAnimationTargetCompat(RemoteAnimationTarget app) {
         taskId = app.taskId;
         mode = app.mode;
@@ -59,6 +62,8 @@
         isNotInRecents = app.isNotInRecents;
         contentInsets = app.contentInsets;
         activityType = app.windowConfiguration.getActivityType();
+
+        mStartLeash = app.startLeash;
     }
 
     public static RemoteAnimationTargetCompat[] wrap(RemoteAnimationTarget[] apps) {
@@ -69,4 +74,14 @@
         }
         return appsCompat;
     }
+
+    /**
+     * @see SurfaceControl#release()
+     */
+    public void release() {
+        leash.mSurfaceControl.release();
+        if (mStartLeash != null) {
+            mStartLeash.release();
+        }
+    }
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
index d5bd2b2..1539582 100644
--- a/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
+++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextController.java
@@ -299,8 +299,9 @@
                 displayText.toString().split(mSeparator.toString()),
                 anySimReadyAndInService && !missingSimsWithSubs,
                 subsIds);
-        if (mCarrierTextCallback != null) {
-            handler.post(() -> mCarrierTextCallback.updateCarrierInfo(info));
+        final CarrierTextCallback callback = mCarrierTextCallback;
+        if (callback != null) {
+            handler.post(() -> callback.updateCarrierInfo(info));
         }
 
     }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index 7218acf..fc1843b 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -1,5 +1,6 @@
 package com.android.keyguard;
 
+import android.app.WallpaperManager;
 import android.content.Context;
 import android.graphics.Paint;
 import android.graphics.Paint.Style;
@@ -12,11 +13,13 @@
 
 import androidx.annotation.VisibleForTesting;
 
+import com.android.internal.colorextraction.ColorExtractor;
 import com.android.keyguard.clock.ClockManager;
 import com.android.systemui.Dependency;
+import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.plugins.ClockPlugin;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.StatusBarStateController;
 
 import java.util.TimeZone;
 
@@ -50,6 +53,8 @@
      * Maintain state so that a newly connected plugin can be initialized.
      */
     private float mDarkAmount;
+    private boolean mSupportsDarkText;
+    private int[] mColorPalette;
 
     private final StatusBarStateController.StateListener mStateListener =
             new StatusBarStateController.StateListener() {
@@ -72,6 +77,21 @@
 
     private ClockManager.ClockChangedListener mClockChangedListener = this::setClockPlugin;
 
+    /**
+     * Listener for changes to the color palette.
+     *
+     * The color palette changes when the wallpaper is changed.
+     */
+    private SysuiColorExtractor.OnColorsChangedListener mColorsListener = (extractor, which) -> {
+        if ((which & WallpaperManager.FLAG_LOCK) != 0) {
+            if (extractor instanceof SysuiColorExtractor) {
+                updateColors((SysuiColorExtractor) extractor);
+            } else {
+                updateColors(Dependency.get(SysuiColorExtractor.class));
+            }
+        }
+    };
+
     public KeyguardClockSwitch(Context context) {
         this(context, null);
     }
@@ -100,6 +120,9 @@
         super.onAttachedToWindow();
         Dependency.get(ClockManager.class).addOnClockChangedListener(mClockChangedListener);
         Dependency.get(StatusBarStateController.class).addCallback(mStateListener);
+        SysuiColorExtractor colorExtractor = Dependency.get(SysuiColorExtractor.class);
+        colorExtractor.addOnColorsChangedListener(mColorsListener);
+        updateColors(colorExtractor);
     }
 
     @Override
@@ -107,6 +130,8 @@
         super.onDetachedFromWindow();
         Dependency.get(ClockManager.class).removeOnClockChangedListener(mClockChangedListener);
         Dependency.get(StatusBarStateController.class).removeCallback(mStateListener);
+        Dependency.get(SysuiColorExtractor.class)
+            .removeOnColorsChangedListener(mColorsListener);
     }
 
     private void setClockPlugin(ClockPlugin plugin) {
@@ -149,6 +174,9 @@
         mClockPlugin.setStyle(getPaint().getStyle());
         mClockPlugin.setTextColor(getCurrentTextColor());
         mClockPlugin.setDarkAmount(mDarkAmount);
+        if (mColorPalette != null) {
+            mClockPlugin.setColorPalette(mSupportsDarkText, mColorPalette);
+        }
     }
 
     /**
@@ -246,6 +274,16 @@
         }
     }
 
+    private void updateColors(SysuiColorExtractor colorExtractor) {
+        ColorExtractor.GradientColors colors = colorExtractor.getColors(WallpaperManager.FLAG_LOCK,
+                true);
+        mSupportsDarkText = colors.supportsDarkText();
+        mColorPalette = colors.getColorPalette();
+        if (mClockPlugin != null) {
+            mClockPlugin.setColorPalette(mSupportsDarkText, mColorPalette);
+        }
+    }
+
     @VisibleForTesting (otherwise = VisibleForTesting.NONE)
     ClockManager.ClockChangedListener getClockChangedListener() {
         return mClockChangedListener;
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java b/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java
index db6127f..3114708 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/BubbleClockController.java
@@ -89,7 +89,17 @@
     @Override
     public void setTextColor(int color) {
         mLockClock.setTextColor(color);
-        mDigitalClock.setTextColor(color);
+    }
+
+    @Override
+    public void setColorPalette(boolean supportsDarkText, int[] colorPalette) {
+        if (colorPalette == null || colorPalette.length == 0) {
+            return;
+        }
+        final int length = colorPalette.length;
+        mDigitalClock.setTextColor(colorPalette[Math.max(0, length - 6)]);
+        mAnalogClock.setClockColors(colorPalette[Math.max(0, length - 6)],
+                colorPalette[Math.max(0, length - 3)]);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ImageClock.java b/packages/SystemUI/src/com/android/keyguard/clock/ImageClock.java
index 2c709e0..e35cf11 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/ImageClock.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/ImageClock.java
@@ -78,6 +78,16 @@
         mTime.setTimeZone(timeZone);
     }
 
+    /**
+     * Sets 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 setClockColors(int dark, int light) {
+        mHourHand.setColorFilter(dark);
+        mMinuteHand.setColorFilter(light);
+    }
+
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClock.java b/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClock.java
index 87347545..3c9a4f8 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClock.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClock.java
@@ -76,10 +76,12 @@
     }
 
     /**
-     * Set the color of the minute hand.
+     * 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 setMinuteHandColor(int color) {
-        mMinutePaint.setColor(color);
+    public void setClockColor(int dark, int light) {
+        mHourPaint.setColor(dark);
         invalidate();
     }
 
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClockController.java b/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClockController.java
index 0a39158..c465114 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClockController.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/StretchAnalogClockController.java
@@ -89,8 +89,17 @@
     @Override
     public void setTextColor(int color) {
         mLockClock.setTextColor(color);
-        mDigitalClock.setTextColor(color);
-        mAnalogClock.setMinuteHandColor(color);
+    }
+
+    @Override
+    public void setColorPalette(boolean supportsDarkText, int[] colorPalette) {
+        if (colorPalette == null || colorPalette.length == 0) {
+            return;
+        }
+        final int length = colorPalette.length;
+        mDigitalClock.setTextColor(colorPalette[Math.max(0, length - 5)]);
+        mAnalogClock.setClockColor(colorPalette[Math.max(0, length - 5)],
+                colorPalette[Math.max(0, length - 2)]);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/TypeClockController.java b/packages/SystemUI/src/com/android/keyguard/clock/TypeClockController.java
index 17d929d..2ea39c4 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/TypeClockController.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/TypeClockController.java
@@ -87,6 +87,15 @@
     }
 
     @Override
+    public void setColorPalette(boolean supportsDarkText, int[] colorPalette) {
+        if (colorPalette == null || colorPalette.length == 0) {
+            return;
+        }
+        final int length = colorPalette.length;
+        mTypeClock.setClockColor(colorPalette[Math.max(0, length - 5)]);
+    }
+
+    @Override
     public void dozeTimeTick() {
         mTypeClock.onTimeChanged();
     }
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/TypographicClock.java b/packages/SystemUI/src/com/android/keyguard/clock/TypographicClock.java
index 8feae53..6f1b59c 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/TypographicClock.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/TypographicClock.java
@@ -43,7 +43,7 @@
     private final Resources mResources;
     private final String[] mHours;
     private final String[] mMinutes;
-    private final int mAccentColor;
+    private int mAccentColor;
     private Calendar mTime;
     private String mDescFormat;
     private TimeZone mTimeZone;
@@ -106,6 +106,13 @@
         mTime.setTimeZone(timeZone);
     }
 
+    /**
+     * Sets the accent color used on the clock face.
+     */
+    public void setClockColor(int color) {
+        mAccentColor = color;
+    }
+
     @Override
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index fece94e..5672073 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -18,6 +18,7 @@
 import android.content.Context;
 import android.content.res.Configuration;
 import android.hardware.SensorPrivacyManager;
+import android.hardware.display.NightDisplayListener;
 import android.os.Handler;
 import android.os.Looper;
 import android.util.ArrayMap;
@@ -25,7 +26,6 @@
 import android.view.IWindowManager;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.app.ColorDisplayController;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.util.Preconditions;
@@ -42,6 +42,7 @@
 import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.plugins.PluginDependencyProvider;
 import com.android.systemui.plugins.VolumeDialogController;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.power.EnhancedEstimates;
 import com.android.systemui.power.PowerUI;
 import com.android.systemui.privacy.PrivacyItemController;
@@ -55,7 +56,6 @@
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.NotificationViewHierarchyManager;
 import com.android.systemui.statusbar.SmartReplyController;
-import com.android.systemui.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.VibratorHelper;
 import com.android.systemui.statusbar.notification.NotificationAlertingManager;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -206,7 +206,7 @@
     @Inject Lazy<UserInfoController> mUserInfoController;
     @Inject Lazy<KeyguardMonitor> mKeyguardMonitor;
     @Inject Lazy<BatteryController> mBatteryController;
-    @Inject Lazy<ColorDisplayController> mColorDisplayController;
+    @Inject Lazy<NightDisplayListener> mNightDisplayListener;
     @Inject Lazy<ManagedProfileController> mManagedProfileController;
     @Inject Lazy<NextAlarmController> mNextAlarmController;
     @Inject Lazy<DataSaverController> mDataSaverController;
@@ -330,7 +330,7 @@
 
         mProviders.put(BatteryController.class, mBatteryController::get);
 
-        mProviders.put(ColorDisplayController.class, mColorDisplayController::get);
+        mProviders.put(NightDisplayListener.class, mNightDisplayListener::get);
 
         mProviders.put(ManagedProfileController.class, mManagedProfileController::get);
 
diff --git a/packages/SystemUI/src/com/android/systemui/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/DependencyProvider.java
index 88e32cb..a517d7c 100644
--- a/packages/SystemUI/src/com/android/systemui/DependencyProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/DependencyProvider.java
@@ -24,6 +24,7 @@
 import android.annotation.Nullable;
 import android.content.Context;
 import android.hardware.SensorPrivacyManager;
+import android.hardware.display.NightDisplayListener;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Looper;
@@ -34,7 +35,6 @@
 import android.view.IWindowManager;
 import android.view.WindowManagerGlobal;
 
-import com.android.internal.app.ColorDisplayController;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
@@ -152,8 +152,8 @@
 
     @Singleton
     @Provides
-    public ColorDisplayController provideColorDisplayController(Context context) {
-        return new ColorDisplayController(context);
+    public NightDisplayListener provideNightDisplayListener(Context context) {
+        return new NightDisplayListener(context);
     }
 
     @Singleton
diff --git a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
index 5040942..2aecc24 100644
--- a/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
+++ b/packages/SystemUI/src/com/android/systemui/ImageWallpaper.java
@@ -19,11 +19,8 @@
 import static android.view.Display.DEFAULT_DISPLAY;
 
 import android.app.WallpaperManager;
-import android.content.BroadcastReceiver;
 import android.content.ComponentCallbacks2;
 import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.RecordingCanvas;
@@ -31,9 +28,7 @@
 import android.graphics.RectF;
 import android.graphics.Region.Op;
 import android.hardware.display.DisplayManager;
-import android.opengl.GLSurfaceView;
 import android.os.AsyncTask;
-import android.os.Build;
 import android.os.Handler;
 import android.os.Trace;
 import android.service.wallpaper.WallpaperService;
@@ -44,7 +39,6 @@
 import android.view.SurfaceHolder;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.glwallpaper.ImageWallpaperRenderer;
 
 import java.io.FileDescriptor;
 import java.io.IOException;
@@ -57,17 +51,12 @@
 public class ImageWallpaper extends WallpaperService {
     private static final String TAG = "ImageWallpaper";
     private static final String GL_LOG_TAG = "ImageWallpaperGL";
-    // TODO: Testing purpose, need to remove later, b/123616712.
-    private static final String SENSOR_EVENT_AWAKE = "systemui.test.event.awake";
-    // TODO: Testing purpose, need to remove later, b/123616712.
-    private static final String SENSOR_EVENT_SLEEP = "systemui.test.event.sleep";
     private static final boolean DEBUG = false;
     private static final String PROPERTY_KERNEL_QEMU = "ro.kernel.qemu";
     private static final long DELAY_FORGET_WALLPAPER = 5000;
 
     private WallpaperManager mWallpaperManager;
     private DrawableEngine mEngine;
-    private GLEngine mGlEngine;
 
     @Override
     public void onCreate() {
@@ -84,112 +73,10 @@
 
     @Override
     public Engine onCreateEngine() {
-        mGlEngine = new GLEngine(this);
-        return mGlEngine;
+        mEngine = new DrawableEngine();
+        return mEngine;
     }
 
-    class GLEngine extends Engine {
-        private GLWallpaperSurfaceView mWallpaperSurfaceView;
-
-        GLEngine(Context context) {
-            mWallpaperSurfaceView = new GLWallpaperSurfaceView(context);
-            mWallpaperSurfaceView.setRenderer(
-                    new ImageWallpaperRenderer(context, mWallpaperSurfaceView));
-            mWallpaperSurfaceView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
-            setOffsetNotificationsEnabled(true);
-        }
-
-        @Override
-        public void onAmbientModeChanged(boolean inAmbientMode, long animationDuration) {
-            if (mWallpaperSurfaceView != null) {
-                mWallpaperSurfaceView.notifyAmbientModeChanged(inAmbientMode);
-            }
-        }
-
-        @Override
-        public void onOffsetsChanged(float xOffset, float yOffset, float xOffsetStep,
-                float yOffsetStep, int xPixelOffset, int yPixelOffset) {
-            if (mWallpaperSurfaceView != null) {
-                mWallpaperSurfaceView.notifyOffsetsChanged(xOffset, yOffset);
-            }
-        }
-
-        private class GLWallpaperSurfaceView extends GLSurfaceView implements ImageGLView {
-            private SensorEventListener mEventListener;
-            private WallpaperStatusListener mWallpaperChangedListener;
-
-            // TODO: Testing purpose, need to remove later, b/123616712.
-            /**
-             * For testing only: adb shell am broadcast -a <INTENT>
-             */
-            private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
-                @Override
-                public void onReceive(Context context, Intent intent) {
-                    if (intent == null) {
-                        return;
-                    }
-                    switch (intent.getAction()) {
-                        case SENSOR_EVENT_AWAKE:
-                            notifySensorEvents(true);
-                            break;
-                        case SENSOR_EVENT_SLEEP:
-                            notifySensorEvents(false);
-                            break;
-                    }
-                }
-            };
-
-            GLWallpaperSurfaceView(Context context) {
-                super(context);
-                setEGLContextClientVersion(2);
-                // TODO: Testing purpose, need to remove later, b/123616712.
-                if (Build.IS_DEBUGGABLE) {
-                    IntentFilter filter = new IntentFilter();
-                    filter.addAction(SENSOR_EVENT_AWAKE);
-                    filter.addAction(SENSOR_EVENT_SLEEP);
-                    registerReceiver(mReceiver, filter);
-                }
-            }
-
-            @Override
-            public SurfaceHolder getHolder() {
-                return getSurfaceHolder();
-            }
-
-            @Override
-            public void setRenderer(Renderer renderer) {
-                super.setRenderer(renderer);
-                mEventListener = (SensorEventListener) renderer;
-                mWallpaperChangedListener = (WallpaperStatusListener) renderer;
-            }
-
-            private void notifySensorEvents(boolean reach) {
-                if (mEventListener != null) {
-                    mEventListener.onSensorEvent(reach);
-                }
-            }
-
-            private void notifyAmbientModeChanged(boolean inAmbient) {
-                if (mWallpaperChangedListener != null) {
-                    mWallpaperChangedListener.onAmbientModeChanged(inAmbient);
-                }
-            }
-
-            private void notifyOffsetsChanged(float xOffset, float yOffset) {
-                if (mWallpaperChangedListener != null) {
-                    mWallpaperChangedListener.onOffsetsChanged(
-                            xOffset, yOffset, getHolder().getSurfaceFrame());
-                }
-            }
-
-            @Override
-            public void render() {
-                requestRender();
-            }
-        }
-    }
-
-    // TODO: Remove this engine, tracking on b/123617158.
     class DrawableEngine extends Engine {
         private final Runnable mUnloadWallpaperCallback = () -> {
             unloadWallpaper(false /* forgetSize */);
@@ -677,46 +564,4 @@
             }
         }
     }
-
-    /**
-     * A listener to trace sensor event.
-     */
-    public interface SensorEventListener {
-
-        /**
-         * Called back while sensor event comes.
-         * @param reach The status of sensor.
-         */
-        void onSensorEvent(boolean reach);
-    }
-
-    /**
-     * A listener to trace status of image wallpaper.
-     */
-    public interface WallpaperStatusListener {
-
-        /**
-         * Called back while ambient mode changes.
-         * @param inAmbientMode true if is in ambient mode, false otherwise.
-         */
-        void onAmbientModeChanged(boolean inAmbientMode);
-
-        /**
-         * Called back while wallpaper offsets.
-         * @param xOffset The offset portion along x.
-         * @param yOffset The offset portion along y.
-         */
-        void onOffsetsChanged(float xOffset, float yOffset, Rect frame);
-    }
-
-    /**
-     * An abstraction for view of GLRenderer.
-     */
-    public interface ImageGLView {
-
-        /**
-         * Ask the view to render.
-         */
-        void render();
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index 9b3d7ed..755d6fc 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -33,6 +33,7 @@
 import com.android.systemui.classifier.FalsingManager;
 import com.android.systemui.fragments.FragmentService;
 import com.android.systemui.keyguard.DismissCallbackRegistry;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.power.EnhancedEstimates;
 import com.android.systemui.power.EnhancedEstimatesImpl;
 import com.android.systemui.statusbar.KeyguardIndicationController;
@@ -40,7 +41,7 @@
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationLockscreenUserManagerImpl;
 import com.android.systemui.statusbar.ScrimView;
-import com.android.systemui.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.StatusBarStateControllerImpl;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
 import com.android.systemui.statusbar.notification.collection.NotificationData;
@@ -152,6 +153,15 @@
         return new VolumeDialogComponent(systemUi, context);
     }
 
+    /**
+     * Provides status bar state controller implementation
+     */
+    @Singleton
+    @Provides
+    public StatusBarStateController provideStatusBarStateController(Context context) {
+        return new StatusBarStateControllerImpl();
+    }
+
     @Singleton
     @Provides
     public NotificationData.KeyguardEnvironment provideKeyguardEnvironment(Context context) {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index f36dca7..41bc1b2 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -16,6 +16,10 @@
 
 package com.android.systemui.bubbles;
 
+import static android.content.pm.ActivityInfo.DOCUMENT_LAUNCH_ALWAYS;
+import static android.util.StatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_MISSING;
+import static android.util.StatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_NOT_RESIZABLE;
+import static android.util.StatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__DOCUMENT_LAUNCH_NOT_ALWAYS;
 import static android.view.View.INVISIBLE;
 import static android.view.View.VISIBLE;
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
@@ -24,9 +28,11 @@
 import static com.android.systemui.statusbar.notification.NotificationAlertingManager.alertAgain;
 
 import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.ActivityTaskManager;
+import android.app.IActivityTaskManager;
 import android.app.INotificationManager;
 import android.app.Notification;
-import android.app.NotificationChannel;
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.pm.ActivityInfo;
@@ -37,6 +43,8 @@
 import android.provider.Settings;
 import android.service.notification.StatusBarNotification;
 import android.util.Log;
+import android.util.StatsLog;
+import android.view.Display;
 import android.view.LayoutInflater;
 import android.view.ViewGroup;
 import android.view.WindowManager;
@@ -48,7 +56,9 @@
 import com.android.internal.statusbar.NotificationVisibility;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
-import com.android.systemui.statusbar.StatusBarStateController;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.TaskStackChangeListener;
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
@@ -57,6 +67,7 @@
 import com.android.systemui.statusbar.phone.StatusBarWindowController;
 
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
@@ -70,7 +81,7 @@
  * The controller manages addition, removal, and visible state of bubbles on screen.
  */
 @Singleton
-public class BubbleController implements BubbleExpandedViewContainer.OnBubbleBlockedListener {
+public class BubbleController implements BubbleExpandedView.OnBubbleBlockedListener {
     private static final int MAX_BUBBLES = 5; // TODO: actually enforce this
 
     private static final String TAG = "BubbleController";
@@ -90,6 +101,8 @@
 
     private final Context mContext;
     private final NotificationEntryManager mNotificationEntryManager;
+    private final IActivityTaskManager mActivityTaskManager;
+    private final BubbleTaskStackListener mTaskStackListener;
     private BubbleStateChangeListener mStateChangeListener;
     private BubbleExpandListener mExpandListener;
     private LayoutInflater mInflater;
@@ -173,6 +186,10 @@
         mStatusBarWindowController = statusBarWindowController;
         mStatusBarStateListener = new StatusBarStateListener();
         Dependency.get(StatusBarStateController.class).addCallback(mStatusBarStateListener);
+
+        mActivityTaskManager = ActivityTaskManager.getService();
+        mTaskStackListener = new BubbleTaskStackListener();
+        ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskStackListener);
     }
 
     /**
@@ -427,11 +444,15 @@
     @Nullable
     private PendingIntent getValidBubbleIntent(NotificationEntry notif) {
         Notification notification = notif.notification.getNotification();
+        String packageName = notif.notification.getPackageName();
         Notification.BubbleMetadata data = notif.getBubbleMetadata();
-        if (data != null && canLaunchInActivityView(data.getIntent())) {
+        if (data != null && canLaunchInActivityView(data.getIntent(),
+                true /* enable logging for bubbles */, packageName)) {
             return data.getIntent();
-        } else if (shouldUseContentIntent(mContext)
-                && canLaunchInActivityView(notification.contentIntent)) {
+        }
+        if (shouldUseContentIntent(mContext)
+                && canLaunchInActivityView(notification.contentIntent,
+                false /* disable logging for notifications */, packageName)) {
             Log.d(TAG, "[addBubble " + notif.key
                     + "]: No appOverlayIntent, using contentIntent.");
             return notification.contentIntent;
@@ -442,16 +463,41 @@
 
     /**
      * Whether an intent is properly configured to display in an {@link android.app.ActivityView}.
+     *
+     * @param intent the pending intent of the bubble.
+     * @param enableLogging whether bubble developer error should be logged.
+     * @param packageName the notification package name for this bubble.
+     * @return
      */
-    private boolean canLaunchInActivityView(PendingIntent intent) {
+    private boolean canLaunchInActivityView(PendingIntent intent, boolean enableLogging,
+                                            String packageName) {
         if (intent == null) {
             return false;
         }
         ActivityInfo info =
                 intent.getIntent().resolveActivityInfo(mContext.getPackageManager(), 0);
-        return info != null
-                && ActivityInfo.isResizeableMode(info.resizeMode)
-                && (info.flags & ActivityInfo.FLAG_ALLOW_EMBEDDED) != 0;
+        if (info == null) {
+            if (enableLogging) {
+                StatsLog.write(StatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED, packageName,
+                        BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_MISSING);
+            }
+            return false;
+        }
+        if (!ActivityInfo.isResizeableMode(info.resizeMode)) {
+            if (enableLogging) {
+                StatsLog.write(StatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED, packageName,
+                        BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__ACTIVITY_INFO_NOT_RESIZABLE);
+            }
+            return false;
+        }
+        if (info.documentLaunchMode != DOCUMENT_LAUNCH_ALWAYS) {
+            if (enableLogging) {
+                StatsLog.write(StatsLog.BUBBLE_DEVELOPER_ERROR_REPORTED, packageName,
+                        BUBBLE_DEVELOPER_ERROR_REPORTED__ERROR__DOCUMENT_LAUNCH_NOT_ALWAYS);
+            }
+            return false;
+        }
+        return (info.flags & ActivityInfo.FLAG_ALLOW_EMBEDDED) != 0;
     }
 
     /**
@@ -460,20 +506,9 @@
     @VisibleForTesting
     protected boolean shouldBubble(NotificationEntry entry) {
         StatusBarNotification n = entry.notification;
-        boolean canAppOverlay = false;
-        try {
-            canAppOverlay = mNotificationManagerService.areBubblesAllowedForPackage(
-                    n.getPackageName(), n.getUid());
-        } catch (RemoteException e) {
-            Log.w(TAG, "Error calling NoMan to determine if app can overlay", e);
-        }
-
-        NotificationChannel channel = mNotificationEntryManager.getNotificationData().getChannel(
-                entry.key);
-        boolean canChannelOverlay = channel != null && channel.canBubble();
         boolean hasOverlayIntent = n.getNotification().getBubbleMetadata() != null
                 && n.getNotification().getBubbleMetadata().getIntent() != null;
-        return hasOverlayIntent && canChannelOverlay && canAppOverlay;
+        return hasOverlayIntent && entry.canBubble;
     }
 
     /**
@@ -512,6 +547,64 @@
                 || autoBubbleAll;
     }
 
+    /**
+     * This task stack listener is responsible for responding to tasks moved to the front
+     * which are on the default (main) display. When this happens, expanded bubbles must be
+     * collapsed so the user may interact with the app which was just moved to the front.
+     * <p>
+     * This listener is registered with SystemUI's ActivityManagerWrapper which dispatches
+     * these calls via a main thread Handler.
+     */
+    @MainThread
+    private class BubbleTaskStackListener extends TaskStackChangeListener {
+
+        @Nullable
+        private ActivityManager.StackInfo findStackInfo(int taskId) throws RemoteException {
+            final List<ActivityManager.StackInfo> stackInfoList =
+                    mActivityTaskManager.getAllStackInfos();
+            // Iterate through stacks from top to bottom.
+            final int stackCount = stackInfoList.size();
+            for (int stackIndex = 0; stackIndex < stackCount; stackIndex++) {
+                final ActivityManager.StackInfo stackInfo = stackInfoList.get(stackIndex);
+                // Iterate through tasks from top to bottom.
+                for (int taskIndex = stackInfo.taskIds.length - 1; taskIndex >= 0; taskIndex--) {
+                    if (stackInfo.taskIds[taskIndex] == taskId) {
+                        return stackInfo;
+                    }
+                }
+            }
+            return null;
+        }
+
+        @Override
+        public void onTaskMovedToFront(int taskId) {
+            ActivityManager.StackInfo stackInfo = null;
+            try {
+                stackInfo = findStackInfo(taskId);
+            } catch (RemoteException e) {
+                e.rethrowAsRuntimeException();
+            }
+            if (stackInfo != null && stackInfo.displayId == Display.DEFAULT_DISPLAY
+                    && mStackView != null) {
+                mStackView.collapseStack();
+            }
+        }
+
+        /**
+         * This is a workaround for the case when the activity had to be created in a new task.
+         * Existing code in ActivityStackSupervisor checks the display where the activity
+         * ultimately ended up, displays an error message toast, and calls this method instead of
+         * onTaskMovedToFront.
+         */
+        // TODO(b/124058588): add requestedDisplayId to this callback, ignore unless matches
+        @Override
+        public void onActivityLaunchOnSecondaryDisplayFailed() {
+            if (mStackView != null) {
+                mStackView.collapseStack();
+            }
+        }
+    }
+
     private static boolean shouldAutoBubbleMessages(Context context) {
         return Settings.Secure.getInt(context.getContentResolver(),
                 ENABLE_AUTO_BUBBLE_MESSAGES, 0) != 0;
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedViewContainer.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
similarity index 86%
rename from packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedViewContainer.java
rename to packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index f08ba19..976a766 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedViewContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -34,8 +34,10 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.provider.Settings;
+import android.service.notification.StatusBarNotification;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.util.StatsLog;
 import android.view.View;
 import android.widget.FrameLayout;
 import android.widget.ImageButton;
@@ -51,7 +53,7 @@
 /**
  * Container for the expanded bubble view, handles rendering the caret and header of the view.
  */
-public class BubbleExpandedViewContainer extends LinearLayout implements View.OnClickListener {
+public class BubbleExpandedView extends LinearLayout implements View.OnClickListener {
     private static final String TAG = "BubbleExpandedView";
 
     // The triangle pointing to the expanded view
@@ -81,19 +83,19 @@
 
     private OnBubbleBlockedListener mOnBubbleBlockedListener;
 
-    public BubbleExpandedViewContainer(Context context) {
+    public BubbleExpandedView(Context context) {
         this(context, null);
     }
 
-    public BubbleExpandedViewContainer(Context context, AttributeSet attrs) {
+    public BubbleExpandedView(Context context, AttributeSet attrs) {
         this(context, attrs, 0);
     }
 
-    public BubbleExpandedViewContainer(Context context, AttributeSet attrs, int defStyleAttr) {
+    public BubbleExpandedView(Context context, AttributeSet attrs, int defStyleAttr) {
         this(context, attrs, defStyleAttr, 0);
     }
 
-    public BubbleExpandedViewContainer(Context context, AttributeSet attrs, int defStyleAttr,
+    public BubbleExpandedView(Context context, AttributeSet attrs, int defStyleAttr,
             int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
         mPm = context.getPackageManager();
@@ -234,6 +236,8 @@
             mStackView.collapseStack(() -> {
                 try {
                     n.contentIntent.send();
+                    logBubbleClickEvent(mEntry.notification,
+                            StatsLog.BUBBLE_UICHANGED__ACTION__HEADER_GO_TO_APP);
                 } catch (PendingIntent.CanceledException e) {
                     Log.w(TAG, "Failed to send intent for bubble with key: "
                             + (mEntry != null ? mEntry.key : " null entry"));
@@ -242,7 +246,11 @@
         } else if (id == R.id.settings_button) {
             Intent intent = getSettingsIntent(mEntry.notification.getPackageName(),
                     mEntry.notification.getUid());
-            mStackView.collapseStack(() -> mContext.startActivity(intent));
+            mStackView.collapseStack(() -> {
+                mContext.startActivity(intent);
+                logBubbleClickEvent(mEntry.notification,
+                        StatsLog.BUBBLE_UICHANGED__ACTION__HEADER_GO_TO_SETTINGS);
+            });
         } else if (id == R.id.no_bubbles_button) {
             setBubblesAllowed(false);
         } else if (id == R.id.yes_bubbles_button) {
@@ -262,6 +270,9 @@
             } else if (mOnBubbleBlockedListener != null) {
                 mOnBubbleBlockedListener.onBubbleBlocked(mEntry);
             }
+            logBubbleClickEvent(mEntry.notification,
+                    allowed ? StatsLog.BUBBLE_UICHANGED__ACTION__PERMISSION_OPT_IN :
+                            StatsLog.BUBBLE_UICHANGED__ACTION__PERMISSION_OPT_OUT);
         } catch (RemoteException e) {
             Log.w(TAG, e);
         }
@@ -318,4 +329,22 @@
          */
         void onBubbleBlocked(NotificationEntry entry);
     }
+
+    /**
+     * Logs bubble UI click event.
+     *
+     * @param notification the bubble notification that user is interacting with.
+     * @param action the user interaction enum.
+     */
+    private void logBubbleClickEvent(StatusBarNotification notification, int action) {
+        StatsLog.write(StatsLog.BUBBLE_UI_CHANGED,
+                notification.getPackageName(),
+                notification.getNotification().getChannelId(),
+                notification.getId(),
+                mStackView.getBubbleIndex(mStackView.getExpandedBubble()),
+                mStackView.getBubbleCount(),
+                action,
+                mStackView.getNormalizedXPosition(),
+                mStackView.getNormalizedYPosition());
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index afa9f02..2b344f6 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -41,6 +41,7 @@
 import android.widget.FrameLayout;
 import android.widget.LinearLayout;
 
+import androidx.annotation.MainThread;
 import androidx.annotation.Nullable;
 import androidx.dynamicanimation.animation.DynamicAnimation;
 import androidx.dynamicanimation.animation.SpringAnimation;
@@ -94,7 +95,7 @@
     private StackAnimationController mStackAnimationController;
     private ExpandedAnimationController mExpandedAnimationController;
 
-    private BubbleExpandedViewContainer mExpandedViewContainer;
+    private BubbleExpandedView mExpandedViewContainer;
 
     private int mBubbleSize;
     private int mBubblePadding;
@@ -173,7 +174,7 @@
         mBubbleContainer.setClipChildren(false);
         addView(mBubbleContainer, new FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT));
 
-        mExpandedViewContainer = (BubbleExpandedViewContainer)
+        mExpandedViewContainer = (BubbleExpandedView)
                 LayoutInflater.from(context).inflate(R.layout.bubble_expanded_view,
                         this /* parent */, false /* attachToRoot */);
         mExpandedViewContainer.setElevation(elevation);
@@ -226,7 +227,7 @@
     /**
      * Sets the listener to notify when a bubble is blocked.
      */
-    public void setOnBlockedListener(BubbleExpandedViewContainer.OnBubbleBlockedListener listener) {
+    public void setOnBlockedListener(BubbleExpandedView.OnBubbleBlockedListener listener) {
         mExpandedViewContainer.setOnBlockedListener(listener);
     }
 
@@ -384,7 +385,10 @@
 
     /**
      * Collapses the stack of bubbles.
+     * <p>
+     * Must be called from the main thread.
      */
+    @MainThread
     public void collapseStack() {
         if (mIsExpanded) {
             // TODO: Save opened bubble & move it to top of stack
@@ -402,7 +406,10 @@
 
     /**
      * Expands the stack fo bubbles.
+     * <p>
+     * Must be called from the main thread.
      */
+    @MainThread
     public void expandStack() {
         if (!mIsExpanded) {
             mExpandedBubble = getTopBubble();
@@ -766,7 +773,7 @@
     /**
      * @return the number of bubbles in the stack view.
      */
-    private int getBubbleCount() {
+    public int getBubbleCount() {
         return mBubbleContainer.getChildCount();
     }
 
@@ -777,14 +784,14 @@
      * @return the index of the bubble view within the bubble stack. The range of the position
      * is between 0 and the bubble count minus 1.
      */
-    private int getBubbleIndex(BubbleView bubbleView) {
+    public int getBubbleIndex(BubbleView bubbleView) {
         return mBubbleContainer.indexOfChild(bubbleView);
     }
 
     /**
      * @return the normalized x-axis position of the bubble stack rounded to 4 decimal places.
      */
-    private float getNormalizedXPosition() {
+    public float getNormalizedXPosition() {
         return new BigDecimal(getPosition().x / mDisplaySize.x)
                 .setScale(4, RoundingMode.CEILING.HALF_UP)
                 .floatValue();
@@ -793,7 +800,7 @@
     /**
      * @return the normalized y-axis position of the bubble stack rounded to 4 decimal places.
      */
-    private float getNormalizedYPosition() {
+    public float getNormalizedYPosition() {
         return new BigDecimal(getPosition().y / mDisplaySize.y)
                 .setScale(4, RoundingMode.CEILING.HALF_UP)
                 .floatValue();
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java
index 2c23c0c..74ddc8f 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleView.java
@@ -22,6 +22,8 @@
 import android.app.PendingIntent;
 import android.content.Context;
 import android.graphics.Color;
+import android.graphics.Insets;
+import android.graphics.Point;
 import android.graphics.PointF;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
@@ -32,6 +34,7 @@
 import android.util.Log;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.WindowInsets;
 import android.widget.FrameLayout;
 import android.widget.LinearLayout;
 import android.widget.TextView;
@@ -266,6 +269,24 @@
                     }
                 }
             });
+            mActivityView.setOnApplyWindowInsetsListener((View view, WindowInsets insets) -> {
+                ActivityView activityView = (ActivityView) view;
+                // Here we assume that the position of the ActivityView on the screen
+                // remains regardless of IME status. When we move ActivityView, the
+                // forwardedInsets should be computed not against the current location
+                // and size, but against the post-moved location and size.
+                Point displaySize = new Point();
+                view.getContext().getDisplay().getSize(displaySize);
+                int[] windowLocation = view.getLocationOnScreen();
+                final int windowBottom = windowLocation[1] + view.getHeight();
+                final int keyboardHeight = insets.getSystemWindowInsetBottom()
+                        - insets.getStableInsetBottom();
+                final int insetsBottom = Math.max(0,
+                        windowBottom + keyboardHeight - displaySize.y);
+                activityView.setForwardedInsets(Insets.of(0, 0, 0, insetsBottom));
+                return view.onApplyWindowInsets(insets);
+            });
+
         }
         return mActivityView;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
index 4ff27b1..8f215ff 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
@@ -35,9 +35,9 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.UiOffloadThread;
 import com.android.systemui.analytics.DataCollector;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
 import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.StatusBarStateController.StateListener;
 import com.android.systemui.util.AsyncSensorManager;
 
 import java.io.PrintWriter;
diff --git a/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java b/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java
index fdf18ce..900ea72 100644
--- a/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java
+++ b/packages/SystemUI/src/com/android/systemui/colorextraction/SysuiColorExtractor.java
@@ -48,6 +48,7 @@
 @Singleton
 public class SysuiColorExtractor extends ColorExtractor implements Dumpable {
     private static final String TAG = "SysuiColorExtractor";
+    private final Tonal mTonal;
     private boolean mWallpaperVisible;
     private boolean mHasBackdrop;
     // Colors to return when the wallpaper isn't visible
@@ -61,6 +62,7 @@
     @VisibleForTesting
     public SysuiColorExtractor(Context context, ExtractionType type, boolean registerVisibility) {
         super(context, type);
+        mTonal = type instanceof Tonal ? (Tonal) type : new Tonal(context);
         mWpHiddenColors = new GradientColors();
 
         WallpaperColors systemColors = getWallpaperColors(WallpaperManager.FLAG_SYSTEM);
@@ -94,7 +96,7 @@
     }
 
     private void updateDefaultGradients(WallpaperColors colors) {
-        Tonal.applyFallback(colors, mWpHiddenColors);
+        mTonal.applyFallback(colors, mWpHiddenColors);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
index 4557b4d..d06feed 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeService.java
@@ -110,7 +110,8 @@
     @Override
     public void requestWakeUp() {
         PowerManager pm = getSystemService(PowerManager.class);
-        pm.wakeUp(SystemClock.uptimeMillis(), "com.android.systemui:NODOZE");
+        pm.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_GESTURE,
+                "com.android.systemui:NODOZE");
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLProgram.java b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLProgram.java
deleted file mode 100644
index d03b00b..0000000
--- a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLProgram.java
+++ /dev/null
@@ -1,115 +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.systemui.glwallpaper;
-
-import static android.opengl.GLES20.GL_FRAGMENT_SHADER;
-import static android.opengl.GLES20.GL_VERTEX_SHADER;
-import static android.opengl.GLES20.glAttachShader;
-import static android.opengl.GLES20.glCompileShader;
-import static android.opengl.GLES20.glCreateProgram;
-import static android.opengl.GLES20.glCreateShader;
-import static android.opengl.GLES20.glGetAttribLocation;
-import static android.opengl.GLES20.glGetUniformLocation;
-import static android.opengl.GLES20.glLinkProgram;
-import static android.opengl.GLES20.glShaderSource;
-import static android.opengl.GLES20.glUseProgram;
-
-import android.content.Context;
-import android.content.res.Resources;
-import android.util.Log;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStreamReader;
-
-/**
- * This class takes charge of linking shader codes and then return a handle for OpenGL ES program.
- */
-class ImageGLProgram {
-    private static final String TAG = ImageGLProgram.class.getSimpleName();
-
-    private Context mContext;
-    private int mProgramHandle;
-
-    ImageGLProgram(Context context) {
-        mContext = context.getApplicationContext();
-    }
-
-    private int loadShaderProgram(int vertexId, int fragmentId) {
-        final String vertexSrc = getShaderResource(vertexId);
-        final String fragmentSrc = getShaderResource(fragmentId);
-        final int vertexHandle = getShaderHandle(GL_VERTEX_SHADER, vertexSrc);
-        final int fragmentHandle = getShaderHandle(GL_FRAGMENT_SHADER, fragmentSrc);
-        return getProgramHandle(vertexHandle, fragmentHandle);
-    }
-
-    private String getShaderResource(int shaderId) {
-        Resources res = mContext.getResources();
-        StringBuilder code = new StringBuilder();
-
-        try (BufferedReader reader = new BufferedReader(
-                new InputStreamReader(res.openRawResource(shaderId)))) {
-            String nextLine;
-            while ((nextLine = reader.readLine()) != null) {
-                code.append(nextLine).append("\n");
-            }
-        } catch (IOException | Resources.NotFoundException ex) {
-            Log.d(TAG, "Can not read the shader source", ex);
-            code = null;
-        }
-
-        return code == null ? "" : code.toString();
-    }
-
-    private int getShaderHandle(int type, String src) {
-        final int shader = glCreateShader(type);
-        if (shader == 0) {
-            Log.d(TAG, "Create shader failed, type=" + type);
-            return 0;
-        }
-        glShaderSource(shader, src);
-        glCompileShader(shader);
-        return shader;
-    }
-
-    private int getProgramHandle(int vertexHandle, int fragmentHandle) {
-        final int program = glCreateProgram();
-        if (program == 0) {
-            Log.d(TAG, "Can not create OpenGL ES program");
-            return 0;
-        }
-
-        glAttachShader(program, vertexHandle);
-        glAttachShader(program, fragmentHandle);
-        glLinkProgram(program);
-        return program;
-    }
-
-    boolean useGLProgram(int vertexResId, int fragmentResId) {
-        mProgramHandle = loadShaderProgram(vertexResId, fragmentResId);
-        glUseProgram(mProgramHandle);
-        return true;
-    }
-
-    int getAttributeHandle(String name) {
-        return glGetAttribLocation(mProgramHandle, name);
-    }
-
-    int getUniformHandle(String name) {
-        return glGetUniformLocation(mProgramHandle, name);
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLWallpaper.java b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLWallpaper.java
deleted file mode 100644
index 4e07872..0000000
--- a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageGLWallpaper.java
+++ /dev/null
@@ -1,245 +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.systemui.glwallpaper;
-
-import static android.opengl.GLES20.GL_FLOAT;
-import static android.opengl.GLES20.GL_LINEAR;
-import static android.opengl.GLES20.GL_TEXTURE0;
-import static android.opengl.GLES20.GL_TEXTURE_2D;
-import static android.opengl.GLES20.GL_TEXTURE_MAG_FILTER;
-import static android.opengl.GLES20.GL_TEXTURE_MIN_FILTER;
-import static android.opengl.GLES20.GL_TRIANGLES;
-import static android.opengl.GLES20.glActiveTexture;
-import static android.opengl.GLES20.glBindTexture;
-import static android.opengl.GLES20.glDrawArrays;
-import static android.opengl.GLES20.glEnableVertexAttribArray;
-import static android.opengl.GLES20.glGenTextures;
-import static android.opengl.GLES20.glTexParameteri;
-import static android.opengl.GLES20.glUniform1i;
-import static android.opengl.GLES20.glVertexAttribPointer;
-
-import android.graphics.Bitmap;
-import android.opengl.GLUtils;
-import android.util.Log;
-
-import java.nio.ByteBuffer;
-import java.nio.ByteOrder;
-import java.nio.FloatBuffer;
-
-/**
- * This class takes charge of the geometry data like vertices and texture coordinates.
- * It delivers these data to opengl runtime and triggers draw calls if necessary.
- */
-class ImageGLWallpaper {
-    private static final String TAG = ImageGLWallpaper.class.getSimpleName();
-
-    static final String A_POSITION = "aPosition";
-    static final String A_TEXTURE_COORDINATES = "aTextureCoordinates";
-    static final String U_CENTER_REVEAL = "uCenterReveal";
-    static final String U_REVEAL = "uReveal";
-    static final String U_AOD2OPACITY = "uAod2Opacity";
-    static final String U_TEXTURE = "uTexture";
-    static final String U_AOD_MODE = "uAodMode";
-
-    private static final int HANDLE_UNDEFINED = -1;
-    private static final int POSITION_COMPONENT_COUNT = 2;
-    private static final int TEXTURE_COMPONENT_COUNT = 2;
-    private static final int BYTES_PER_FLOAT = 4;
-
-    // Vertices to define the square with 2 triangles.
-    private static final float[] VERTICES = {
-            -1.0f,  -1.0f,
-            +1.0f,  -1.0f,
-            +1.0f,  +1.0f,
-            +1.0f,  +1.0f,
-            -1.0f,  +1.0f,
-            -1.0f,  -1.0f
-    };
-
-    // Texture coordinates that maps to vertices.
-    private static final float[] TEXTURES = {
-            0f, 1f,
-            1f, 1f,
-            1f, 0f,
-            1f, 0f,
-            0f, 0f,
-            0f, 1f
-    };
-
-    private final FloatBuffer mVertexBuffer;
-    private final FloatBuffer mTextureBuffer;
-    private final ImageGLProgram mProgram;
-
-    private int mAttrPosition;
-    private int mAttrTextureCoordinates;
-    private int mUniAod2Opacity;
-    private int mUniAodMode;
-    private int mUniCenterReveal;
-    private int mUniReveal;
-    private int mUniTexture;
-    private int mTextureId;
-
-    ImageGLWallpaper(ImageGLProgram program) {
-        mProgram = program;
-
-        // Create an float array in opengles runtime (native) and put vertex data.
-        mVertexBuffer = ByteBuffer.allocateDirect(VERTICES.length * BYTES_PER_FLOAT)
-            .order(ByteOrder.nativeOrder())
-            .asFloatBuffer();
-        mVertexBuffer.put(VERTICES);
-        mVertexBuffer.position(0);
-
-        // Create an float array in opengles runtime (native) and put texture data.
-        mTextureBuffer = ByteBuffer.allocateDirect(TEXTURES.length * BYTES_PER_FLOAT)
-            .order(ByteOrder.nativeOrder())
-            .asFloatBuffer();
-        mTextureBuffer.put(TEXTURES);
-        mTextureBuffer.position(0);
-    }
-
-    void setup() {
-        setupAttributes();
-        setupUniforms();
-    }
-
-    private void setupAttributes() {
-        mAttrPosition = mProgram.getAttributeHandle(A_POSITION);
-        mVertexBuffer.position(0);
-        glVertexAttribPointer(mAttrPosition, POSITION_COMPONENT_COUNT, GL_FLOAT,
-                false, 0, mVertexBuffer);
-        glEnableVertexAttribArray(mAttrPosition);
-
-        mAttrTextureCoordinates = mProgram.getAttributeHandle(A_TEXTURE_COORDINATES);
-        mTextureBuffer.position(0);
-        glVertexAttribPointer(mAttrTextureCoordinates, TEXTURE_COMPONENT_COUNT, GL_FLOAT,
-                false, 0, mTextureBuffer);
-        glEnableVertexAttribArray(mAttrTextureCoordinates);
-    }
-
-    private void setupUniforms() {
-        mUniAod2Opacity = mProgram.getUniformHandle(U_AOD2OPACITY);
-        mUniAodMode = mProgram.getUniformHandle(U_AOD_MODE);
-        mUniCenterReveal = mProgram.getUniformHandle(U_CENTER_REVEAL);
-        mUniReveal = mProgram.getUniformHandle(U_REVEAL);
-        mUniTexture = mProgram.getUniformHandle(U_TEXTURE);
-    }
-
-    int getHandle(String name) {
-        switch (name) {
-            case A_POSITION:
-                return mAttrPosition;
-            case A_TEXTURE_COORDINATES:
-                return mAttrTextureCoordinates;
-            case U_AOD2OPACITY:
-                return mUniAod2Opacity;
-            case U_AOD_MODE:
-                return mUniAodMode;
-            case U_CENTER_REVEAL:
-                return mUniCenterReveal;
-            case U_REVEAL:
-                return mUniReveal;
-            case U_TEXTURE:
-                return mUniTexture;
-            default:
-                return HANDLE_UNDEFINED;
-        }
-    }
-
-    void draw() {
-        glDrawArrays(GL_TRIANGLES, 0, VERTICES.length / 2);
-    }
-
-    void setupTexture(Bitmap bitmap) {
-        final int[] tids = new int[1];
-
-        if (bitmap == null) {
-            Log.w(TAG, "setupTexture: invalid bitmap");
-            return;
-        }
-
-        // Generate one texture object and store the id in tids[0].
-        glGenTextures(1, tids, 0);
-        if (tids[0] == 0) {
-            Log.w(TAG, "setupTexture: glGenTextures() failed");
-            return;
-        }
-
-        // Bind a named texture to a texturing target.
-        glBindTexture(GL_TEXTURE_2D, tids[0]);
-        // Load the bitmap data and copy it over into the texture object that is currently bound.
-        GLUtils.texImage2D(GL_TEXTURE_2D, 0, bitmap, 0);
-        // Use bilinear texture filtering when minification.
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-        // Use bilinear texture filtering when magnification.
-        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-
-        mTextureId = tids[0];
-    }
-
-    void useTexture() {
-        // Set the active texture unit to texture unit 0.
-        glActiveTexture(GL_TEXTURE0);
-        // Bind the texture to this unit.
-        glBindTexture(GL_TEXTURE_2D, mTextureId);
-        // Let the texture sampler in fragment shader to read form this texture unit.
-        glUniform1i(mUniTexture, 0);
-    }
-
-    void adjustTextureCoordinates(Bitmap bitmap, int surfaceWidth, int surfaceHeight,
-            float xOffset, float yOffset) {
-        if (bitmap == null) {
-            Log.d(TAG, "adjustTextureCoordinates: invalid bitmap");
-            return;
-        }
-
-        float ratioW = 1f;
-        float ratioH = 1f;
-        int bitmapWidth = bitmap.getWidth();
-        int bitmapHeight = bitmap.getHeight();
-
-        boolean adjustWidth = bitmapWidth > surfaceWidth;
-        if (adjustWidth) {
-            ratioW = (float) surfaceWidth / bitmapWidth;
-            float referenceX = xOffset + ratioW > 1f ? 1f - ratioW : xOffset;
-            for (int i = 0; i < TEXTURES.length; i += 2) {
-                if (i == 2 || i == 4 || i == 6) {
-                    TEXTURES[i] = Math.min(1f, referenceX + ratioW);
-                } else {
-                    TEXTURES[i] = referenceX;
-                }
-            }
-        }
-
-        boolean adjustHeight = bitmapHeight > surfaceHeight;
-        if (adjustHeight) {
-            ratioH = (float) surfaceHeight / bitmapHeight;
-            float referenceY = yOffset + ratioH > 1f ? 1f - ratioH : yOffset;
-            for (int i = 1; i < TEXTURES.length; i += 2) {
-                if (i == 1 || i == 3 || i == 11) {
-                    TEXTURES[i] = Math.min(1f, referenceY + ratioH);
-                } else {
-                    TEXTURES[i] = referenceY;
-                }
-            }
-        }
-
-        if (adjustWidth || adjustHeight) {
-            mTextureBuffer.put(TEXTURES);
-            mTextureBuffer.position(0);
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageProcessHelper.java b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageProcessHelper.java
deleted file mode 100644
index 477e7d7e..0000000
--- a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageProcessHelper.java
+++ /dev/null
@@ -1,144 +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.systemui.glwallpaper;
-
-import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.ColorMatrix;
-import android.graphics.ColorMatrixColorFilter;
-import android.graphics.Matrix;
-import android.graphics.Paint;
-import android.os.AsyncTask;
-import android.os.Handler;
-import android.os.Handler.Callback;
-import android.os.Message;
-import android.util.Log;
-
-/**
- * A helper class that computes histogram and percentile 85 from a bitmap.
- * Percentile 85 will be computed each time the user picks a new image wallpaper.
- */
-class ImageProcessHelper {
-    private static final String TAG = ImageProcessHelper.class.getSimpleName();
-    private static final float DEFAULT_PER85 = 0.8f;
-    private static final int MSG_UPDATE_PER85 = 1;
-
-    /**
-     * This color matrix will be applied to each pixel to get luminance from rgb by below formula:
-     * Luminance = .2126f * r + .7152f * g + .0722f * b.
-     */
-    private static final float[] LUMINOSITY_MATRIX = new float[] {
-            .2126f,     .0000f,     .0000f,     .0000f,     .0000f,
-            .0000f,     .7152f,     .0000f,     .0000f,     .0000f,
-            .0000f,     .0000f,     .0722f,     .0000f,     .0000f,
-            .0000f,     .0000f,     .0000f,     1.000f,     .0000f
-    };
-
-    private final Handler mHandler = new Handler(new Callback() {
-        @Override
-        public boolean handleMessage(Message msg) {
-            switch (msg.what) {
-                case MSG_UPDATE_PER85:
-                    mPer85 = (float) msg.obj;
-                    return true;
-                default:
-                    return false;
-            }
-        }
-    });
-
-    private float mPer85 = DEFAULT_PER85;
-
-    void startComputingPercentile85(Bitmap bitmap) {
-        new Per85ComputeTask(mHandler).execute(bitmap);
-    }
-
-    float getPercentile85() {
-        return mPer85;
-    }
-
-    private static class Per85ComputeTask extends AsyncTask<Bitmap, Void, Float> {
-        private Handler mUpdateHandler;
-
-        Per85ComputeTask(Handler handler) {
-            super(handler);
-            mUpdateHandler = handler;
-        }
-
-        @Override
-        protected Float doInBackground(Bitmap... bitmaps) {
-            Bitmap bitmap = bitmaps[0];
-            if (bitmap != null) {
-                int[] histogram = processHistogram(bitmap);
-                return computePercentile85(bitmap, histogram);
-            }
-            Log.e(TAG, "Per85ComputeTask: Can't get bitmap");
-            return DEFAULT_PER85;
-        }
-
-        @Override
-        protected void onPostExecute(Float result) {
-            Message msg = mUpdateHandler.obtainMessage(MSG_UPDATE_PER85, result);
-            mUpdateHandler.sendMessage(msg);
-        }
-
-        private int[] processHistogram(Bitmap bitmap) {
-            int width = bitmap.getWidth();
-            int height = bitmap.getHeight();
-
-            Bitmap target = Bitmap.createBitmap(width, height, bitmap.getConfig());
-            Canvas canvas = new Canvas(target);
-            ColorMatrix cm = new ColorMatrix(LUMINOSITY_MATRIX);
-            Paint paint = new Paint();
-            paint.setColorFilter(new ColorMatrixColorFilter(cm));
-            canvas.drawBitmap(bitmap, new Matrix(), paint);
-
-            // TODO: Fine tune the performance here, tracking on b/123615079.
-            int[] histogram = new int[256];
-            for (int row = 0; row < height; row++) {
-                for (int col = 0; col < width; col++) {
-                    int pixel = target.getPixel(col, row);
-                    int y = Color.red(pixel) + Color.green(pixel) + Color.blue(pixel);
-                    histogram[y]++;
-                }
-            }
-
-            return histogram;
-        }
-
-        private float computePercentile85(Bitmap bitmap, int[] histogram) {
-            float per85 = DEFAULT_PER85;
-            int pixelCount = bitmap.getWidth() * bitmap.getHeight();
-            float[] acc = new float[256];
-            for (int i = 0; i < acc.length; i++) {
-                acc[i] = (float) histogram[i] / pixelCount;
-                float prev = i == 0 ? 0f : acc[i - 1];
-                float next = acc[i];
-                float idx = (float) (i + 1) / 255;
-                float sum = prev + next;
-                if (prev < 0.85f && sum >= 0.85f) {
-                    per85 = idx;
-                }
-                if (i > 0) {
-                    acc[i] += acc[i - 1];
-                }
-            }
-            return per85;
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageRevealHelper.java b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageRevealHelper.java
deleted file mode 100644
index 787972c..0000000
--- a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageRevealHelper.java
+++ /dev/null
@@ -1,103 +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.systemui.glwallpaper;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ValueAnimator;
-
-import com.android.systemui.Interpolators;
-
-/**
- * Use ValueAnimator and appropriate interpolator to control the progress of reveal transition.
- * The transition will happen while getting awake and quit events.
- */
-class ImageRevealHelper {
-    private static final String TAG = ImageRevealHelper.class.getSimpleName();
-    private static final float MAX_REVEAL = 0f;
-    private static final float MIN_REVEAL = 1f;
-    private static final int REVEAL_DURATION = 1000;
-
-    private final ValueAnimator mAnimator;
-    private final RevealStateListener mRevealListener;
-    private float mReveal = MIN_REVEAL;
-    private boolean mAwake = false;
-
-    ImageRevealHelper(RevealStateListener listener) {
-        mRevealListener = listener;
-        mAnimator = ValueAnimator.ofFloat();
-        mAnimator.setDuration(REVEAL_DURATION);
-        mAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
-        mAnimator.addUpdateListener(animator -> {
-            mReveal = (float) animator.getAnimatedValue();
-            if (mRevealListener != null) {
-                mRevealListener.onRevealStateChanged();
-            }
-        });
-        mAnimator.addListener(new AnimatorListenerAdapter() {
-            private boolean mIsCanceled;
-
-            @Override
-            public void onAnimationCancel(Animator animation) {
-                mIsCanceled = true;
-            }
-
-            @Override
-            public void onAnimationEnd(Animator animation) {
-                if (!mIsCanceled) {
-                    mAwake = !mAwake;
-                }
-                mIsCanceled = false;
-            }
-        });
-    }
-
-    private void animate() {
-        mAnimator.cancel();
-        mAnimator.setFloatValues(mReveal, !mAwake ? MIN_REVEAL : MAX_REVEAL);
-        mAnimator.start();
-    }
-
-    public float getReveal() {
-        return mReveal;
-    }
-
-    public boolean isAwake() {
-        return mAwake;
-    }
-
-    void updateAwake(boolean awake) {
-        mAwake = awake;
-        animate();
-    }
-
-    void sleep() {
-        mReveal = MIN_REVEAL;
-        mAwake = false;
-    }
-
-    /**
-     * A listener to trace value changes of reveal.
-     */
-    public interface RevealStateListener {
-
-        /**
-         * Called back while reveal status changes.
-         */
-        void onRevealStateChanged();
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java b/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java
deleted file mode 100644
index 8916b28..0000000
--- a/packages/SystemUI/src/com/android/systemui/glwallpaper/ImageWallpaperRenderer.java
+++ /dev/null
@@ -1,153 +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.systemui.glwallpaper;
-
-import static android.opengl.GLES20.GL_COLOR_BUFFER_BIT;
-import static android.opengl.GLES20.glClear;
-import static android.opengl.GLES20.glClearColor;
-import static android.opengl.GLES20.glUniform1f;
-import static android.opengl.GLES20.glUniform1i;
-import static android.opengl.GLES20.glViewport;
-
-import android.app.WallpaperManager;
-import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.Rect;
-import android.opengl.GLSurfaceView;
-import android.util.Log;
-
-import com.android.systemui.ImageWallpaper;
-import com.android.systemui.ImageWallpaper.ImageGLView;
-import com.android.systemui.R;
-
-import javax.microedition.khronos.egl.EGLConfig;
-import javax.microedition.khronos.opengles.GL10;
-
-/**
- * A GL renderer for image wallpaper.
- */
-public class ImageWallpaperRenderer implements GLSurfaceView.Renderer,
-        ImageWallpaper.SensorEventListener, ImageWallpaper.WallpaperStatusListener,
-        ImageRevealHelper.RevealStateListener {
-    private static final String TAG = ImageWallpaperRenderer.class.getSimpleName();
-
-    private final WallpaperManager mWallpaperManager;
-    private final ImageGLProgram mProgram;
-    private final ImageGLWallpaper mWallpaper;
-    private final ImageProcessHelper mImageProcessHelper;
-    private final ImageRevealHelper mImageRevealHelper;
-    private final ImageGLView mGLView;
-    private boolean mIsInAmbientMode;
-    private float mXOffset = 0f;
-    private float mYOffset = 0f;
-
-    public ImageWallpaperRenderer(Context context, ImageGLView glView) {
-        mWallpaperManager = context.getSystemService(WallpaperManager.class);
-        if (mWallpaperManager == null) {
-            Log.w(TAG, "WallpaperManager not available");
-        }
-
-        mProgram = new ImageGLProgram(context);
-        mWallpaper = new ImageGLWallpaper(mProgram);
-        mImageProcessHelper = new ImageProcessHelper();
-        mImageRevealHelper = new ImageRevealHelper(this);
-        mGLView = glView;
-
-        if (mWallpaperManager != null) {
-            // Compute per85 as transition threshold, this is an async work.
-            mImageProcessHelper.startComputingPercentile85(mWallpaperManager.getBitmap());
-        }
-    }
-
-    @Override
-    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
-        glClearColor(0f, 0f, 0f, 1.0f);
-        mProgram.useGLProgram(
-                R.raw.image_wallpaper_vertex_shader, R.raw.image_wallpaper_fragment_shader);
-        mWallpaper.setup();
-        mWallpaper.setupTexture(mWallpaperManager.getBitmap());
-    }
-
-    @Override
-    public void onSurfaceChanged(GL10 gl, int width, int height) {
-        glViewport(0, 0, width, height);
-        mWallpaper.adjustTextureCoordinates(mWallpaperManager.getBitmap(),
-                width, height, mXOffset, mYOffset);
-    }
-
-    @Override
-    public void onDrawFrame(GL10 gl) {
-        float threshold = mImageProcessHelper.getPercentile85();
-        float reveal = mImageRevealHelper.getReveal();
-
-        glClear(GL_COLOR_BUFFER_BIT);
-
-        glUniform1f(mWallpaper.getHandle(ImageGLWallpaper.U_AOD2OPACITY), .25f);
-        glUniform1f(mWallpaper.getHandle(ImageGLWallpaper.U_CENTER_REVEAL), threshold);
-        glUniform1f(mWallpaper.getHandle(ImageGLWallpaper.U_REVEAL), reveal);
-        glUniform1i(mWallpaper.getHandle(ImageGLWallpaper.U_AOD_MODE), mIsInAmbientMode ? 1 : 0);
-
-        mWallpaper.useTexture();
-        mWallpaper.draw();
-    }
-
-    @Override
-    public void onSensorEvent(boolean awake) {
-        mImageRevealHelper.updateAwake(awake);
-    }
-
-    @Override
-    public void onAmbientModeChanged(boolean inAmbientMode) {
-        mIsInAmbientMode = inAmbientMode;
-        if (inAmbientMode) {
-            mImageRevealHelper.sleep();
-        }
-        requestRender();
-    }
-
-    @Override
-    public void onOffsetsChanged(float xOffset, float yOffset, Rect frame) {
-        if (frame == null || mWallpaperManager == null
-                || (xOffset == mXOffset && yOffset == mYOffset)) {
-            return;
-        }
-
-        Bitmap bitmap = mWallpaperManager.getBitmap();
-        if (bitmap == null) {
-            return;
-        }
-
-        int width = frame.width();
-        int height = frame.height();
-        mXOffset = xOffset;
-        mYOffset = yOffset;
-
-        mWallpaper.adjustTextureCoordinates(bitmap, width, height, mXOffset, mYOffset);
-        requestRender();
-    }
-
-    @Override
-    public void onRevealStateChanged() {
-        requestRender();
-    }
-
-    private void requestRender() {
-        if (mGLView != null) {
-            mGLView.render();
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
index c4c8bc7..684175c 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
@@ -51,8 +51,8 @@
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.systemui.R;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.NotificationMediaManager;
-import com.android.systemui.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.policy.NextAlarmController;
 import com.android.systemui.statusbar.policy.NextAlarmControllerImpl;
 import com.android.systemui.statusbar.policy.ZenModeController;
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index 4527f73..66cfadf 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -884,6 +884,7 @@
 
                 // Just to make sure, make sure the device is awake.
                 mContext.getSystemService(PowerManager.class).wakeUp(SystemClock.uptimeMillis(),
+                        PowerManager.WAKE_REASON_CAMERA_LAUNCH,
                         "com.android.systemui:CAMERA_GESTURE_PREVENT_LOCK");
                 mPendingLock = false;
                 mPendingReset = false;
@@ -1854,8 +1855,9 @@
 
         // It's possible that the device was unlocked in a dream state. It's time to wake up.
         if (mAodShowing) {
-            PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
-            pm.wakeUp(SystemClock.uptimeMillis(), "com.android.systemui:BOUNCER_DOZING");
+            PowerManager pm = mContext.getSystemService(PowerManager.class);
+            pm.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_GESTURE,
+                    "com.android.systemui:BOUNCER_DOZING");
         }
 
         synchronized (KeyguardViewMediator.this) {
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt
index 65ed889..ecbf024 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyChip.kt
@@ -16,6 +16,7 @@
 
 import android.content.Context
 import android.util.AttributeSet
+import android.view.View
 import android.view.ViewGroup
 import android.widget.ImageView
 import android.widget.LinearLayout
@@ -29,14 +30,25 @@
     defStyleRes: Int = 0
 ) : LinearLayout(context, attrs, defStyleAttrs, defStyleRes) {
 
-    private val iconMargin =
-            context.resources.getDimensionPixelSize(R.dimen.ongoing_appops_chip_icon_margin)
+    private val iconMarginExpanded = context.resources.getDimensionPixelSize(
+                    R.dimen.ongoing_appops_chip_icon_margin_expanded)
+    private val iconMarginCollapsed = context.resources.getDimensionPixelSize(
+                    R.dimen.ongoing_appops_chip_icon_margin_collapsed)
     private val iconSize =
             context.resources.getDimensionPixelSize(R.dimen.ongoing_appops_chip_icon_size)
-    val iconColor = context.resources.getColor(
+    private val iconColor = context.resources.getColor(
             R.color.status_bar_clock_color, context.theme)
+    private val backgroundDrawable = context.getDrawable(R.drawable.privacy_chip_bg)
     private lateinit var text: TextView
     private lateinit var iconsContainer: LinearLayout
+    private lateinit var inUseText: TextView
+    var expanded = false
+        set(value) {
+            if (value != field) {
+                field = value
+                updateView()
+            }
+        }
     var builder = PrivacyDialogBuilder(context, emptyList<PrivacyItem>())
     var privacyList = emptyList<PrivacyItem>()
         set(value) {
@@ -48,15 +60,18 @@
     override fun onFinishInflate() {
         super.onFinishInflate()
 
+        inUseText = findViewById(R.id.in_use_text)
         text = findViewById(R.id.text_container)
         iconsContainer = findViewById(R.id.icons_container)
     }
 
     // Should only be called if the builder icons or app changed
     private fun updateView() {
+        inUseText.visibility = if (expanded) View.GONE else View.VISIBLE
+        background = if (expanded) backgroundDrawable else null
         fun setIcons(dialogBuilder: PrivacyDialogBuilder, iconsContainer: ViewGroup) {
             iconsContainer.removeAllViews()
-            dialogBuilder.generateIcons().forEach {
+            dialogBuilder.generateIcons().forEachIndexed { i, it ->
                 it.mutate()
                 it.setTint(iconColor)
                 val image = ImageView(context).apply {
@@ -64,17 +79,19 @@
                     scaleType = ImageView.ScaleType.CENTER_INSIDE
                 }
                 iconsContainer.addView(image, iconSize, iconSize)
-                val lp = image.layoutParams as MarginLayoutParams
-                lp.marginStart = iconMargin
-                image.layoutParams = lp
+                if (i != 0) {
+                    val lp = image.layoutParams as MarginLayoutParams
+                    lp.marginStart = if (expanded) iconMarginExpanded else iconMarginCollapsed
+                    image.layoutParams = lp
+                }
             }
         }
 
         if (!privacyList.isEmpty()) {
             generateContentDescription()
             setIcons(builder, iconsContainer)
-            text.visibility = if (builder.types.size == 1) VISIBLE else GONE
-            if (builder.types.size == 1) {
+            text.visibility = if (builder.types.size == 1 && expanded) VISIBLE else GONE
+            if (builder.types.size == 1 && expanded) {
                 if (builder.app != null) {
                     text.setText(builder.app?.applicationName)
                 } else {
diff --git a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt
index fa1426e..cff7fe4 100644
--- a/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/privacy/OngoingPrivacyDialog.kt
@@ -69,7 +69,7 @@
             setPositiveButton(R.string.ongoing_privacy_dialog_ok, null)
             setNeutralButton(R.string.ongoing_privacy_dialog_open_settings,
                     object : DialogInterface.OnClickListener {
-                        val intent = Intent(Settings.ACTION_ENTERPRISE_PRIVACY_SETTINGS).putExtra(
+                        val intent = Intent(Settings.ACTION_PRIVACY_SETTINGS).putExtra(
                                 Intent.EXTRA_DURATION_MILLIS, TimeUnit.MINUTES.toMillis(1))
 
                         @Suppress("DEPRECATION")
@@ -167,7 +167,7 @@
             // Check if package exists
             context.packageManager.getPackageInfo(app.packageName, 0)
             item.setOnClickListener(object : View.OnClickListener {
-                val intent = Intent(Intent.ACTION_REVIEW_APP_PERMISSION_USAGE)
+                val intent = Intent(Intent.ACTION_MANAGE_APP_PERMISSIONS)
                         .putExtra(Intent.EXTRA_PACKAGE_NAME, app.packageName)
                         .putExtra(Intent.EXTRA_USER, UserHandle.getUserHandleForUid(app.uid))
                 override fun onClick(v: View?) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
index b865ce8..f91c9d9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFooterImpl.java
@@ -189,6 +189,7 @@
         addOnLayoutChangeListener((v, left, top, right, bottom, oldLeft, oldTop, oldRight,
                 oldBottom) -> updateAnimator(right - left));
         setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
+        updateEverything();
     }
 
     private void updateAnimator(int width) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index 74e82b2..ee9255c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -124,6 +124,7 @@
     private TintedIconManager mIconManager;
     private TouchAnimator mStatusIconsAlphaAnimator;
     private TouchAnimator mHeaderTextContainerAlphaAnimator;
+    private TouchAnimator mPrivacyChipAlphaAnimator;
 
     private View mSystemIconsView;
     private View mQuickQsStatusIcons;
@@ -212,6 +213,8 @@
         mNextAlarmTextView = findViewById(R.id.next_alarm_text);
         mRingerModeIcon = findViewById(R.id.ringer_mode_icon);
         mRingerModeTextView = findViewById(R.id.ringer_mode_text);
+        mPrivacyChip = findViewById(R.id.privacy_chip);
+        mPrivacyChip.setOnClickListener(this);
 
         updateResources();
 
@@ -230,8 +233,6 @@
         mClockView = findViewById(R.id.clock);
         mClockView.setOnClickListener(this);
         mDateView = findViewById(R.id.date);
-        mPrivacyChip = findViewById(R.id.privacy_chip);
-        mPrivacyChip.setOnClickListener(this);
         mSpace = findViewById(R.id.space);
 
         // Tint for the battery icons are handled in setupHost()
@@ -383,6 +384,7 @@
 
         updateStatusIconAlphaAnimator();
         updateHeaderTextContainerAlphaAnimator();
+        updatePrivacyChipAlphaAnimator();
     }
 
     private void updateStatusIconAlphaAnimator() {
@@ -398,6 +400,12 @@
                 .build();
     }
 
+    private void updatePrivacyChipAlphaAnimator() {
+        mPrivacyChipAlphaAnimator = new TouchAnimator.Builder()
+                .addFloat(mPrivacyChip, "alpha", 1, 0, 1)
+                .build();
+    }
+
     public void setExpanded(boolean expanded) {
         if (mExpanded == expanded) return;
         mExpanded = expanded;
@@ -431,6 +439,10 @@
         if (mHeaderTextContainerAlphaAnimator != null) {
             mHeaderTextContainerAlphaAnimator.setPosition(keyguardExpansionFraction);
         }
+        if (mPrivacyChipAlphaAnimator != null) {
+            mPrivacyChip.setExpanded(expansionFraction > 0.5);
+            mPrivacyChipAlphaAnimator.setPosition(keyguardExpansionFraction);
+        }
 
         // Check the original expansion fraction - we don't want to show the tooltip until the
         // panel is pulled all the way out.
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
index e1a4378..e275690 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
@@ -58,10 +58,10 @@
 import com.android.systemui.plugins.qs.QSIconView;
 import com.android.systemui.plugins.qs.QSTile;
 import com.android.systemui.plugins.qs.QSTile.State;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.PagedTileLayout.TilePage;
 import com.android.systemui.qs.QSHost;
 import com.android.systemui.qs.QuickStatusBarHeader;
-import com.android.systemui.statusbar.StatusBarStateController;
 
 import java.util.ArrayList;
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
index de78d33..effa935 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/NightDisplayTile.java
@@ -22,6 +22,7 @@
 import android.app.ActivityManager;
 import android.content.Intent;
 import android.hardware.display.ColorDisplayManager;
+import android.hardware.display.NightDisplayListener;
 import android.metrics.LogMaker;
 import android.provider.Settings;
 import android.service.quicksettings.Tile;
@@ -31,7 +32,6 @@
 
 import androidx.annotation.StringRes;
 
-import com.android.internal.app.ColorDisplayController;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
 import com.android.systemui.plugins.qs.QSTile.BooleanState;
@@ -46,8 +46,9 @@
 
 import javax.inject.Inject;
 
-public class NightDisplayTile extends QSTileImpl<BooleanState>
-        implements ColorDisplayController.Callback {
+/** Quick settings tile: Night display **/
+public class NightDisplayTile extends QSTileImpl<BooleanState> implements
+        NightDisplayListener.Callback {
 
     /**
      * Pattern for {@link java.time.format.DateTimeFormatter} used to approximate the time to the
@@ -57,13 +58,15 @@
     private static final String PATTERN_HOUR_MINUTE = "h:mm a";
     private static final String PATTERN_HOUR_NINUTE_24 = "HH:mm";
 
-    private ColorDisplayController mController;
+    private final ColorDisplayManager mManager;
+    private NightDisplayListener mListener;
     private boolean mIsListening;
 
     @Inject
     public NightDisplayTile(QSHost host) {
         super(host);
-        mController = new ColorDisplayController(mContext, ActivityManager.getCurrentUser());
+        mManager = mContext.getSystemService(ColorDisplayManager.class);
+        mListener = new NightDisplayListener(mContext, ActivityManager.getCurrentUser());
     }
 
     @Override
@@ -81,27 +84,27 @@
         // Enroll in forced auto mode if eligible.
         if ("1".equals(Settings.Global.getString(mContext.getContentResolver(),
                 Settings.Global.NIGHT_DISPLAY_FORCED_AUTO_MODE_AVAILABLE))
-                && mController.getAutoModeRaw() == -1) {
-            mController.setAutoMode(ColorDisplayManager.AUTO_MODE_CUSTOM_TIME);
+                && mManager.getNightDisplayAutoModeRaw() == -1) {
+            mManager.setNightDisplayAutoMode(ColorDisplayManager.AUTO_MODE_CUSTOM_TIME);
             Log.i("NightDisplayTile", "Enrolled in forced night display auto mode");
         }
 
         // Change current activation state.
         final boolean activated = !mState.value;
-        mController.setActivated(activated);
+        mManager.setNightDisplayActivated(activated);
     }
 
     @Override
     protected void handleUserSwitch(int newUserId) {
         // Stop listening to the old controller.
         if (mIsListening) {
-            mController.setListener(null);
+            mListener.setCallback(null);
         }
 
         // Make a new controller for the new user.
-        mController = new ColorDisplayController(mContext, newUserId);
+        mListener = new NightDisplayListener(mContext, newUserId);
         if (mIsListening) {
-            mController.setListener(this);
+            mListener.setCallback(this);
         }
 
         super.handleUserSwitch(newUserId);
@@ -109,7 +112,7 @@
 
     @Override
     protected void handleUpdateState(BooleanState state, Object arg) {
-        state.value = mController.isActivated();
+        state.value = mManager.isNightDisplayActivated();
         state.label = mContext.getString(R.string.quick_settings_night_display_label);
         state.icon = ResourceIcon.get(com.android.internal.R.drawable.ic_qs_night_display_on);
         state.expandedAccessibilityClassName = Switch.class.getName();
@@ -121,12 +124,12 @@
     }
 
     /**
-     * Returns a {@link String} for the secondary label that reflects when the light will be turned
-     * on or off based on the current auto mode and night light activated status.
+     * Returns a String for the secondary label that reflects when the light will be turned on or
+     * off based on the current auto mode and night light activated status.
      */
     @Nullable
     private String getSecondaryLabel(boolean isNightLightActivated) {
-        switch(mController.getAutoMode()) {
+        switch (mManager.getNightDisplayAutoMode()) {
             case ColorDisplayManager.AUTO_MODE_TWILIGHT:
                 // Auto mode related to sunrise & sunset. If the light is on, it's guaranteed to be
                 // turned off at sunrise. If it's off, it's guaranteed to be turned on at sunset.
@@ -143,10 +146,10 @@
                 final DateTimeFormatter toggleTimeFormat;
 
                 if (isNightLightActivated) {
-                    toggleTime = mController.getCustomEndTime();
+                    toggleTime = mManager.getNightDisplayCustomEndTime();
                     toggleTimeStringRes = R.string.quick_settings_secondary_label_until;
                 } else {
-                    toggleTime = mController.getCustomStartTime();
+                    toggleTime = mManager.getNightDisplayCustomStartTime();
                     toggleTimeStringRes = R.string.quick_settings_night_secondary_label_on_at;
                 }
 
@@ -175,7 +178,8 @@
 
     @Override
     public LogMaker populate(LogMaker logMaker) {
-        return super.populate(logMaker).addTaggedData(FIELD_QS_MODE, mController.getAutoModeRaw());
+        return super.populate(logMaker)
+                .addTaggedData(FIELD_QS_MODE, mManager.getNightDisplayAutoModeRaw());
     }
 
     @Override
@@ -187,10 +191,10 @@
     protected void handleSetListening(boolean listening) {
         mIsListening = listening;
         if (listening) {
-            mController.setListener(this);
+            mListener.setCallback(this);
             refreshState();
         } else {
-            mController.setListener(null);
+            mListener.setCallback(null);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 2811505..be749ae 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -47,7 +47,8 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
-import com.android.systemui.statusbar.StatusBarStateController.StateListener;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
 import com.android.systemui.statusbar.phone.KeyguardIndicationTextView;
 import com.android.systemui.statusbar.phone.LockIcon;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index 4f9d428..6a49b80 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -44,8 +44,9 @@
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.Dependency;
 import com.android.systemui.Dumpable;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
 import com.android.systemui.recents.OverviewProxyService;
-import com.android.systemui.statusbar.StatusBarStateController.StateListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationUtils;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index 98a3a54..490317b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -47,6 +47,7 @@
 import com.android.systemui.Dumpable;
 import com.android.systemui.Interpolators;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
index 491f310..b820dc0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationRemoteInputManager.java
@@ -132,7 +132,8 @@
         @Override
         public boolean onClickHandler(
                 View view, PendingIntent pendingIntent, RemoteViews.RemoteResponse response) {
-            mShadeController.get().wakeUpIfDozing(SystemClock.uptimeMillis(), view);
+            mShadeController.get().wakeUpIfDozing(SystemClock.uptimeMillis(), view,
+                    "NOTIFICATION_CLICK");
 
             if (handleRemoteInput(view, pendingIntent)) {
                 return true;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index 546b2e9..01b0bb1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -26,7 +26,6 @@
 import android.os.SystemProperties;
 import android.util.AttributeSet;
 import android.util.Log;
-import android.util.MathUtils;
 import android.view.DisplayCutout;
 import android.view.View;
 import android.view.ViewGroup;
@@ -38,7 +37,8 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
-import com.android.systemui.statusbar.StatusBarStateController.StateListener;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
 import com.android.systemui.statusbar.notification.NotificationUtils;
 import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
@@ -118,8 +118,8 @@
     @Override
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
-        Dependency.get(StatusBarStateController.class)
-                .addCallback(this, StatusBarStateController.RANK_SHELF);
+        ((SysuiStatusBarStateController) Dependency.get(StatusBarStateController.class))
+                .addCallback(this, SysuiStatusBarStateController.RANK_SHELF);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
index f2ff85b..662cf51 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java
@@ -61,7 +61,7 @@
     protected final NotificationLockscreenUserManager mLockscreenUserManager;
     protected final NotificationGroupManager mGroupManager;
     protected final VisualStabilityManager mVisualStabilityManager;
-    private final StatusBarStateController mStatusBarStateController;
+    private final StatusBarStateControllerImpl mStatusBarStateController;
     private final NotificationEntryManager mEntryManager;
 
     // Lazy
@@ -82,7 +82,7 @@
             NotificationLockscreenUserManager notificationLockscreenUserManager,
             NotificationGroupManager groupManager,
             VisualStabilityManager visualStabilityManager,
-            StatusBarStateController statusBarStateController,
+            StatusBarStateControllerImpl statusBarStateController,
             NotificationEntryManager notificationEntryManager,
             Lazy<ShadeController> shadeController) {
         mLockscreenUserManager = notificationLockscreenUserManager;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateController.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
similarity index 60%
rename from packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateController.java
rename to packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
index 54bce1c..ad5aa57 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarStateControllerImpl.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2014 The Android Open Source Project
+ * 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.
@@ -11,27 +11,22 @@
  * 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
+ * limitations under the License.
  */
 
 package com.android.systemui.statusbar;
 
-import static java.lang.annotation.RetentionPolicy.SOURCE;
-
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
-import android.annotation.IntDef;
 import android.util.FloatProperty;
 import android.view.animation.Interpolator;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.systemui.Interpolators;
-import com.android.systemui.statusbar.StatusBarStateController.StateListener;
+import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
-import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.policy.CallbackController;
 
-import java.lang.annotation.Retention;
 import java.util.ArrayList;
 import java.util.Comparator;
 
@@ -42,24 +37,25 @@
  * Tracks and reports on {@link StatusBarState}.
  */
 @Singleton
-public class StatusBarStateController implements CallbackController<StateListener> {
+public class StatusBarStateControllerImpl implements SysuiStatusBarStateController,
+        CallbackController<StateListener> {
     private static final String TAG = "SbStateController";
 
     private static final int MAX_STATE = StatusBarState.FULLSCREEN_USER_SWITCHER;
     private static final int MIN_STATE = StatusBarState.SHADE;
 
-    private static final Comparator <RankedListener> mComparator
-            = (o1, o2) -> Integer.compare(o1.rank, o2.rank);
-    private static final FloatProperty<StatusBarStateController> SET_DARK_AMOUNT_PROPERTY =
-            new FloatProperty<StatusBarStateController>("mDozeAmount") {
+    private static final Comparator<RankedListener> sComparator =
+            Comparator.comparingInt(o -> o.mRank);
+    private static final FloatProperty<StatusBarStateControllerImpl> SET_DARK_AMOUNT_PROPERTY =
+            new FloatProperty<StatusBarStateControllerImpl>("mDozeAmount") {
 
                 @Override
-                public void setValue(StatusBarStateController object, float value) {
+                public void setValue(StatusBarStateControllerImpl object, float value) {
                     object.setDozeAmountInternal(value);
                 }
 
                 @Override
-                public Float get(StatusBarStateController object) {
+                public Float get(StatusBarStateControllerImpl object) {
                     return object.mDozeAmount;
                 }
             };
@@ -95,29 +91,16 @@
      */
     private Interpolator mDozeInterpolator = Interpolators.FAST_OUT_SLOW_IN;
 
-    // TODO: b/115739177 (remove this explicit ordering if we can)
-    @Retention(SOURCE)
-    @IntDef({RANK_STATUS_BAR, RANK_STATUS_BAR_WINDOW_CONTROLLER, RANK_STACK_SCROLLER, RANK_SHELF})
-    public @interface SbStateListenerRank {}
-    // This is the set of known dependencies when updating StatusBarState
-    public static final int RANK_STATUS_BAR = 0;
-    public static final int RANK_STATUS_BAR_WINDOW_CONTROLLER = 1;
-    public static final int RANK_STACK_SCROLLER = 2;
-    public static final int RANK_SHELF = 3;
-
     @Inject
-    public StatusBarStateController() {
+    public StatusBarStateControllerImpl() {
     }
 
+    @Override
     public int getState() {
         return mState;
     }
 
-    /**
-     * Update the status bar state
-     * @param state see {@link StatusBarState} for valid options
-     * @return {@code true} if the state changed, else {@code false}
-     */
+    @Override
     public boolean setState(int state) {
         if (state > MAX_STATE || state < MIN_STATE) {
             throw new IllegalArgumentException("Invalid state " + state);
@@ -127,40 +110,38 @@
         }
         synchronized (mListeners) {
             for (RankedListener rl : new ArrayList<>(mListeners)) {
-                rl.listener.onStatePreChange(mState, state);
+                rl.mListener.onStatePreChange(mState, state);
             }
             mLastState = mState;
             mState = state;
             for (RankedListener rl : new ArrayList<>(mListeners)) {
-                rl.listener.onStateChanged(mState);
+                rl.mListener.onStateChanged(mState);
             }
 
             for (RankedListener rl : new ArrayList<>(mListeners)) {
-                rl.listener.onStatePostChange();
+                rl.mListener.onStatePostChange();
             }
         }
 
         return true;
     }
 
+    @Override
     public boolean isDozing() {
         return mIsDozing;
     }
 
+    @Override
     public float getDozeAmount() {
         return mDozeAmount;
     }
 
+    @Override
     public float getInterpolatedDozeAmount() {
         return mDozeInterpolator.getInterpolation(mDozeAmount);
     }
 
-    /**
-     * Update the dozing state from {@link StatusBar}'s perspective
-     * @param isDozing well, are we dozing?
-     * @return {@code true} if the state changed, else {@code false}
-     */
-    @SuppressWarnings("UnusedReturnValue")
+    @Override
     public boolean setIsDozing(boolean isDozing) {
         if (mIsDozing == isDozing) {
             return false;
@@ -170,19 +151,14 @@
 
         synchronized (mListeners) {
             for (RankedListener rl : new ArrayList<>(mListeners)) {
-                rl.listener.onDozingChanged(isDozing);
+                rl.mListener.onDozingChanged(isDozing);
             }
         }
 
         return true;
     }
 
-    /**
-     * Changes the current doze amount.
-     *
-     * @param dozeAmount New doze/dark amount.
-     * @param animated If change should be animated or not. This will cancel current animations.
-     */
+    @Override
     public void setDozeAmount(float dozeAmount, boolean animated) {
         if (mDarkAnimator != null && mDarkAnimator.isRunning()) {
             if (animated && mDozeAmountTarget == dozeAmount) {
@@ -217,27 +193,32 @@
         float interpolatedAmount = mDozeInterpolator.getInterpolation(dozeAmount);
         synchronized (mListeners) {
             for (RankedListener rl : new ArrayList<>(mListeners)) {
-                rl.listener.onDozeAmountChanged(mDozeAmount, interpolatedAmount);
+                rl.mListener.onDozeAmountChanged(mDozeAmount, interpolatedAmount);
             }
         }
     }
 
+    @Override
     public boolean goingToFullShade() {
         return mState == StatusBarState.SHADE && mLeaveOpenOnKeyguardHide;
     }
 
+    @Override
     public void setLeaveOpenOnKeyguardHide(boolean leaveOpen) {
         mLeaveOpenOnKeyguardHide = leaveOpen;
     }
 
+    @Override
     public boolean leaveOpenOnKeyguardHide() {
         return mLeaveOpenOnKeyguardHide;
     }
 
+    @Override
     public boolean fromShadeLocked() {
         return mLastState == StatusBarState.SHADE_LOCKED;
     }
 
+    @Override
     public void addCallback(StateListener listener) {
         synchronized (mListeners) {
             addListenerInternalLocked(listener, Integer.MAX_VALUE);
@@ -254,6 +235,8 @@
      * StatusBarState out of StatusBar.java. Any new listeners should be built not to need ranking
      * (i.e., they are non-dependent on the order of operations of StatusBarState listeners).
      */
+    @Deprecated
+    @Override
     public void addCallback(StateListener listener, @SbStateListenerRank int rank) {
         synchronized (mListeners) {
             addListenerInternalLocked(listener, rank);
@@ -264,91 +247,38 @@
     private void addListenerInternalLocked(StateListener listener, int rank) {
         // Protect against double-subscribe
         for (RankedListener rl : mListeners) {
-            if (rl.listener.equals(listener)) {
+            if (rl.mListener.equals(listener)) {
                 return;
             }
         }
 
-        RankedListener rl = new RankedListener(listener, rank);
+        RankedListener rl = new SysuiStatusBarStateController.RankedListener(listener, rank);
         mListeners.add(rl);
-        mListeners.sort(mComparator);
+        mListeners.sort(sComparator);
     }
 
+
+    @Override
     public void removeCallback(StateListener listener) {
         synchronized (mListeners) {
-            mListeners.removeIf((it) -> it.listener.equals(listener));
+            mListeners.removeIf((it) -> it.mListener.equals(listener));
         }
     }
 
+    @Override
     public void setKeyguardRequested(boolean keyguardRequested) {
         mKeyguardRequested = keyguardRequested;
     }
 
+    @Override
     public boolean isKeyguardRequested() {
         return mKeyguardRequested;
     }
 
+    /**
+     * Returns String readable state of status bar from {@link StatusBarState}
+     */
     public static String describe(int state) {
         return StatusBarState.toShortString(state);
     }
-
-    private class RankedListener {
-        private final StateListener listener;
-        private final int rank;
-
-        private RankedListener(StateListener l, int r) {
-            listener = l;
-            rank = r;
-        }
-    }
-
-    /**
-     * Listener for StatusBarState updates
-     */
-    public interface StateListener {
-
-        /**
-         * Callback before the new state is applied, for those who need to preempt the change.
-         *
-         * @param oldState state before the change
-         * @param newState new state to be applied in {@link #onStateChanged}
-         */
-        public default void onStatePreChange(int oldState, int newState) {
-        }
-
-        /**
-         * Callback after all listeners have had a chance to update based on the state change
-         */
-        public default void onStatePostChange() {
-        }
-
-        /**
-         * Required callback. Get the new state and do what you will with it. Keep in mind that
-         * other listeners are typically unordered and don't rely on your work being done before
-         * other peers.
-         *
-         * Only called if the state is actually different.
-         *
-         * @param newState the new {@link StatusBarState}
-         */
-        default void onStateChanged(int newState) {
-        }
-
-        /**
-         * Callback to be notified when Dozing changes. Dozing is stored separately from state.
-         *
-         * @param isDozing {@code true} if dozing according to {@link StatusBar}
-         */
-        public default void onDozingChanged(boolean isDozing) {}
-
-        /**
-         * Callback to be notified when the doze amount changes. Useful for animations.
-         * Note: this will be called for each animation frame. Please be careful to avoid
-         * performance regressions.
-         *
-         * @param linear A number from 0 to 1, where 1 means that the device is dozing.
-         * @param eased Same as {@code linear} but transformed by an interpolator.
-         */
-        default void onDozeAmountChanged(float linear, float eased) {}
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java b/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java
new file mode 100644
index 0000000..dc5e1e9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SysuiStatusBarStateController.java
@@ -0,0 +1,126 @@
+/*
+ * 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.systemui.statusbar;
+
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.annotation.IntDef;
+
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.phone.StatusBar;
+
+import java.lang.annotation.Retention;
+
+/**
+ * Sends updates to {@link StateListener}s about changes to the status bar state and dozing state
+ */
+public interface SysuiStatusBarStateController extends StatusBarStateController {
+
+    // TODO: b/115739177 (remove this explicit ordering if we can)
+    @Retention(SOURCE)
+    @IntDef({RANK_STATUS_BAR, RANK_STATUS_BAR_WINDOW_CONTROLLER, RANK_STACK_SCROLLER, RANK_SHELF})
+    @interface SbStateListenerRank {}
+    // This is the set of known dependencies when updating StatusBarState
+    int RANK_STATUS_BAR = 0;
+    int RANK_STATUS_BAR_WINDOW_CONTROLLER = 1;
+    int RANK_STACK_SCROLLER = 2;
+    int RANK_SHELF = 3;
+
+    /**
+     * Add a listener and a rank based on the priority of this message
+     * @param listener the listener
+     * @param rank the order in which you'd like to be called. Ranked listeners will be
+     * notified before unranked, and we will sort ranked listeners from low to high
+     *
+     * @deprecated This method exists only to solve latent inter-dependencies from refactoring
+     * StatusBarState out of StatusBar.java. Any new listeners should be built not to need ranking
+     * (i.e., they are non-dependent on the order of operations of StatusBarState listeners).
+     */
+    @Deprecated
+    void addCallback(StateListener listener, int rank);
+
+    /**
+     * Update the status bar state
+     * @param state see {@link StatusBarState} for valid options
+     * @return {@code true} if the state changed, else {@code false}
+     */
+    boolean setState(int state);
+
+    /**
+     * Update the dozing state from {@link StatusBar}'s perspective
+     * @param isDozing well, are we dozing?
+     * @return {@code true} if the state changed, else {@code false}
+     */
+    boolean setIsDozing(boolean isDozing);
+
+    /**
+     * Changes the current doze amount.
+     *
+     * @param dozeAmount New doze/dark amount.
+     * @param animated If change should be animated or not. This will cancel current animations.
+     */
+    void setDozeAmount(float dozeAmount, boolean animated);
+
+    /**
+     * Sets whether to leave status bar open when hiding keyguard
+     */
+    void setLeaveOpenOnKeyguardHide(boolean leaveOpen);
+
+    /**
+     * Whether to leave status bar open when hiding keyguard
+     */
+    boolean leaveOpenOnKeyguardHide();
+
+    /**
+     * Interpolated doze amount
+     */
+    float getInterpolatedDozeAmount();
+
+    /**
+     * Whether status bar is going to full shade
+     */
+    boolean goingToFullShade();
+
+    /**
+     * Whether the previous state of the status bar was the shade locked
+     */
+    boolean fromShadeLocked();
+
+    /**
+     * Set keyguard requested
+     */
+    void setKeyguardRequested(boolean keyguardRequested);
+
+    /**
+     * Is keyguard requested
+     */
+    boolean isKeyguardRequested();
+
+    /**
+     * Listener with rankings SbStateListenerRank that have dependencies so must be updated
+     * in a certain order
+     */
+    class RankedListener {
+        final StateListener mListener;
+        final int mRank;
+
+        RankedListener(StateListener l, int r) {
+            mListener = l;
+            mRank = r;
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java
index 49f1a8d..b788f53 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java
@@ -52,7 +52,7 @@
             return;
         }
 
-        mShadeController.wakeUpIfDozing(SystemClock.uptimeMillis(), v);
+        mShadeController.wakeUpIfDozing(SystemClock.uptimeMillis(), v, "NOTIFICATION_CLICK");
 
         final ExpandableNotificationRow row = (ExpandableNotificationRow) v;
         final StatusBarNotification sbn = row.getStatusBarNotification();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java
index c50f10b..7cbe1a3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationInterruptionStateProvider.java
@@ -35,8 +35,8 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.Dependency;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.NotificationPresenter;
-import com.android.systemui.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.phone.ShadeController;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java
index 54ed0d9..8b522a2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationData.java
@@ -16,8 +16,10 @@
 
 package com.android.systemui.statusbar.notification.collection;
 
+import android.app.Notification;
 import android.app.NotificationChannel;
 import android.app.NotificationManager;
+import android.app.Person;
 import android.service.notification.NotificationListenerService.Ranking;
 import android.service.notification.NotificationListenerService.RankingMap;
 import android.service.notification.SnoozeCriterion;
@@ -235,8 +237,11 @@
         if (mRankingMap != null) {
             getRanking(statusBarNotification.getKey(), mTmpRanking);
             if (mTmpRanking.getImportance() >= NotificationManager.IMPORTANCE_DEFAULT
-                    || statusBarNotification.getNotification().isForegroundService()
-                    || statusBarNotification.getNotification().hasMediaSession()) {
+                    || isImportantOngoing(statusBarNotification.getNotification())
+                    || statusBarNotification.getNotification().hasMediaSession()
+                    || hasPerson(statusBarNotification.getNotification())
+                    || hasStyle(statusBarNotification.getNotification(),
+                    Notification.MessagingStyle.class)) {
                 return true;
             }
             if (mGroupManager.isSummaryOfGroup(statusBarNotification)) {
@@ -252,6 +257,24 @@
         return false;
     }
 
+    private boolean isImportantOngoing(Notification notification) {
+        return notification.isForegroundService()
+                && mTmpRanking.getImportance() >= NotificationManager.IMPORTANCE_LOW;
+    }
+
+    private boolean hasStyle(Notification notification, Class targetStyle) {
+        Class<? extends Notification.Style> style = notification.getNotificationStyle();
+        return targetStyle.equals(style);
+    }
+
+    private boolean hasPerson(Notification notification) {
+        // TODO: cache favorite and recent contacts to check contact affinity
+        ArrayList<Person> people = notification.extras != null
+                ? notification.extras.getParcelableArrayList(Notification.EXTRA_PEOPLE_LIST)
+                : new ArrayList<>();
+        return people != null && !people.isEmpty();
+    }
+
     public boolean isAmbient(String key) {
         if (mRankingMap != null) {
             getRanking(key, mTmpRanking);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
index 9f1693c..f74de5b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
@@ -151,6 +151,12 @@
     private boolean mIsBubble;
 
     /**
+     * Whether this notification has been approved globally, at the app level, and at the channel
+     * level for bubbling.
+     */
+    public boolean canBubble;
+
+    /**
      * Whether this notification should be shown in the shade when it is also displayed as a bubble.
      *
      * <p>When a notification is a bubble we don't show it in the shade once the bubble has been
@@ -197,6 +203,7 @@
                 : ranking.getSmartReplies().toArray(new CharSequence[0]);
         suppressedVisualEffects = ranking.getSuppressedVisualEffects();
         suspended = ranking.isSuspended();
+        canBubble = ranking.canBubble();
     }
 
     public void setInterruption() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
index 5e52419..c4ecb82 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/logging/NotificationLogger.java
@@ -33,9 +33,9 @@
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.statusbar.NotificationVisibility;
 import com.android.systemui.UiOffloadThread;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
 import com.android.systemui.statusbar.NotificationListener;
-import com.android.systemui.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.StatusBarStateController.StateListener;
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
index 8095615..1dc48d4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentView.java
@@ -68,6 +68,7 @@
 public class NotificationContentView extends FrameLayout {
 
     private static final String TAG = "NotificationContentView";
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
     public static final int VISIBLE_TYPE_CONTRACTED = 0;
     public static final int VISIBLE_TYPE_EXPANDED = 1;
     public static final int VISIBLE_TYPE_HEADSUP = 2;
@@ -1319,6 +1320,14 @@
 
         SmartRepliesAndActions smartRepliesAndActions =
                 chooseSmartRepliesAndActions(mSmartReplyConstants, entry);
+        if (DEBUG) {
+            Log.d(TAG, String.format("Adding suggestions for %s, %d actions, and %d replies.",
+                    entry.notification.getKey(),
+                    smartRepliesAndActions.smartActions == null ? 0 :
+                            smartRepliesAndActions.smartActions.actions.size(),
+                    smartRepliesAndActions.smartReplies == null ? 0 :
+                            smartRepliesAndActions.smartReplies.choices.length));
+        }
 
         applyRemoteInput(entry, smartRepliesAndActions.hasFreeformRemoteInput);
         applySmartReplyView(smartRepliesAndActions, entry);
@@ -1341,6 +1350,10 @@
                 notification.findRemoteInputActionPair(true /* freeform */);
 
         if (!smartReplyConstants.isEnabled()) {
+            if (DEBUG) {
+                Log.d(TAG, "Smart suggestions not enabled, not adding suggestions for "
+                        + entry.notification.getKey());
+            }
             return new SmartRepliesAndActions(null, null, freeformRemoteInputActionPair != null);
         }
         // Only use smart replies from the app if they target P or above. We have this check because
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
index aa221993..fea01ef 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java
@@ -42,11 +42,11 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.Dumpable;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.NotificationLifetimeExtender;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationPresenter;
 import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.notification.NotificationActivityStarter;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.NotificationInfo.CheckSaveListener;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
index b6948fc..c7b2fab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java
@@ -537,7 +537,7 @@
                     mChosenImportance = IMPORTANCE_LOW;
                     confirmationText.setText(R.string.notification_channel_silenced);
                 } else {
-                    mChosenImportance = IMPORTANCE_HIGH;
+                    mChosenImportance = IMPORTANCE_DEFAULT;
                     confirmationText.setText(R.string.notification_channel_unsilenced);
                 }
                 break;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapper.java
index 4bdc170..4c9c2f9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationCustomViewWrapper.java
@@ -17,12 +17,7 @@
 package com.android.systemui.statusbar.notification.row.wrapper;
 
 import android.content.Context;
-import android.content.res.Configuration;
 import android.graphics.Color;
-import android.graphics.ColorMatrix;
-import android.graphics.ColorMatrixColorFilter;
-import android.graphics.Paint;
-import android.os.Build;
 import android.view.View;
 
 import com.android.internal.graphics.ColorUtils;
@@ -49,43 +44,22 @@
     }
 
     @Override
-    public void onReinflated() {
-        super.onReinflated();
-
-        Configuration configuration = mView.getResources().getConfiguration();
-        boolean nightMode = (configuration.uiMode & Configuration.UI_MODE_NIGHT_MASK)
-                == Configuration.UI_MODE_NIGHT_YES;
-
-        float[] hsl = new float[] {0f, 0f, 0f};
-        ColorUtils.colorToHSL(mBackgroundColor, hsl);
-        boolean backgroundIsDark = Color.alpha(mBackgroundColor) == 0
-                || hsl[1] == 0 && hsl[2] < 0.5;
-        boolean backgroundHasColor = hsl[1] > 0;
+    public void onContentUpdated(ExpandableNotificationRow row) {
+        super.onContentUpdated(row);
 
         // Let's invert the notification colors when we're in night mode and
         // the notification background isn't colorized.
-        if (!backgroundIsDark && !backgroundHasColor && nightMode
-                && mRow.getEntry().targetSdk < Build.VERSION_CODES.Q) {
-            Paint paint = new Paint();
-            ColorMatrix matrix = new ColorMatrix();
-            ColorMatrix tmp = new ColorMatrix();
-            // Inversion should happen on Y'UV space to conseve the colors and
-            // only affect the luminosity.
-            matrix.setRGB2YUV();
-            tmp.set(new float[]{
-                    -1f, 0f, 0f, 0f, 255f,
-                    0f, 1f, 0f, 0f, 0f,
-                    0f, 0f, 1f, 0f, 0f,
-                    0f, 0f, 0f, 1f, 0f
-            });
-            matrix.postConcat(tmp);
-            tmp.setYUV2RGB();
-            matrix.postConcat(tmp);
-            paint.setColorFilter(new ColorMatrixColorFilter(matrix));
-            mView.setLayerType(View.LAYER_TYPE_HARDWARE, paint);
+        if (needsInversion(mBackgroundColor, mView)) {
+            invertViewLuminosity(mView);
 
-            hsl[2] = 1f - hsl[2];
-            mBackgroundColor = ColorUtils.HSLToColor(hsl);
+            // Also invert background color if necessary
+            // (Otherwise we'd end-up with white on white.)
+            float[] hsl = new float[] {0f, 0f, 0f};
+            ColorUtils.colorToHSL(mBackgroundColor, hsl);
+            if (mBackgroundColor != Color.TRANSPARENT && hsl[2] > 0.5) {
+                hsl[2] = 1f - hsl[2];
+                mBackgroundColor = ColorUtils.HSLToColor(hsl);
+            }
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationDecoratedCustomViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationDecoratedCustomViewWrapper.java
new file mode 100644
index 0000000..49a8d56
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationDecoratedCustomViewWrapper.java
@@ -0,0 +1,51 @@
+/*
+ * 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.systemui.statusbar.notification.row.wrapper;
+
+import android.content.Context;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
+
+/**
+ * Wraps a notification containing a decorated custom view.
+ */
+public class NotificationDecoratedCustomViewWrapper extends NotificationTemplateViewWrapper {
+
+    private View mWrappedView = null;
+
+    protected NotificationDecoratedCustomViewWrapper(Context ctx, View view,
+            ExpandableNotificationRow row) {
+        super(ctx, view, row);
+    }
+
+    @Override
+    public void onContentUpdated(ExpandableNotificationRow row) {
+        ViewGroup container = mView.findViewById(
+                com.android.internal.R.id.notification_main_column);
+        Integer childIndex = (Integer) container.getTag(
+                com.android.internal.R.id.notification_custom_view_index_tag);
+        if (childIndex != null && childIndex != -1) {
+            mWrappedView = container.getChildAt(childIndex);
+        }
+        if (needsInversion(resolveBackgroundColor(), mWrappedView)) {
+            invertViewLuminosity(mWrappedView);
+        }
+        super.onContentUpdated(row);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
index 9258c99..4c06ff6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationViewWrapper.java
@@ -16,13 +16,22 @@
 
 package com.android.systemui.statusbar.notification.row.wrapper;
 
+import android.annotation.ColorInt;
+import android.app.Notification;
 import android.content.Context;
+import android.content.res.Configuration;
 import android.graphics.Color;
+import android.graphics.ColorMatrix;
+import android.graphics.ColorMatrixColorFilter;
+import android.graphics.Paint;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.view.NotificationHeaderView;
 import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
 
+import com.android.internal.graphics.ColorUtils;
 import com.android.systemui.statusbar.CrossFadeHelper;
 import com.android.systemui.statusbar.TransformableView;
 import com.android.systemui.statusbar.notification.TransformState;
@@ -50,6 +59,11 @@
             } else if ("messaging".equals(v.getTag())) {
                 return new NotificationMessagingTemplateViewWrapper(ctx, v, row);
             }
+            Class<? extends Notification.Style> style =
+                    row.getEntry().notification.getNotification().getNotificationStyle();
+            if (Notification.DecoratedCustomViewStyle.class.equals(style)) {
+                return new NotificationDecoratedCustomViewWrapper(ctx, v, row);
+            }
             return new NotificationTemplateViewWrapper(ctx, v, row);
         } else if (v instanceof NotificationHeaderView) {
             return new NotificationHeaderViewWrapper(ctx, v, row);
@@ -75,14 +89,110 @@
         if (shouldClearBackgroundOnReapply()) {
             mBackgroundColor = 0;
         }
-        Drawable background = mView.getBackground();
-        if (background instanceof ColorDrawable) {
-            int backgroundColor = ((ColorDrawable) background).getColor();
-            if (backgroundColor != Color.TRANSPARENT) {
-                mBackgroundColor = backgroundColor;
-                mView.setBackground(new ColorDrawable(Color.TRANSPARENT));
+        int backgroundColor = getBackgroundColor(mView);
+        if (backgroundColor != Color.TRANSPARENT) {
+            mBackgroundColor = backgroundColor;
+            mView.setBackground(new ColorDrawable(Color.TRANSPARENT));
+        }
+    }
+
+    protected boolean needsInversion(int defaultBackgroundColor, View view) {
+        if (view == null) {
+            return false;
+        }
+
+        Configuration configuration = mView.getResources().getConfiguration();
+        boolean nightMode = (configuration.uiMode & Configuration.UI_MODE_NIGHT_MASK)
+                == Configuration.UI_MODE_NIGHT_YES;
+        if (!nightMode) {
+            return false;
+        }
+
+        int background = getBackgroundColor(view);
+        if (background == Color.TRANSPARENT) {
+            background = defaultBackgroundColor;
+        }
+        if (background == Color.TRANSPARENT) {
+            background = resolveBackgroundColor();
+        }
+
+        float[] hsl = new float[] {0f, 0f, 0f};
+        ColorUtils.colorToHSL(background, hsl);
+
+        // Notifications with colored backgrounds should not be inverted
+        if (hsl[1] != 0) {
+            return false;
+        }
+
+        // Invert white or light gray backgrounds.
+        boolean isLightGrayOrWhite = hsl[1] == 0 && hsl[2] > 0.5;
+        if (isLightGrayOrWhite) {
+            return true;
+        }
+
+        // Now let's check if there's unprotected text somewhere, and invert if we find it.
+        if (view instanceof ViewGroup) {
+            return childrenNeedInversion(background, (ViewGroup) view);
+        } else {
+            return false;
+        }
+    }
+
+    private boolean childrenNeedInversion(@ColorInt int parentBackground, ViewGroup viewGroup) {
+        if (viewGroup == null) {
+            return false;
+        }
+
+        for (int i = 0; i < viewGroup.getChildCount(); i++) {
+            View child = viewGroup.getChildAt(i);
+            int backgroundColor = getBackgroundColor(viewGroup);
+            if (backgroundColor == Color.TRANSPARENT) {
+                backgroundColor = parentBackground;
+            }
+            if (child instanceof TextView) {
+                int foreground = ((TextView) child).getCurrentTextColor();
+                if (ColorUtils.calculateContrast(foreground, backgroundColor) < 3) {
+                    return true;
+                }
+            } else if (child instanceof ViewGroup) {
+                if (childrenNeedInversion(backgroundColor, (ViewGroup) child)) {
+                    return true;
+                }
             }
         }
+
+        return false;
+    }
+
+    protected int getBackgroundColor(View view) {
+        if (view == null) {
+            return Color.TRANSPARENT;
+        }
+        Drawable background = view.getBackground();
+        if (background instanceof ColorDrawable) {
+            return ((ColorDrawable) background).getColor();
+        }
+        return Color.TRANSPARENT;
+    }
+
+    protected void invertViewLuminosity(View view) {
+        Paint paint = new Paint();
+        ColorMatrix matrix = new ColorMatrix();
+        ColorMatrix tmp = new ColorMatrix();
+        // Inversion should happen on Y'UV space to conserve the colors and
+        // only affect the luminosity.
+        matrix.setRGB2YUV();
+        tmp.set(new float[]{
+                -1f, 0f, 0f, 0f, 255f,
+                0f, 1f, 0f, 0f, 0f,
+                0f, 0f, 1f, 0f, 0f,
+                0f, 0f, 0f, 1f, 0f
+        });
+        matrix.postConcat(tmp);
+        tmp.setYUV2RGB();
+        matrix.postConcat(tmp);
+        paint.setColorFilter(new ColorMatrixColorFilter(matrix));
+        view.setLayerType(View.LAYER_TYPE_HARDWARE, paint);
     }
 
     protected boolean shouldClearBackgroundOnReapply() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 63b34d1..7105876 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -86,6 +86,8 @@
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.MenuItem;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin.OnMenuEventListener;
 import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.DragDownHelper.DragDownCallback;
 import com.android.systemui.statusbar.EmptyShadeView;
@@ -94,8 +96,7 @@
 import com.android.systemui.statusbar.NotificationShelf;
 import com.android.systemui.statusbar.RemoteInputController;
 import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.StatusBarStateController.StateListener;
+import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.notification.FakeShadowView;
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -599,6 +600,16 @@
         updateFooter();
     }
 
+    @Override
+    public void onOverlayChanged() {
+        int newRadius = mContext.getResources().getDimensionPixelSize(
+                Utils.getThemeAttr(mContext, android.R.attr.dialogCornerRadius));
+        if (mCornerRadius != newRadius) {
+            mCornerRadius = newRadius;
+            invalidate();
+        }
+    }
+
     @VisibleForTesting
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
     public void updateFooter() {
@@ -654,8 +665,8 @@
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
-        Dependency.get(StatusBarStateController.class)
-                .addCallback(mStateListener, StatusBarStateController.RANK_STACK_SCROLLER);
+        ((SysuiStatusBarStateController) Dependency.get(StatusBarStateController.class))
+                .addCallback(mStateListener, SysuiStatusBarStateController.RANK_STACK_SCROLLER);
         Dependency.get(ConfigurationController.class).addCallback(this);
     }
 
@@ -5420,7 +5431,8 @@
             mHeadsUpAppearanceController.setPublicMode(publicMode);
         }
 
-        StatusBarStateController state = Dependency.get(StatusBarStateController.class);
+        SysuiStatusBarStateController state = (SysuiStatusBarStateController)
+                Dependency.get(StatusBarStateController.class);
         setHideSensitive(publicMode, state.goingToFullShade() /* animate */);
         setDimmed(onKeyguard, state.fromShadeLocked() /* animate */);
         setExpandingEnabled(!onKeyguard);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
index b96c55b..c9be2c8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoTileManager.java
@@ -16,11 +16,11 @@
 
 import android.content.Context;
 import android.hardware.display.ColorDisplayManager;
+import android.hardware.display.NightDisplayListener;
 import android.os.Handler;
 import android.provider.Settings.Secure;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.app.ColorDisplayController;
 import com.android.systemui.Dependency;
 import com.android.systemui.qs.AutoAddTracker;
 import com.android.systemui.qs.QSTileHost;
@@ -50,7 +50,7 @@
     private final HotspotController mHotspotController;
     private final DataSaverController mDataSaverController;
     private final ManagedProfileController mManagedProfileController;
-    private final ColorDisplayController mColorDisplayController;
+    private final NightDisplayListener mNightDisplayListener;
 
     @Inject
     public AutoTileManager(Context context, AutoAddTracker autoAddTracker, QSTileHost host,
@@ -58,7 +58,7 @@
             HotspotController hotspotController,
             DataSaverController dataSaverController,
             ManagedProfileController managedProfileController,
-            ColorDisplayController colorDisplayController) {
+            NightDisplayListener nightDisplayListener) {
         mAutoTracker = autoAddTracker;
         mContext = context;
         mHost = host;
@@ -66,7 +66,7 @@
         mHotspotController = hotspotController;
         mDataSaverController = dataSaverController;
         mManagedProfileController = managedProfileController;
-        mColorDisplayController = colorDisplayController;
+        mNightDisplayListener = nightDisplayListener;
         if (!mAutoTracker.isAdded(HOTSPOT)) {
             hotspotController.addCallback(mHotspotCallback);
         }
@@ -93,7 +93,7 @@
         }
         if (!mAutoTracker.isAdded(NIGHT)
                 && ColorDisplayManager.isNightDisplayAvailable(mContext)) {
-            colorDisplayController.setListener(mColorDisplayCallback);
+            nightDisplayListener.setCallback(mNightDisplayCallback);
         }
     }
 
@@ -106,7 +106,7 @@
         mDataSaverController.removeCallback(mDataSaverListener);
         mManagedProfileController.removeCallback(mProfileCallback);
         if (ColorDisplayManager.isNightDisplayAvailable(mContext)) {
-            mColorDisplayController.setListener(null);
+            mNightDisplayListener.setCallback(null);
         }
     }
 
@@ -157,8 +157,8 @@
     };
 
     @VisibleForTesting
-    final ColorDisplayController.Callback mColorDisplayCallback =
-            new ColorDisplayController.Callback() {
+    final NightDisplayListener.Callback mNightDisplayCallback =
+            new NightDisplayListener.Callback() {
         @Override
         public void onActivated(boolean activated) {
             if (activated) {
@@ -178,7 +178,7 @@
             if (mAutoTracker.isAdded(NIGHT)) return;
             mHost.addTile(NIGHT);
             mAutoTracker.setTileAdded(NIGHT);
-            mHandler.post(() -> mColorDisplayController.setListener(null));
+            mHandler.post(() -> mNightDisplayListener.setCallback(null));
         }
     };
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
index 304d2ee..2162ea7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java
@@ -232,7 +232,8 @@
                 if (DEBUG_BIO_WAKELOCK) {
                     Log.i(TAG, "bio wakelock: Authenticated, waking up...");
                 }
-                mPowerManager.wakeUp(SystemClock.uptimeMillis(), "android.policy:BIOMETRIC");
+                mPowerManager.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_GESTURE,
+                        "android.policy:BIOMETRIC");
             }
             if (delayWakeUp) {
                 mKeyguardViewMediator.onWakeAndUnlocking();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
index 35763dc..6410860 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragment.java
@@ -33,8 +33,8 @@
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.SysUiServiceProvider;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.phone.StatusBarIconController.DarkIconManager;
 import com.android.systemui.statusbar.policy.EncryptionHelper;
 import com.android.systemui.statusbar.policy.KeyguardMonitor;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
index 280dda0..d9d74b9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeScrimController.java
@@ -24,8 +24,8 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.doze.DozeHost;
 import com.android.systemui.doze.DozeLog;
-import com.android.systemui.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.StatusBarStateController.StateListener;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
 
 /**
  * Controller which handles all the doze animations of the scrims.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
index 035ccf1..4c1c0a4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpManagerPhone.java
@@ -38,9 +38,9 @@
 import com.android.systemui.R;
 import com.android.systemui.ScreenDecorations;
 import com.android.systemui.bubbles.BubbleController;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
 import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.StatusBarStateController.StateListener;
 import com.android.systemui.statusbar.notification.VisualStabilityManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
index 1944c3f..5ccb9b2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LightBarTransitionsController.java
@@ -33,9 +33,9 @@
 import com.android.systemui.Dumpable;
 import com.android.systemui.Interpolators;
 import com.android.systemui.SysUiServiceProvider;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.CommandQueue.Callbacks;
-import com.android.systemui.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.policy.KeyguardMonitor;
 
 import java.io.FileDescriptor;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index ee047e4..538d797 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -85,6 +85,7 @@
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.fragments.FragmentHostManager;
 import com.android.systemui.fragments.FragmentHostManager.FragmentListener;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.recents.OverviewProxyService;
 import com.android.systemui.recents.Recents;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -92,7 +93,6 @@
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.CommandQueue.Callbacks;
 import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
 import com.android.systemui.statusbar.phone.ContextualButton.ContextButtonListener;
 import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java
index d364356..b613e8e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupAlertTransferHelper.java
@@ -25,12 +25,12 @@
 
 import com.android.internal.statusbar.NotificationVisibility;
 import com.android.systemui.Dependency;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
 import com.android.systemui.statusbar.AlertingNotificationManager;
 import com.android.systemui.statusbar.AmbientPulseManager;
 import com.android.systemui.statusbar.AmbientPulseManager.OnAmbientChangedListener;
 import com.android.systemui.statusbar.InflationTask;
-import com.android.systemui.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.StatusBarStateController.StateListener;
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
index bb9e418..cc8af3b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationGroupManager.java
@@ -22,11 +22,11 @@
 import android.util.Log;
 
 import com.android.systemui.Dependency;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
 import com.android.systemui.statusbar.AmbientPulseManager;
 import com.android.systemui.statusbar.AmbientPulseManager.OnAmbientChangedListener;
 import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.StatusBarStateController.StateListener;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.policy.HeadsUpManager;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index 9e99fe9..62f85fe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -11,6 +11,9 @@
 import android.view.ViewGroup;
 import android.widget.FrameLayout;
 
+import androidx.annotation.NonNull;
+import androidx.collection.ArrayMap;
+
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.statusbar.StatusBarIcon;
 import com.android.internal.util.ContrastColorUtil;
@@ -19,10 +22,10 @@
 import com.android.systemui.R;
 import com.android.systemui.plugins.DarkIconDispatcher;
 import com.android.systemui.plugins.DarkIconDispatcher.DarkReceiver;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.NotificationListener;
 import com.android.systemui.statusbar.NotificationShelf;
 import com.android.systemui.statusbar.StatusBarIconView;
-import com.android.systemui.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationUtils;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
@@ -31,9 +34,6 @@
 import java.util.ArrayList;
 import java.util.function.Function;
 
-import androidx.annotation.NonNull;
-import androidx.collection.ArrayMap;
-
 /**
  * A controller for the space in the status bar to the left of the system icons. This area is
  * normally reserved for notifications.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index a9727c9..069703e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -17,8 +17,7 @@
 package com.android.systemui.statusbar.phone;
 
 import static com.android.systemui.SysUiServiceProvider.getComponent;
-import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator
-        .ExpandAnimationParameters;
+import static com.android.systemui.statusbar.notification.ActivityLaunchAnimator.ExpandAnimationParameters;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -63,6 +62,8 @@
 import com.android.systemui.fragments.FragmentHostManager;
 import com.android.systemui.fragments.FragmentHostManager.FragmentListener;
 import com.android.systemui.plugins.qs.QS;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
 import com.android.systemui.qs.QSFragment;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.FlingAnimationUtils;
@@ -73,8 +74,6 @@
 import com.android.systemui.statusbar.NotificationShelf;
 import com.android.systemui.statusbar.RemoteInputController;
 import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.StatusBarStateController.StateListener;
 import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
 import com.android.systemui.statusbar.notification.AnimatableProperty;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
index f17145d..4d0c8c3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -44,9 +44,10 @@
 import com.android.systemui.R;
 import com.android.systemui.classifier.FalsingManager;
 import com.android.systemui.doze.DozeLog;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.FlingAnimationUtils;
 import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.VibratorHelper;
 import com.android.systemui.statusbar.policy.KeyguardMonitor;
 
@@ -142,8 +143,8 @@
     private boolean mIgnoreXTouchSlop;
     private boolean mExpandLatencyTracking;
     protected final KeyguardMonitor mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);
-    protected final StatusBarStateController mStatusBarStateController =
-            Dependency.get(StatusBarStateController.class);
+    protected final SysuiStatusBarStateController mStatusBarStateController =
+            (SysuiStatusBarStateController) Dependency.get(StatusBarStateController.class);
 
     protected void onExpandingFinished() {
         mBar.onExpandingFinished();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeController.java
index f926218..234a968 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadeController.java
@@ -14,6 +14,7 @@
 
 package com.android.systemui.statusbar.phone;
 
+import android.annotation.NonNull;
 import android.view.View;
 
 import com.android.systemui.statusbar.StatusBarState;
@@ -96,8 +97,9 @@
      *
      * @param time when to wake up
      * @param view the view requesting the wakeup
+     * @param why the reason for the wake up
      */
-    void wakeUpIfDozing(long time, View view);
+    void wakeUpIfDozing(long time, View view, @NonNull String why);
 
     /**
      * If secure with redaction: Show bouncer, go to unlocked shade.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 3532af5..9f3bec6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -163,6 +163,7 @@
 import com.android.systemui.plugins.PluginDependencyProvider;
 import com.android.systemui.plugins.qs.QS;
 import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSFragment;
 import com.android.systemui.qs.QSPanel;
 import com.android.systemui.recents.Recents;
@@ -188,7 +189,8 @@
 import com.android.systemui.statusbar.NotificationViewHierarchyManager;
 import com.android.systemui.statusbar.ScrimView;
 import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.StatusBarStateControllerImpl;
+import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.VibratorHelper;
 import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
 import com.android.systemui.statusbar.notification.NotificationActivityStarter;
@@ -482,7 +484,8 @@
             updateAodMaskVisibility(deviceSupportsAodWallpaper && aodImageWallpaperEnabled);
             // If WallpaperInfo is null, it must be ImageWallpaper.
             final boolean supportsAmbientMode = deviceSupportsAodWallpaper
-                    && (info == null || info.supportsAmbientMode());
+                    && (info == null && aodImageWallpaperEnabled
+                        || info != null && info.supportsAmbientMode());
 
             mStatusBarWindowController.setWallpaperSupportsAmbientMode(supportsAmbientMode);
             mScrimController.setWallpaperSupportsAmbientMode(supportsAmbientMode);
@@ -551,14 +554,14 @@
 
     private final View.OnClickListener mGoToLockedShadeListener = v -> {
         if (mState == StatusBarState.KEYGUARD) {
-            wakeUpIfDozing(SystemClock.uptimeMillis(), v);
+            wakeUpIfDozing(SystemClock.uptimeMillis(), v, "SHADE_CLICK");
             goToLockedShade(null);
         }
     };
     private boolean mNoAnimationOnNextBarModeChange;
     protected FalsingManager mFalsingManager;
-    private final StatusBarStateController
-            mStatusBarStateController = Dependency.get(StatusBarStateController.class);
+    private final SysuiStatusBarStateController mStatusBarStateController =
+            (SysuiStatusBarStateController) Dependency.get(StatusBarStateController.class);
 
     private final KeyguardUpdateMonitorCallback mUpdateCallback =
             new KeyguardUpdateMonitorCallback() {
@@ -649,7 +652,8 @@
         }
 
         mColorExtractor.addOnColorsChangedListener(this);
-        mStatusBarStateController.addCallback(this, StatusBarStateController.RANK_STATUS_BAR);
+        mStatusBarStateController.addCallback(this,
+                StatusBarStateControllerImpl.RANK_STATUS_BAR);
 
         mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
         mDreamManager = IDreamManager.Stub.asInterface(
@@ -803,15 +807,17 @@
         mNotificationLogger.setUpWithContainer(notifListContainer);
 
         mNotificationIconAreaController = SystemUIFactory.getInstance()
-                .createNotificationIconAreaController(
-                        context, this, mStatusBarStateController, mNotificationListener);
+                .createNotificationIconAreaController(context, this,
+                        mStatusBarStateController, mNotificationListener);
         inflateShelf();
         mNotificationIconAreaController.setupShelf(mNotificationShelf);
 
         Dependency.get(DarkIconDispatcher.class).addDarkReceiver(mNotificationIconAreaController);
-        // Allow plugins to reference DarkIconDispatcher
+        // Allow plugins to reference DarkIconDispatcher and StatusBarStateController
         Dependency.get(PluginDependencyProvider.class)
                 .allowPluginDependency(DarkIconDispatcher.class);
+        Dependency.get(PluginDependencyProvider.class)
+                .allowPluginDependency(StatusBarStateController.class);
         FragmentHostManager.get(mStatusBarWindow)
                 .addTagListener(CollapsedStatusBarFragment.TAG, (tag, fragment) -> {
                     CollapsedStatusBarFragment statusBarFragment =
@@ -1090,10 +1096,10 @@
     }
 
     @Override
-    public void wakeUpIfDozing(long time, View where) {
+    public void wakeUpIfDozing(long time, View where, String why) {
         if (mDozing) {
-            PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
-            pm.wakeUp(time, "com.android.systemui:NODOZE");
+            PowerManager pm = mContext.getSystemService(PowerManager.class);
+            pm.wakeUp(time, PowerManager.WAKE_REASON_GESTURE, "com.android.systemui:" + why);
             mWakeUpComingFromTouch = true;
             where.getLocationInWindow(mTmpInt2);
             mWakeUpTouchLocation = new PointF(mTmpInt2[0] + where.getWidth() / 2,
@@ -3369,7 +3375,8 @@
         // ringing.
         // Other transitions are covered in handleVisibleToUserChanged().
         if (mVisible && (newState == StatusBarState.SHADE_LOCKED
-                || (Dependency.get(StatusBarStateController.class).goingToFullShade()))) {
+                || (((SysuiStatusBarStateController) Dependency.get(StatusBarStateController.class))
+                .goingToFullShade()))) {
             clearNotificationEffects();
         }
         if (newState == StatusBarState.KEYGUARD) {
@@ -3729,7 +3736,8 @@
         }
         if (!mDeviceInteractive) {
             PowerManager pm = mContext.getSystemService(PowerManager.class);
-            pm.wakeUp(SystemClock.uptimeMillis(), "com.android.systemui:CAMERA_GESTURE");
+            pm.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_CAMERA_LAUNCH,
+                    "com.android.systemui:CAMERA_GESTURE");
             mStatusBarKeyguardViewManager.notifyDeviceWakeUpRequested();
         }
         vibrateForCameraGesture();
@@ -3890,7 +3898,8 @@
         public void pulseWhileDozing(@NonNull PulseCallback callback, int reason) {
             mScrimController.setPulseReason(reason);
             if (reason == DozeLog.PULSE_REASON_SENSOR_LONG_PRESS) {
-                mPowerManager.wakeUp(SystemClock.uptimeMillis(), "com.android.systemui:NODOZE");
+                mPowerManager.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_GESTURE,
+                        "com.android.systemui:LONG_PRESS");
                 startAssist(new Bundle());
                 return;
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index bb23608..5014783 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -42,10 +42,11 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.SystemUIFactory;
 import com.android.systemui.keyguard.DismissCallbackRegistry;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.NotificationMediaManager;
 import com.android.systemui.statusbar.RemoteInputController;
-import com.android.systemui.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.phone.KeyguardBouncer.BouncerExpansionCallback;
 import com.android.systemui.statusbar.policy.KeyguardMonitor;
 import com.android.systemui.statusbar.policy.KeyguardMonitorImpl;
@@ -701,7 +702,8 @@
     }
 
     public boolean isGoingToNotificationShade() {
-        return Dependency.get(StatusBarStateController.class).leaveOpenOnKeyguardHide();
+        return ((SysuiStatusBarStateController) Dependency.get(StatusBarStateController.class))
+                .leaveOpenOnKeyguardHide();
     }
 
     public boolean isSecure(int userId) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index 86326be..b0e006d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -51,13 +51,13 @@
 import com.android.systemui.UiOffloadThread;
 import com.android.systemui.assist.AssistManager;
 import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationPresenter;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.RemoteInputController;
 import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
 import com.android.systemui.statusbar.notification.NotificationActivityStarter;
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index df7f53b..e9705ff 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -48,6 +48,7 @@
 import com.android.systemui.R;
 import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.AmbientPulseManager;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
@@ -56,7 +57,7 @@
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.NotificationViewHierarchyManager;
 import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.notification.AboveShelfObserver;
 import com.android.systemui.statusbar.notification.ActivityLaunchAnimator;
 import com.android.systemui.statusbar.notification.NotificationAlertingManager;
@@ -92,8 +93,8 @@
             Dependency.get(NotificationViewHierarchyManager.class);
     private final NotificationLockscreenUserManager mLockscreenUserManager =
             Dependency.get(NotificationLockscreenUserManager.class);
-    private final StatusBarStateController mStatusBarStateController =
-            Dependency.get(StatusBarStateController.class);
+    private final SysuiStatusBarStateController mStatusBarStateController =
+            (SysuiStatusBarStateController) Dependency.get(StatusBarStateController.class);
     private final NotificationEntryManager mEntryManager =
             Dependency.get(NotificationEntryManager.class);
     private final NotificationRowBinder mNotificationRowBinder =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
index 8d58410..21d9dcc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java
@@ -35,13 +35,14 @@
 
 import com.android.systemui.Dependency;
 import com.android.systemui.plugins.ActivityStarter;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.CommandQueue.Callbacks;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.NotificationRemoteInputManager.Callback;
 import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.policy.KeyguardMonitor;
@@ -57,10 +58,10 @@
         StatusBarStateController.StateListener {
 
     private final KeyguardMonitor mKeyguardMonitor = Dependency.get(KeyguardMonitor.class);
-    private final StatusBarStateController mStatusBarStateController
-            = Dependency.get(StatusBarStateController.class);
-    private final NotificationLockscreenUserManager mLockscreenUserManager
-            = Dependency.get(NotificationLockscreenUserManager.class);
+    private final SysuiStatusBarStateController mStatusBarStateController =
+            (SysuiStatusBarStateController) Dependency.get(StatusBarStateController.class);
+    private final NotificationLockscreenUserManager mLockscreenUserManager =
+            Dependency.get(NotificationLockscreenUserManager.class);
     private final ActivityStarter mActivityStarter = Dependency.get(ActivityStarter.class);
     private final Context mContext;
     private View mPendingWorkRemoteInputView;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
index 86e17f3..e1a77b0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowController.java
@@ -43,10 +43,11 @@
 import com.android.systemui.Dumpable;
 import com.android.systemui.colorextraction.SysuiColorExtractor;
 import com.android.systemui.keyguard.KeyguardViewMediator;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
 import com.android.systemui.statusbar.RemoteInputController.Callback;
 import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.StatusBarStateController.StateListener;
+import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener;
 
@@ -98,8 +99,9 @@
         mDozeParameters = dozeParameters;
         mScreenBrightnessDoze = mDozeParameters.getScreenBrightnessDoze();
         mLpChanged = new WindowManager.LayoutParams();
-        Dependency.get(StatusBarStateController.class).addCallback(
-                mStateListener, StatusBarStateController.RANK_STATUS_BAR_WINDOW_CONTROLLER);
+        ((SysuiStatusBarStateController) Dependency.get(StatusBarStateController.class))
+                .addCallback(mStateListener,
+                        SysuiStatusBarStateController.RANK_STATUS_BAR_WINDOW_CONTROLLER);
         Dependency.get(ConfigurationController.class).addCallback(this);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index 8b25c34..ad4ba75 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -59,15 +59,14 @@
 import com.android.systemui.ExpandHelper;
 import com.android.systemui.R;
 import com.android.systemui.classifier.FalsingManager;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.DragDownHelper;
 import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 
-
 public class StatusBarWindowView extends FrameLayout {
     public static final String TAG = "StatusBarWindowView";
     public static final boolean DEBUG = StatusBar.DEBUG;
@@ -112,7 +111,7 @@
         mTransparentSrcPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
         mFalsingManager = FalsingManager.getInstance(context);
         mDoubleTapHelper = new DoubleTapHelper(this, active -> {}, () -> {
-            mService.wakeUpIfDozing(SystemClock.uptimeMillis(), this);
+            mService.wakeUpIfDozing(SystemClock.uptimeMillis(), this, "DOUBLE_TAP");
             return true;
         }, null, null);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/wallpaper/AodMaskView.java b/packages/SystemUI/src/com/android/systemui/wallpaper/AodMaskView.java
index dd1d0ca..6ee341d 100644
--- a/packages/SystemUI/src/com/android/systemui/wallpaper/AodMaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/wallpaper/AodMaskView.java
@@ -34,7 +34,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
-import com.android.systemui.statusbar.StatusBarStateController;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.notification.AnimatableProperty;
 import com.android.systemui.statusbar.notification.PropertyAnimator;
 import com.android.systemui.statusbar.notification.stack.AnimationProperties;
@@ -156,8 +156,6 @@
 
     private boolean checkIfNeedMask() {
         // We need mask for ImageWallpaper / LockScreen Wallpaper (Music album art).
-        // Because of conflicting with another wallpaper feature,
-        // we only support LockScreen wallpaper currently.
         return mWallpaperManager.getWallpaperInfo() == null || ScrimState.AOD.hasBackdrop();
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
index d80b444..5d03f19 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardClockSwitchTest.java
@@ -42,8 +42,8 @@
 import com.android.keyguard.clock.ClockManager;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.plugins.ClockPlugin;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.StatusBarStateController;
 
 import org.junit.Before;
 import org.junit.Test;
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 49b4641..2742577 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -294,11 +294,6 @@
         assertTrue(mRow.getEntry().showInShadeWhenBubble());
     }
 
-    @Test
-    public void testNotificationWithoutChannel() {
-        assertFalse(mBubbleController.shouldBubble(mNoChannelRow.getEntry()));
-    }
-
     static class TestableBubbleController extends BubbleController {
 
         TestableBubbleController(Context context,
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 cfc19ef..01d7b8b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/KeyguardSliceProviderTest.java
@@ -44,8 +44,8 @@
 
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.NotificationMediaManager;
-import com.android.systemui.statusbar.StatusBarStateController;
 
 import org.junit.Assert;
 import org.junit.Before;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
index e5464e0..86f6cd3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSTileImplTest.java
@@ -47,10 +47,10 @@
 import com.android.systemui.Dependency;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.plugins.qs.QSTile;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.qs.QSHost;
 import com.android.systemui.qs.QSTileHost;
 import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.StatusBarStateController;
 
 import org.junit.Before;
 import org.junit.Ignore;
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 56e1fc6..62700c0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationViewHierarchyManagerTest.java
@@ -95,7 +95,7 @@
 
         mViewHierarchyManager = new NotificationViewHierarchyManager(mContext,
                 mLockscreenUserManager, mGroupManager, mVisualStabilityManager,
-                mock(StatusBarStateController.class), mEntryManager,
+                mock(StatusBarStateControllerImpl.class), mEntryManager,
                 () -> mShadeController);
         Dependency.get(InitController.class).executePostInitTasks();
         mViewHierarchyManager.setUpWithPresenter(mPresenter, mListContainer);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
index a0b3420..cad1a96 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/NotificationEntryManagerTest.java
@@ -170,7 +170,7 @@
                     0,
                     NotificationManager.IMPORTANCE_DEFAULT,
                     null, null,
-                    null, null, null, true, sentiment, false, -1, false, null, null);
+                    null, null, null, true, sentiment, false, -1, false, null, null, false);
             return true;
         }).when(mRankingMap).getRanking(eq(key), any(NotificationListenerService.Ranking.class));
     }
@@ -189,7 +189,7 @@
                     null, null,
                     null, null, null, true,
                     NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL, false, -1,
-                    false, smartActions, null);
+                    false, smartActions, null, false);
             return true;
         }).when(mRankingMap).getRanking(eq(key), any(NotificationListenerService.Ranking.class));
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java
index b507692..9f36a1e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationDataTest.java
@@ -23,12 +23,19 @@
 import static android.app.Notification.CATEGORY_EVENT;
 import static android.app.Notification.CATEGORY_MESSAGE;
 import static android.app.Notification.CATEGORY_REMINDER;
+import static android.app.NotificationManager.IMPORTANCE_LOW;
+import static android.app.NotificationManager.IMPORTANCE_MIN;
+
+import static com.android.systemui.statusbar.notification.collection.NotificationDataTest.TestableNotificationData.OVERRIDE_CHANNEL;
+import static com.android.systemui.statusbar.notification.collection.NotificationDataTest.TestableNotificationData.OVERRIDE_IMPORTANCE;
+import static com.android.systemui.statusbar.notification.collection.NotificationDataTest.TestableNotificationData.OVERRIDE_VIS_EFFECTS;
 
 import static junit.framework.Assert.assertEquals;
 
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
@@ -36,6 +43,7 @@
 import android.Manifest;
 import android.app.Notification;
 import android.app.NotificationChannel;
+import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.app.Person;
 import android.content.Intent;
@@ -84,8 +92,6 @@
 
     private static final int UID_NORMAL = 123;
     private static final int UID_ALLOW_DURING_SETUP = 456;
-    private static final String TEST_HIDDEN_NOTIFICATION_KEY = "testHiddenNotificationKey";
-    private static final String TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY = "exempt";
     private static final NotificationChannel NOTIFICATION_CHANNEL =
             new NotificationChannel("id", "name", NotificationChannel.USER_LOCKED_IMPORTANCE);
 
@@ -97,7 +103,7 @@
     NotificationData.KeyguardEnvironment mEnvironment;
 
     private final IPackageManager mMockPackageManager = mock(IPackageManager.class);
-    private NotificationData mNotificationData;
+    private TestableNotificationData mNotificationData;
     private ExpandableNotificationRow mRow;
 
     @Before
@@ -131,6 +137,7 @@
 
     @Test
     public void testChannelSetWhenAdded() {
+        mNotificationData.rankingOverrides.putParcelable(OVERRIDE_CHANNEL, NOTIFICATION_CHANNEL);
         mNotificationData.add(mRow.getEntry());
         assertEquals(NOTIFICATION_CHANNEL, mRow.getEntry().channel);
     }
@@ -217,12 +224,12 @@
     @Test
     public void testIsExemptFromDndVisualSuppression_foreground() {
         initStatusBarNotification(false);
-        when(mMockStatusBarNotification.getKey()).thenReturn(
-                TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY);
+
         Notification n = mMockStatusBarNotification.getNotification();
         n.flags = Notification.FLAG_FOREGROUND_SERVICE;
         NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification);
         mNotificationData.add(entry);
+        mNotificationData.rankingOverrides.putInt(OVERRIDE_VIS_EFFECTS, 255);
 
         assertTrue(entry.isExemptFromDndVisualSuppression());
         assertFalse(entry.shouldSuppressAmbient());
@@ -231,8 +238,6 @@
     @Test
     public void testIsExemptFromDndVisualSuppression_media() {
         initStatusBarNotification(false);
-        when(mMockStatusBarNotification.getKey()).thenReturn(
-                TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY);
         Notification n = mMockStatusBarNotification.getNotification();
         Notification.Builder nb = Notification.Builder.recoverBuilder(mContext, n);
         nb.setStyle(new Notification.MediaStyle().setMediaSession(mock(MediaSession.Token.class)));
@@ -240,6 +245,7 @@
         when(mMockStatusBarNotification.getNotification()).thenReturn(n);
         NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification);
         mNotificationData.add(entry);
+        mNotificationData.rankingOverrides.putInt(OVERRIDE_VIS_EFFECTS, 255);
 
         assertTrue(entry.isExemptFromDndVisualSuppression());
         assertFalse(entry.shouldSuppressAmbient());
@@ -248,11 +254,10 @@
     @Test
     public void testIsExemptFromDndVisualSuppression_system() {
         initStatusBarNotification(false);
-        when(mMockStatusBarNotification.getKey()).thenReturn(
-                TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY);
         NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification);
         entry.mIsSystemNotification = true;
         mNotificationData.add(entry);
+        mNotificationData.rankingOverrides.putInt(OVERRIDE_VIS_EFFECTS, 255);
 
         assertTrue(entry.isExemptFromDndVisualSuppression());
         assertFalse(entry.shouldSuppressAmbient());
@@ -261,10 +266,10 @@
     @Test
     public void testIsNotExemptFromDndVisualSuppression_hiddenCategories() {
         initStatusBarNotification(false);
-        when(mMockStatusBarNotification.getKey()).thenReturn(
-                TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY);
         NotificationEntry entry = new NotificationEntry(mMockStatusBarNotification);
         entry.mIsSystemNotification = true;
+        mNotificationData.rankingOverrides.putInt(OVERRIDE_VIS_EFFECTS,
+                NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT);
         mNotificationData.add(entry);
 
         when(mMockStatusBarNotification.getNotification()).thenReturn(
@@ -353,6 +358,64 @@
         assertTrue(entry.isLastMessageFromReply());
     }
 
+    @Test
+    public void personHighPriority() {
+        Person person = new Person.Builder()
+                .setName("name")
+                .setKey("abc")
+                .setUri("uri")
+                .setBot(true)
+                .build();
+
+        Notification notification = new Notification.Builder(mContext, "test")
+                .addPerson(person)
+                .build();
+
+        StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
+                notification, mContext.getUser(), "", 0);
+
+        assertTrue(mNotificationData.isHighPriority(sbn));
+    }
+
+    @Test
+    public void messagingStyleHighPriority() {
+
+        Notification notification = new Notification.Builder(mContext, "test")
+                .setStyle(new Notification.MessagingStyle(""))
+                .build();
+
+        StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
+                notification, mContext.getUser(), "", 0);
+
+        assertTrue(mNotificationData.isHighPriority(sbn));
+    }
+
+    @Test
+    public void minForegroundNotHighPriority() {
+        Notification notification = mock(Notification.class);
+        when(notification.isForegroundService()).thenReturn(true);
+
+        mNotificationData.rankingOverrides.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_MIN);
+
+        StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
+                notification, mContext.getUser(), "", 0);
+
+        assertFalse(mNotificationData.isHighPriority(sbn));
+    }
+
+    @Test
+    public void lowForegroundHighPriority() {
+        Notification notification = mock(Notification.class);
+        when(notification.isForegroundService()).thenReturn(true);
+
+        mNotificationData.rankingOverrides.putInt(OVERRIDE_IMPORTANCE, IMPORTANCE_LOW);
+
+        StatusBarNotification sbn = new StatusBarNotification("pkg", "pkg", 0, "tag", 0, 0,
+                notification, mContext.getUser(), "", 0);
+
+        assertTrue(mNotificationData.isHighPriority(sbn));
+    }
+
     private void initStatusBarNotification(boolean allowDuringSetup) {
         Bundle bundle = new Bundle();
         bundle.putBoolean(Notification.EXTRA_ALLOW_DURING_SETUP, allowDuringSetup);
@@ -362,39 +425,90 @@
         when(mMockStatusBarNotification.getNotification()).thenReturn(notification);
     }
 
-    private class TestableNotificationData extends NotificationData {
+    public static class TestableNotificationData extends NotificationData {
         public TestableNotificationData() {
             super();
         }
 
+        public static final String OVERRIDE_RANK = "r";
+        public static final String OVERRIDE_DND = "dnd";
+        public static final String OVERRIDE_VIS_OVERRIDE = "vo";
+        public static final String OVERRIDE_VIS_EFFECTS = "ve";
+        public static final String OVERRIDE_IMPORTANCE = "i";
+        public static final String OVERRIDE_IMP_EXP = "ie";
+        public static final String OVERRIDE_GROUP = "g";
+        public static final String OVERRIDE_CHANNEL = "c";
+        public static final String OVERRIDE_PEOPLE = "p";
+        public static final String OVERRIDE_SNOOZE_CRITERIA = "sc";
+        public static final String OVERRIDE_BADGE = "b";
+        public static final String OVERRIDE_USER_SENTIMENT = "us";
+        public static final String OVERRIDE_HIDDEN = "h";
+        public static final String OVERRIDE_LAST_ALERTED = "la";
+        public static final String OVERRIDE_NOISY = "n";
+        public static final String OVERRIDE_SMART_ACTIONS = "sa";
+        public static final String OVERRIDE_SMART_REPLIES = "sr";
+        public static final String OVERRIDE_BUBBLE = "cb";
+
+        public Bundle rankingOverrides = new Bundle();
+
         @Override
         protected boolean getRanking(String key, Ranking outRanking) {
             super.getRanking(key, outRanking);
-            if (key.equals(TEST_HIDDEN_NOTIFICATION_KEY)) {
-                outRanking.populate(key, outRanking.getRank(),
-                        outRanking.matchesInterruptionFilter(),
-                        outRanking.getVisibilityOverride(), outRanking.getSuppressedVisualEffects(),
-                        outRanking.getImportance(), outRanking.getImportanceExplanation(),
-                        outRanking.getOverrideGroupKey(), outRanking.getChannel(), null, null,
-                        outRanking.canShowBadge(), outRanking.getUserSentiment(), true,
-                        -1, false, null, null);
-            } else if (key.equals(TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY)) {
-                outRanking.populate(key, outRanking.getRank(),
-                        outRanking.matchesInterruptionFilter(),
-                        outRanking.getVisibilityOverride(), 255,
-                        outRanking.getImportance(), outRanking.getImportanceExplanation(),
-                        outRanking.getOverrideGroupKey(), outRanking.getChannel(), null, null,
-                        outRanking.canShowBadge(), outRanking.getUserSentiment(), true, -1,
-                        false, null, null);
-            } else {
-                outRanking.populate(key, outRanking.getRank(),
-                        outRanking.matchesInterruptionFilter(),
-                        outRanking.getVisibilityOverride(), outRanking.getSuppressedVisualEffects(),
-                        outRanking.getImportance(), outRanking.getImportanceExplanation(),
-                        outRanking.getOverrideGroupKey(), NOTIFICATION_CHANNEL, null, null,
-                        outRanking.canShowBadge(), outRanking.getUserSentiment(), false, -1,
-                        false, null, null);
+
+            ArrayList<String> currentAdditionalPeople = new ArrayList<>();
+            if (outRanking.getAdditionalPeople() != null) {
+                currentAdditionalPeople.addAll(outRanking.getAdditionalPeople());
             }
+
+            ArrayList<SnoozeCriterion> currentSnooze = new ArrayList<>();
+            if (outRanking.getSnoozeCriteria() != null) {
+                currentSnooze.addAll(outRanking.getSnoozeCriteria());
+            }
+
+            ArrayList<Notification.Action> currentActions = new ArrayList<>();
+            if (outRanking.getSmartActions() != null) {
+                currentActions.addAll(outRanking.getSmartActions());
+            }
+
+            ArrayList<CharSequence> currentReplies = new ArrayList<>();
+            if (outRanking.getSmartReplies() != null) {
+                currentReplies.addAll(outRanking.getSmartReplies());
+            }
+
+            outRanking.populate(key,
+                    rankingOverrides.getInt(OVERRIDE_RANK, outRanking.getRank()),
+                    rankingOverrides.getBoolean(OVERRIDE_DND,
+                            outRanking.matchesInterruptionFilter()),
+                    rankingOverrides.getInt(OVERRIDE_VIS_OVERRIDE,
+                            outRanking.getVisibilityOverride()),
+                    rankingOverrides.getInt(OVERRIDE_VIS_EFFECTS,
+                            outRanking.getSuppressedVisualEffects()),
+                    rankingOverrides.getInt(OVERRIDE_IMPORTANCE, outRanking.getImportance()),
+                    rankingOverrides.getCharSequence(OVERRIDE_IMP_EXP,
+                            outRanking.getImportanceExplanation()),
+                    rankingOverrides.getString(OVERRIDE_GROUP, outRanking.getOverrideGroupKey()),
+                    rankingOverrides.containsKey(OVERRIDE_CHANNEL)
+                            ? (NotificationChannel) rankingOverrides.getParcelable(OVERRIDE_CHANNEL)
+                            : outRanking.getChannel(),
+                    rankingOverrides.containsKey(OVERRIDE_PEOPLE)
+                            ? rankingOverrides.getStringArrayList(OVERRIDE_PEOPLE)
+                            : currentAdditionalPeople,
+                    rankingOverrides.containsKey(OVERRIDE_SNOOZE_CRITERIA)
+                            ? rankingOverrides.getParcelableArrayList(OVERRIDE_SNOOZE_CRITERIA)
+                            : currentSnooze,
+                    rankingOverrides.getBoolean(OVERRIDE_BADGE, outRanking.canShowBadge()),
+                    rankingOverrides.getInt(OVERRIDE_USER_SENTIMENT, outRanking.getUserSentiment()),
+                    rankingOverrides.getBoolean(OVERRIDE_HIDDEN, outRanking.isSuspended()),
+                    rankingOverrides.getLong(OVERRIDE_LAST_ALERTED,
+                            outRanking.getLastAudiblyAlertedMillis()),
+                    rankingOverrides.getBoolean(OVERRIDE_NOISY, outRanking.isNoisy()),
+                    rankingOverrides.containsKey(OVERRIDE_SMART_ACTIONS)
+                            ? rankingOverrides.getParcelableArrayList(OVERRIDE_SMART_ACTIONS)
+                            : currentActions,
+                    rankingOverrides.containsKey(OVERRIDE_SMART_REPLIES)
+                            ? rankingOverrides.getCharSequenceArrayList(OVERRIDE_SMART_REPLIES)
+                            : currentReplies,
+                    rankingOverrides.getBoolean(OVERRIDE_BUBBLE, outRanking.canBubble()));
             return true;
         }
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
index db2706b..d47700b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/logging/NotificationLoggerTest.java
@@ -40,7 +40,7 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.UiOffloadThread;
 import com.android.systemui.statusbar.NotificationListener;
-import com.android.systemui.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.StatusBarStateControllerImpl;
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotificationData;
@@ -99,7 +99,7 @@
         mEntry.setRow(mRow);
 
         mLogger = new TestableNotificationLogger(mListener, Dependency.get(UiOffloadThread.class),
-                mEntryManager, mock(StatusBarStateController.class), mBarService,
+                mEntryManager, mock(StatusBarStateControllerImpl.class), mBarService,
                 mExpansionStateLogger);
         mLogger.setUpWithContainer(mListContainer);
         verify(mEntryManager).addNotificationEntryListener(mEntryListenerCaptor.capture());
@@ -167,7 +167,7 @@
         TestableNotificationLogger(NotificationListener notificationListener,
                 UiOffloadThread uiOffloadThread,
                 NotificationEntryManager entryManager,
-                StatusBarStateController statusBarStateController,
+                StatusBarStateControllerImpl statusBarStateController,
                 IStatusBarService barService,
                 ExpansionStateLogger expansionStateLogger) {
             super(notificationListener, uiOffloadThread, entryManager, statusBarStateController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
index 2a64445..105bd9d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationInfoTest.java
@@ -18,7 +18,6 @@
 
 import static android.app.NotificationChannel.USER_LOCKED_IMPORTANCE;
 import static android.app.NotificationManager.IMPORTANCE_DEFAULT;
-import static android.app.NotificationManager.IMPORTANCE_HIGH;
 import static android.app.NotificationManager.IMPORTANCE_LOW;
 import static android.app.NotificationManager.IMPORTANCE_MIN;
 import static android.app.NotificationManager.IMPORTANCE_NONE;
@@ -1067,7 +1066,7 @@
                 anyString(), eq(TEST_UID), updated.capture());
         assertTrue((updated.getValue().getUserLockedFields()
                 & USER_LOCKED_IMPORTANCE) != 0);
-        assertEquals(IMPORTANCE_HIGH, updated.getValue().getImportance());
+        assertEquals(IMPORTANCE_DEFAULT, updated.getValue().getImportance());
     }
 
     @Test
@@ -1111,7 +1110,7 @@
                 anyString(), eq(TEST_UID), updated.capture());
         assertTrue((updated.getValue().getUserLockedFields()
                 & USER_LOCKED_IMPORTANCE) != 0);
-        assertEquals(IMPORTANCE_HIGH, updated.getValue().getImportance());
+        assertEquals(IMPORTANCE_DEFAULT, updated.getValue().getImportance());
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index ae70b01..d835082 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -51,13 +51,13 @@
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.EmptyShadeView;
 import com.android.systemui.statusbar.NotificationPresenter;
 import com.android.systemui.statusbar.NotificationRemoteInputManager;
 import com.android.systemui.statusbar.NotificationShelf;
 import com.android.systemui.statusbar.RemoteInputController;
 import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.collection.NotificationData;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
index 1ded835..f3740c4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/AutoTileManagerTest.java
@@ -21,13 +21,13 @@
 import static org.mockito.Mockito.verify;
 
 import android.hardware.display.ColorDisplayManager;
+import android.hardware.display.NightDisplayListener;
 import android.os.Handler;
 import android.support.test.filters.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.testing.TestableLooper.RunWithLooper;
 
-import com.android.internal.app.ColorDisplayController;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.qs.AutoAddTracker;
 import com.android.systemui.qs.QSTileHost;
@@ -58,7 +58,7 @@
                 mock(HotspotController.class),
                 mock(DataSaverController.class),
                 mock(ManagedProfileController.class),
-                mock(ColorDisplayController.class));
+                mock(NightDisplayListener.class));
     }
 
     @Test
@@ -66,7 +66,7 @@
         if (!ColorDisplayManager.isNightDisplayAvailable(mContext)) {
             return;
         }
-        mAutoTileManager.mColorDisplayCallback.onActivated(true);
+        mAutoTileManager.mNightDisplayCallback.onActivated(true);
         verify(mQsTileHost).addTile("night");
     }
 
@@ -75,7 +75,7 @@
         if (!ColorDisplayManager.isNightDisplayAvailable(mContext)) {
             return;
         }
-        mAutoTileManager.mColorDisplayCallback.onActivated(false);
+        mAutoTileManager.mNightDisplayCallback.onActivated(false);
         verify(mQsTileHost, never()).addTile("night");
     }
 
@@ -84,7 +84,7 @@
         if (!ColorDisplayManager.isNightDisplayAvailable(mContext)) {
             return;
         }
-        mAutoTileManager.mColorDisplayCallback.onAutoModeChanged(
+        mAutoTileManager.mNightDisplayCallback.onAutoModeChanged(
                 ColorDisplayManager.AUTO_MODE_TWILIGHT);
         verify(mQsTileHost).addTile("night");
     }
@@ -94,7 +94,7 @@
         if (!ColorDisplayManager.isNightDisplayAvailable(mContext)) {
             return;
         }
-        mAutoTileManager.mColorDisplayCallback.onAutoModeChanged(
+        mAutoTileManager.mNightDisplayCallback.onAutoModeChanged(
                 ColorDisplayManager.AUTO_MODE_CUSTOM_TIME);
         verify(mQsTileHost).addTile("night");
     }
@@ -104,7 +104,7 @@
         if (!ColorDisplayManager.isNightDisplayAvailable(mContext)) {
             return;
         }
-        mAutoTileManager.mColorDisplayCallback.onAutoModeChanged(
+        mAutoTileManager.mNightDisplayCallback.onAutoModeChanged(
                 ColorDisplayManager.AUTO_MODE_DISABLED);
         verify(mQsTileHost, never()).addTile("night");
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java
index a72be7a..3c5425c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/CollapsedStatusBarFragmentTest.java
@@ -32,8 +32,8 @@
 
 import com.android.systemui.R;
 import com.android.systemui.SysuiBaseFragmentTest;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.StatusBarStateController;
 import com.android.systemui.tuner.TunerService;
 
 import org.junit.Before;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java
index 13145b8..608dd8b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationIconAreaControllerTest.java
@@ -20,23 +20,15 @@
 
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.reset;
-import static org.mockito.Mockito.times;
-import static org.mockito.Mockito.verify;
 
-import android.content.Context;
 import android.provider.Settings;
 import android.support.test.filters.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.NotificationListener;
-import com.android.systemui.statusbar.StatusBarStateController;
-import com.android.systemui.statusbar.phone.LightBarTransitionsController.DarkIntensityApplier;
 
 import org.junit.Before;
 import org.junit.Test;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
index 3b98f0c..a97fa1f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
@@ -27,8 +27,9 @@
 
 import com.android.keyguard.KeyguardStatusView;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
-import com.android.systemui.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 import com.android.systemui.statusbar.policy.ConfigurationController;
 import com.android.systemui.statusbar.policy.ZenModeController;
@@ -46,7 +47,7 @@
 public class NotificationPanelViewTest extends SysuiTestCase {
 
     @Mock
-    private StatusBarStateController mStatusBarStateController;
+    private SysuiStatusBarStateController mStatusBarStateController;
     @Mock
     private NotificationStackScrollLayout mNotificationStackScrollLayout;
     @Mock
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index 036e57acb..a95361f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -82,6 +82,7 @@
 import com.android.systemui.keyguard.KeyguardViewMediator;
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.plugins.ActivityStarter.OnDismissAction;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.KeyguardIndicationController;
 import com.android.systemui.statusbar.NavigationBarController;
@@ -94,7 +95,7 @@
 import com.android.systemui.statusbar.NotificationViewHierarchyManager;
 import com.android.systemui.statusbar.RemoteInputController;
 import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.StatusBarStateControllerImpl;
 import com.android.systemui.statusbar.notification.NotificationAlertingManager;
 import com.android.systemui.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
@@ -153,7 +154,7 @@
     @Mock private NotificationLockscreenUserManager mLockscreenUserManager;
     @Mock private NotificationRemoteInputManager mRemoteInputManager;
     @Mock private RemoteInputController mRemoteInputController;
-    @Mock private StatusBarStateController mStatusBarStateController;
+    @Mock private StatusBarStateControllerImpl mStatusBarStateController;
     @Mock private DeviceProvisionedController mDeviceProvisionedController;
     @Mock private NotificationPresenter mNotificationPresenter;
     @Mock
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java
index 46335dc..11284d6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarWindowViewTest.java
@@ -28,9 +28,9 @@
 
 import com.android.systemui.Dependency;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.DragDownHelper;
 import com.android.systemui.statusbar.StatusBarState;
-import com.android.systemui.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
 
 import org.junit.Before;
diff --git a/packages/overlays/Android.mk b/packages/overlays/Android.mk
index b8a57ae..1294dbb 100644
--- a/packages/overlays/Android.mk
+++ b/packages/overlays/Android.mk
@@ -16,17 +16,13 @@
 include $(CLEAR_VARS)
 
 LOCAL_MODULE := frameworks-base-overlays
-
 LOCAL_REQUIRED_MODULES := \
-	ExperimentNavigationBarFloatingOverlay \
-	ExperimentNavigationBarDefaultOverlay \
-	ExperimentNavigationBarSlimOverlay32 \
-	ExperimentNavigationBarSlimOverlay40 \
-	ExperimentNavigationBarLargeOverlay56 \
-	ExperimentNavigationBarLargeOverlay64 \
 	AccentColorBlackOverlay \
 	AccentColorGreenOverlay \
 	AccentColorPurpleOverlay \
+	DisplayCutoutEmulationCornerOverlay \
+	DisplayCutoutEmulationDoubleOverlay \
+	DisplayCutoutEmulationTallOverlay \
 	FontNotoSerifSourceOverlay \
 	IconPackCircularAndroidOverlay \
 	IconPackCircularSettingsOverlay \
@@ -42,7 +38,17 @@
 	IconShapeSquircleOverlay \
 	IconShapeTeardropOverlay
 
+include $(BUILD_PHONY_PACKAGE)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := frameworks-base-overlays-debug
+LOCAL_REQUIRED_MODULES := \
+	ExperimentNavigationBarFloatingOverlay \
+	ExperimentNavigationBarDefaultOverlay \
+	ExperimentNavigationBarSlimOverlay32 \
+	ExperimentNavigationBarSlimOverlay40 \
+	ExperimentNavigationBarLargeOverlay56 \
+	ExperimentNavigationBarLargeOverlay64
 
 include $(BUILD_PHONY_PACKAGE)
-
 include $(call first-makefiles-under,$(LOCAL_PATH))
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index eb8710d..3c91069 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -6949,6 +6949,32 @@
     // OS: Q
     NOTIFICATION_SMART_REPLY_MODIFIED_BEFORE_SENDING = 1648;
 
+    // CATEGORY: ACTION_ACTIVITY_CHOOSER_SHOWN
+    // Field to add the mimetype for a ChooserActivity
+    // OS:Q
+    FIELD_SHARESHEET_MIMETYPE = 1649;
+
+    // CATEGORY: ACTION_ACTIVITY_CHOOSER_SHOWN
+    // Sharesheet direct targets are ready to show.
+    // OS:Q
+    ACTION_ACTIVITY_CHOOSER_SHOWN_DIRECT_TARGET = 1650;
+
+    // CATEGORY: ACTION_SHARESHEET_SCROLL
+    // Sharesheet are either expanded, scrolling through them or compacted again.
+    // OS:Q
+    // Subtype 1 means collapsed, 0 expanded
+    ACTION_SHARESHEET_COLLAPSED_CHANGED = 1651;
+
+    // ACTION: Share with screenshot extra
+    // OS: Q
+    ACTION_SHARE_WITH_PREVIEW = 1652;
+
+    // CATEGORY: ACTION_ACTIVITY_CHOOSER_SHOWN
+    // OS:Q
+    // The time elapsed from triggering the share to displaying the app targets
+    // formerly: histogram system_cost_for_smart_sharing
+    FIELD_TIME_TO_APP_TARGETS = 1653;
+
     // ---- End Q Constants, all Q constants go above this line ----
     // Add new aosp constants above this line.
     // END OF AOSP CONSTANTS
diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto
index 2b45b49..82359c5 100644
--- a/proto/src/wifi.proto
+++ b/proto/src/wifi.proto
@@ -515,6 +515,9 @@
 
   // Total number of scan results for WPA3-Enterprise networks
   optional int32 num_wpa3_enterprise_network_scan_results = 136;
+
+  // WifiConfigStore read/write metrics.
+  optional WifiConfigStoreIO wifi_config_store_io = 137;
 }
 
 // Information that gets logged for every WiFi connection.
@@ -668,6 +671,9 @@
 
   // Has bug report been taken.
   optional bool automatic_bug_report_taken = 9;
+
+  // Connection is using locally generated random MAC address.
+  optional bool use_randomized_mac = 10 [default = false];
 }
 
 // Number of occurrences of a specific RSSI poll rssi value
@@ -1874,6 +1880,13 @@
 
   // Rx link speed at the sample time in Mbps
   optional int32 rx_link_speed_mbps = 27;
+
+  // Sequence number generated by framework
+  optional int32 seq_num_inside_framework = 28;
+
+  // Whether current entry is for the same BSSID on the same frequency compared
+  // to last entry
+  optional bool is_same_bssid_and_freq = 29;
 }
 
 message WifiUsabilityStats {
@@ -2170,3 +2183,25 @@
     EASY_CONNECT_EVENT_FAILURE_INVALID_NETWORK = 9;
   }
 }
+
+// WifiConfigStore read/write metrics.
+message WifiConfigStoreIO {
+  // Histogram of config store read durations.
+  repeated DurationBucket read_durations = 1;
+
+  // Histogram of config store write durations.
+  repeated DurationBucket write_durations = 2;
+
+  // Total Number of instances of write/read duration in this duration bucket.
+  message DurationBucket {
+    // Bucket covers duration : [range_start_ms, range_end_ms)
+    // The (inclusive) lower bound of read/write duration represented by this bucket
+    optional int32 range_start_ms = 1;
+
+    // The (exclusive) upper bound of read/write duration represented by this bucket
+    optional int32 range_end_ms = 2;
+
+    // Number of read/write durations that fit into this bucket
+    optional int32 count = 3;
+  }
+}
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 8886ee2..1bce11ee 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -180,7 +180,7 @@
         mAugmentedAutofillResolver = new FrameworkResourcesServiceNameResolver(master.getContext(),
                 com.android.internal.R.string.config_defaultAugmentedAutofillService);
         mAugmentedAutofillResolver.setOnTemporaryServiceNameChangedCallback(
-                (u, s) -> updateRemoteAugmentedAutofillService());
+                (u, s) -> updateRemoteAugmentedAutofillService(s));
 
         updateLocked(disabled);
     }
@@ -1048,8 +1048,12 @@
                     componentName, mUserId, new RemoteAugmentedAutofillServiceCallbacks() {
                         @Override
                         public void onServiceDied(@NonNull RemoteAugmentedAutofillService service) {
-                            // TODO(b/123100811): properly implement
                             Slog.w(TAG, "remote augmented autofill service died");
+                            final RemoteAugmentedAutofillService remoteService =
+                                    mRemoteAugmentedAutofillService;
+                            if (remoteService != null) {
+                                remoteService.destroy();
+                            }
                         }
                     }, mMaster.isInstantServiceAllowed(), mMaster.verbose);
         }
@@ -1060,8 +1064,7 @@
     /**
      * Called when the {@link #mAugmentedAutofillResolver} changed (among other places).
      */
-    private void updateRemoteAugmentedAutofillService() {
-        final String serviceName = mAugmentedAutofillResolver.getServiceName(mUserId);
+    private void updateRemoteAugmentedAutofillService(@Nullable String serviceName) {
         if (serviceName == null) {
             if (sVerbose) Slog.v(TAG, "updateRemoteAugmentedAutofillService(): time's up!");
             if (mRemoteAugmentedAutofillService != null) {
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 194332a..04fc258 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -2595,8 +2595,6 @@
         final int mode;
         if ((supportedModes & FLAG_SMART_SUGGESTION_SYSTEM) != 0) {
             mode = FLAG_SMART_SUGGESTION_SYSTEM;
-        } else if ((supportedModes & AutofillManager.FLAG_SMART_SUGGESTION_LEGACY) != 0) {
-            mode = AutofillManager.FLAG_SMART_SUGGESTION_LEGACY;
         } else {
             Slog.w(TAG, "Unsupported Smart Suggestion mode: " + supportedModes);
             return null;
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 14322ec..0dd1ded 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -41,6 +41,7 @@
 import android.os.ParcelFileDescriptor;
 import android.os.Trace;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.util.Slog;
 import android.util.SparseArray;
 
@@ -433,8 +434,46 @@
                 getServiceForUserIfCallerHasPermission(userId, "getConfigurationIntent()");
 
         return userBackupManagerService == null
-                ? null
-                : userBackupManagerService.getConfigurationIntent(transportName);
+            ? null
+            : userBackupManagerService.getConfigurationIntent(transportName);
+    }
+
+    /**
+     * Sets the ancestral work profile for the calling user.
+     *
+     * <p> The ancestral work profile corresponds to the profile that was used to restore to the
+     * callers profile.
+     */
+    public void setAncestralSerialNumber(long ancestralSerialNumber) {
+        UserBackupManagerService userBackupManagerService =
+                getServiceForUserIfCallerHasPermission(
+                        Binder.getCallingUserHandle().getIdentifier(),
+                        "setAncestralSerialNumber()");
+
+        if (userBackupManagerService != null) {
+            userBackupManagerService.setAncestralSerialNumber(ancestralSerialNumber);
+        }
+    }
+
+    /**
+     * Returns a {@link UserHandle} for the user that has {@code ancestralSerialNumber} as the
+     * serial number of the its ancestral work profile.
+     *
+     * <p> The ancestral work profile is set by {@link #setAncestralSerialNumber(long)}
+     * and it corresponds to the profile that was used to restore to the callers profile.
+     */
+    @Nullable
+    public UserHandle getUserForAncestralSerialNumber(long ancestralSerialNumber) {
+        for (UserHandle handle : mContext.getSystemService(UserManager.class).getUserProfiles()) {
+            UserBackupManagerService userBackupManagerService = getServiceUsers().get(
+                    handle.getIdentifier());
+            if (userBackupManagerService != null) {
+                if (userBackupManagerService.getAncestralSerialNumber() == ancestralSerialNumber) {
+                    return handle;
+                }
+            }
+        }
+        return null;
     }
 
     /**
diff --git a/services/backup/java/com/android/server/backup/Trampoline.java b/services/backup/java/com/android/server/backup/Trampoline.java
index 87872e8..17e9b35 100644
--- a/services/backup/java/com/android/server/backup/Trampoline.java
+++ b/services/backup/java/com/android/server/backup/Trampoline.java
@@ -760,6 +760,21 @@
     }
 
     @Override
+    @Nullable public UserHandle getUserForAncestralSerialNumber(long ancestralSerialNumber) {
+        if (mService != null) {
+            return mService.getUserForAncestralSerialNumber(ancestralSerialNumber);
+        }
+        return null;
+    }
+
+    @Override
+    public void setAncestralSerialNumber(long ancestralSerialNumber) {
+        if (mService != null) {
+            mService.setAncestralSerialNumber(ancestralSerialNumber);
+        }
+    }
+
+    @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
         int userId = binderGetCallingUserId();
diff --git a/services/backup/java/com/android/server/backup/UserBackupManagerService.java b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
index 8b2c1b9..b2afbc3 100644
--- a/services/backup/java/com/android/server/backup/UserBackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/UserBackupManagerService.java
@@ -244,6 +244,8 @@
     private static final long BUSY_BACKOFF_MIN_MILLIS = 1000 * 60 * 60;  // one hour
     private static final int BUSY_BACKOFF_FUZZ = 1000 * 60 * 60 * 2;  // two hours
 
+    private static final String SERIAL_ID_FILE = "serial_id";
+
     private final @UserIdInt int mUserId;
     private final BackupAgentTimeoutParameters mAgentTimeoutParameters;
     private final TransportManager mTransportManager;
@@ -360,6 +362,8 @@
     private Set<String> mAncestralPackages = null;
     private long mAncestralToken = 0;
     private long mCurrentToken = 0;
+    @Nullable private File mAncestralSerialNumberFile;
+
 
     /**
      * Creates an instance of {@link UserBackupManagerService} and initializes state for it. This
@@ -2308,6 +2312,55 @@
         }
     }
 
+    /**
+     * Sets the work profile serial number of the ancestral work profile.
+     */
+    public void setAncestralSerialNumber(long ancestralSerialNumber) {
+        mContext.enforceCallingPermission(android.Manifest.permission.BACKUP,
+                "setAncestralSerialNumber");
+        Slog.v(TAG, "Setting ancestral work profile id to " + ancestralSerialNumber);
+        try (RandomAccessFile af = getAncestralSerialNumberFile()) {
+            af.writeLong(ancestralSerialNumber);
+        } catch (IOException e) {
+            Slog.w(TAG, "Unable to write to work profile serial mapping file:", e);
+        }
+    }
+
+    /**
+     * Returns the work profile serial number of the ancestral device. This will be set by
+     * {@link #setAncestralSerialNumber(long)}. Will return {@code -1} if not set.
+     */
+    public long getAncestralSerialNumber() {
+        try (RandomAccessFile af = getAncestralSerialNumberFile()) {
+            return af.readLong();
+        } catch (IOException e) {
+            Slog.w(TAG, "Unable to write to work profile serial number file:", e);
+            return -1;
+        }
+    }
+
+    private RandomAccessFile getAncestralSerialNumberFile() throws FileNotFoundException {
+        if (mAncestralSerialNumberFile == null) {
+            mAncestralSerialNumberFile = new File(
+                UserBackupManagerFiles.getBaseStateDir(getUserId()),
+                SERIAL_ID_FILE);
+            if (!mAncestralSerialNumberFile.exists()) {
+                try {
+                    mAncestralSerialNumberFile.createNewFile();
+                } catch (IOException e) {
+                    Slog.w(TAG, "serial number mapping file creation failed", e);
+                }
+            }
+        }
+        return new RandomAccessFile(mAncestralSerialNumberFile, "rwd");
+    }
+
+    @VisibleForTesting
+    void setAncestralSerialNumberFile(File ancestralSerialNumberFile) {
+        mAncestralSerialNumberFile = ancestralSerialNumberFile;
+    }
+
+
     /** Clear the given package's backup data from the current transport. */
     public void clearBackupData(String transportName, String packageName) {
         if (DEBUG) Slog.v(TAG, "clearBackupData() of " + packageName + " on " + transportName);
diff --git a/services/backup/java/com/android/server/backup/encryption/chunking/ByteRange.java b/services/backup/java/com/android/server/backup/encryption/chunking/ByteRange.java
new file mode 100644
index 0000000..004d9e3
--- /dev/null
+++ b/services/backup/java/com/android/server/backup/encryption/chunking/ByteRange.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2018 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.encryption.chunking;
+
+import com.android.internal.util.Preconditions;
+
+/** Representation of a range of bytes to be downloaded. */
+final class ByteRange {
+    private final long mStart;
+    private final long mEnd;
+
+    /** Creates a range of bytes which includes {@code mStart} and {@code mEnd}. */
+    ByteRange(long start, long end) {
+        Preconditions.checkArgument(start >= 0);
+        Preconditions.checkArgument(end >= start);
+        mStart = start;
+        mEnd = end;
+    }
+
+    /** Returns the start of the {@code ByteRange}. The start is included in the range. */
+    long getStart() {
+        return mStart;
+    }
+
+    /** Returns the end of the {@code ByteRange}. The end is included in the range. */
+    long getEnd() {
+        return mEnd;
+    }
+
+    /** Returns the number of bytes included in the {@code ByteRange}. */
+    int getLength() {
+        return (int) (mEnd - mStart + 1);
+    }
+
+    /** Creates a new {@link ByteRange} from {@code mStart} to {@code mEnd + length}. */
+    ByteRange extend(long length) {
+        Preconditions.checkArgument(length > 0);
+        return new ByteRange(mStart, mEnd + length);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) {
+            return true;
+        }
+        if (!(o instanceof ByteRange)) {
+            return false;
+        }
+
+        ByteRange byteRange = (ByteRange) o;
+        return (mEnd == byteRange.mEnd && mStart == byteRange.mStart);
+    }
+
+    @Override
+    public int hashCode() {
+        int result = 17;
+        result = 31 * result + (int) (mStart ^ (mStart >>> 32));
+        result = 31 * result + (int) (mEnd ^ (mEnd >>> 32));
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        return String.format("ByteRange{mStart=%d, mEnd=%d}", mStart, mEnd);
+    }
+}
diff --git a/services/backup/java/com/android/server/backup/encryption/chunking/DiffScriptBackupWriter.java b/services/backup/java/com/android/server/backup/encryption/chunking/DiffScriptBackupWriter.java
new file mode 100644
index 0000000..69fb5cb
--- /dev/null
+++ b/services/backup/java/com/android/server/backup/encryption/chunking/DiffScriptBackupWriter.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2018 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.encryption.chunking;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/** Writes backup data to a diff script, using a {@link SingleStreamDiffScriptWriter}. */
+public class DiffScriptBackupWriter implements BackupWriter {
+    /**
+     * The maximum size of a chunk in the diff script. The diff script writer {@code mWriter} will
+     * buffer this many bytes in memory.
+     */
+    private static final int ENCRYPTION_DIFF_SCRIPT_MAX_CHUNK_SIZE_BYTES = 1024 * 1024;
+
+    private final SingleStreamDiffScriptWriter mWriter;
+    private long mBytesWritten;
+
+    /**
+     * Constructs a new writer which writes the diff script to the given output stream, using the
+     * maximum new chunk size {@code ENCRYPTION_DIFF_SCRIPT_MAX_CHUNK_SIZE_BYTES}.
+     */
+    public static DiffScriptBackupWriter newInstance(OutputStream outputStream) {
+        SingleStreamDiffScriptWriter writer =
+                new SingleStreamDiffScriptWriter(
+                        outputStream, ENCRYPTION_DIFF_SCRIPT_MAX_CHUNK_SIZE_BYTES);
+        return new DiffScriptBackupWriter(writer);
+    }
+
+    @VisibleForTesting
+    DiffScriptBackupWriter(SingleStreamDiffScriptWriter writer) {
+        mWriter = writer;
+    }
+
+    @Override
+    public void writeBytes(byte[] bytes) throws IOException {
+        for (byte b : bytes) {
+            mWriter.writeByte(b);
+        }
+
+        mBytesWritten += bytes.length;
+    }
+
+    @Override
+    public void writeChunk(long start, int length) throws IOException {
+        mWriter.writeChunk(start, length);
+        mBytesWritten += length;
+    }
+
+    @Override
+    public long getBytesWritten() {
+        return mBytesWritten;
+    }
+
+    @Override
+    public void flush() throws IOException {
+        mWriter.flush();
+    }
+}
diff --git a/services/backup/java/com/android/server/backup/encryption/chunking/DiffScriptWriter.java b/services/backup/java/com/android/server/backup/encryption/chunking/DiffScriptWriter.java
new file mode 100644
index 0000000..49d1571
--- /dev/null
+++ b/services/backup/java/com/android/server/backup/encryption/chunking/DiffScriptWriter.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2018 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.encryption.chunking;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+/** Writer that formats a Diff Script and writes it to an output source. */
+interface DiffScriptWriter {
+    /** Adds a new byte to the diff script. */
+    void writeByte(byte b) throws IOException;
+
+    /** Adds a known chunk to the diff script. */
+    void writeChunk(long chunkStart, int chunkLength) throws IOException;
+
+    /** Indicates that no more bytes or chunks will be added to the diff script. */
+    void flush() throws IOException;
+
+    interface Factory {
+        DiffScriptWriter create(OutputStream outputStream);
+    }
+}
diff --git a/core/java/android/app/ISmsAppService.aidl b/services/backup/java/com/android/server/backup/encryption/chunking/OutputStreamWrapper.java
similarity index 65%
copy from core/java/android/app/ISmsAppService.aidl
copy to services/backup/java/com/android/server/backup/encryption/chunking/OutputStreamWrapper.java
index 1ac2ec6..4aea601 100644
--- a/core/java/android/app/ISmsAppService.aidl
+++ b/services/backup/java/com/android/server/backup/encryption/chunking/OutputStreamWrapper.java
@@ -14,10 +14,12 @@
  * limitations under the License.
  */
 
-package android.app;
+package com.android.server.backup.encryption.chunking;
 
-/**
- * @hide
- */
-interface ISmsAppService {
+import java.io.OutputStream;
+
+/** An interface that wraps one {@link OutputStream} with another for filtration purposes. */
+public interface OutputStreamWrapper {
+    /** Wraps a given {@link OutputStream}. */
+    OutputStream wrap(OutputStream outputStream);
 }
diff --git a/services/backup/java/com/android/server/backup/encryption/chunking/SingleStreamDiffScriptWriter.java b/services/backup/java/com/android/server/backup/encryption/chunking/SingleStreamDiffScriptWriter.java
new file mode 100644
index 0000000..0e4bd58
--- /dev/null
+++ b/services/backup/java/com/android/server/backup/encryption/chunking/SingleStreamDiffScriptWriter.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2018 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.encryption.chunking;
+
+import android.annotation.Nullable;
+
+import com.android.internal.util.Preconditions;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.charset.Charset;
+import java.util.Locale;
+
+/**
+ * A {@link DiffScriptWriter} that writes an entire diff script to a single {@link OutputStream}.
+ */
+public class SingleStreamDiffScriptWriter implements DiffScriptWriter {
+    static final byte LINE_SEPARATOR = 0xA;
+    private static final Charset UTF_8 = Charset.forName("UTF-8");
+
+    private final int mMaxNewByteChunkSize;
+    private final OutputStream mOutputStream;
+    private final byte[] mByteBuffer;
+    private int mBufferSize = 0;
+    // Each chunk could be written immediately to the output stream. However,
+    // it is possible that chunks may overlap. We therefore cache the most recent
+    // reusable chunk and try to merge it with future chunks.
+    private ByteRange mReusableChunk;
+
+    public SingleStreamDiffScriptWriter(OutputStream outputStream, int maxNewByteChunkSize) {
+        mOutputStream = outputStream;
+        mMaxNewByteChunkSize = maxNewByteChunkSize;
+        mByteBuffer = new byte[maxNewByteChunkSize];
+    }
+
+    @Override
+    public void writeByte(byte b) throws IOException {
+        if (mReusableChunk != null) {
+            writeReusableChunk();
+        }
+        mByteBuffer[mBufferSize++] = b;
+        if (mBufferSize == mMaxNewByteChunkSize) {
+            writeByteBuffer();
+        }
+    }
+
+    @Override
+    public void writeChunk(long chunkStart, int chunkLength) throws IOException {
+        Preconditions.checkArgument(chunkStart >= 0);
+        Preconditions.checkArgument(chunkLength > 0);
+        if (mBufferSize != 0) {
+            writeByteBuffer();
+        }
+
+        if (mReusableChunk != null && mReusableChunk.getEnd() + 1 == chunkStart) {
+            // The new chunk overlaps the old, so combine them into a single byte range.
+            mReusableChunk = mReusableChunk.extend(chunkLength);
+        } else {
+            writeReusableChunk();
+            mReusableChunk = new ByteRange(chunkStart, chunkStart + chunkLength - 1);
+        }
+    }
+
+    @Override
+    public void flush() throws IOException {
+        Preconditions.checkState(!(mBufferSize != 0 && mReusableChunk != null));
+        if (mBufferSize != 0) {
+            writeByteBuffer();
+        }
+        if (mReusableChunk != null) {
+            writeReusableChunk();
+        }
+        mOutputStream.flush();
+    }
+
+    private void writeByteBuffer() throws IOException {
+        mOutputStream.write(Integer.toString(mBufferSize).getBytes(UTF_8));
+        mOutputStream.write(LINE_SEPARATOR);
+        mOutputStream.write(mByteBuffer, 0, mBufferSize);
+        mOutputStream.write(LINE_SEPARATOR);
+        mBufferSize = 0;
+    }
+
+    private void writeReusableChunk() throws IOException {
+        if (mReusableChunk != null) {
+            mOutputStream.write(
+                    String.format(
+                                    Locale.US,
+                                    "%d-%d",
+                                    mReusableChunk.getStart(),
+                                    mReusableChunk.getEnd())
+                            .getBytes(UTF_8));
+            mOutputStream.write(LINE_SEPARATOR);
+            mReusableChunk = null;
+        }
+    }
+
+    /** A factory that creates {@link SingleStreamDiffScriptWriter}s. */
+    public static class Factory implements DiffScriptWriter.Factory {
+        private final int mMaxNewByteChunkSize;
+        private final OutputStreamWrapper mOutputStreamWrapper;
+
+        public Factory(int maxNewByteChunkSize, @Nullable OutputStreamWrapper outputStreamWrapper) {
+            mMaxNewByteChunkSize = maxNewByteChunkSize;
+            mOutputStreamWrapper = outputStreamWrapper;
+        }
+
+        @Override
+        public SingleStreamDiffScriptWriter create(OutputStream outputStream) {
+            if (mOutputStreamWrapper != null) {
+                outputStream = mOutputStreamWrapper.wrap(outputStream);
+            }
+            return new SingleStreamDiffScriptWriter(outputStream, mMaxNewByteChunkSize);
+        }
+    }
+}
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
index 9249c9c..4afbc64 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
@@ -23,6 +23,7 @@
 import android.annotation.Nullable;
 import android.annotation.UserIdInt;
 import android.app.ActivityManagerInternal;
+import android.app.ActivityThread;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -39,6 +40,7 @@
 import android.os.ShellCallback;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.provider.DeviceConfig;
 import android.provider.Settings;
 import android.util.LocalLog;
 import android.util.Slog;
@@ -89,19 +91,38 @@
     @Nullable
     private SparseBooleanArray mDisabledUsers;
 
+    /**
+     * Global kill-switch based on value defined by
+     * {@link ContentCaptureManager#DEVICE_CONFIG_PROPERTY_SERVICE_EXPLICITLY_ENABLED}.
+     */
+    @GuardedBy("mLock")
+    @Nullable
+    private boolean mDisabledByDeviceConfig;
 
     public ContentCaptureManagerService(@NonNull Context context) {
         super(context, new FrameworkResourcesServiceNameResolver(context,
                 com.android.internal.R.string.config_defaultContentCaptureService),
                 UserManager.DISALLOW_CONTENT_CAPTURE);
-        // Sets which serviecs are disabled
+        DeviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
+                ActivityThread.currentApplication().getMainExecutor(),
+                (namespace, key, value) -> {
+                    if (!ContentCaptureManager.DEVICE_CONFIG_PROPERTY_SERVICE_EXPLICITLY_ENABLED
+                            .equals(key)) {
+                        Slog.i(mTag, "Ignoring change on " + key);
+                        return;
+                    }
+                    setDisabledByDeviceConfig(value);
+                });
+        setDisabledByDeviceConfig();
+
+        // Sets which services are disabled
         final UserManager um = getContext().getSystemService(UserManager.class);
         final List<UserInfo> users = um.getUsers();
         for (int i = 0; i < users.size(); i++) {
             final int userId = users.get(i).id;
-            final boolean disabled = isDisabledBySettings(userId);
+            final boolean disabled = mDisabledByDeviceConfig || isDisabledBySettings(userId);
             if (disabled) {
-                Slog.i(mTag, "user " + userId + " disabled by settings");
+                Slog.i(mTag, "user " + userId + " disabled by settings or device config");
                 if (mDisabledUsers == null) {
                     mDisabledUsers = new SparseBooleanArray(1);
                 }
@@ -160,7 +181,8 @@
 
     @Override // from AbstractMasterSystemService
     protected boolean isDisabledLocked(@UserIdInt int userId) {
-        return isDisabledBySettingsLocked(userId) || super.isDisabledLocked(userId);
+        return mDisabledByDeviceConfig || isDisabledBySettingsLocked(userId)
+                || super.isDisabledLocked(userId);
     }
 
     private boolean isDisabledBySettingsLocked(@UserIdInt int userId) {
@@ -191,6 +213,45 @@
         return false;
     }
 
+    private void setDisabledByDeviceConfig() {
+        final String value = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
+                ContentCaptureManager.DEVICE_CONFIG_PROPERTY_SERVICE_EXPLICITLY_ENABLED);
+        setDisabledByDeviceConfig(value);
+    }
+
+    private void setDisabledByDeviceConfig(@Nullable String value) {
+        if (verbose) Slog.v(mTag, "setDisabledByDeviceConfig(): value=" + value);
+        final UserManager um = getContext().getSystemService(UserManager.class);
+        final List<UserInfo> users = um.getUsers();
+
+        final boolean newDisabledValue;
+
+        if (value != null && value.equalsIgnoreCase("false")) {
+            newDisabledValue = true;
+        } else {
+            newDisabledValue = false;
+        }
+
+        synchronized (mLock) {
+            if (mDisabledByDeviceConfig == newDisabledValue) {
+                if (verbose) {
+                    Slog.v(mTag, "setDisabledByDeviceConfig(): already " + newDisabledValue);
+                }
+                return;
+            }
+            mDisabledByDeviceConfig = newDisabledValue;
+
+            Slog.i(mTag, "setDisabledByDeviceConfig(): set to " + mDisabledByDeviceConfig);
+            for (int i = 0; i < users.size(); i++) {
+                final int userId = users.get(i).id;
+                boolean disabled = mDisabledByDeviceConfig || isDisabledBySettingsLocked(userId);
+                Slog.i(mTag, "setDisabledByDeviceConfig(): updating service for user "
+                        + userId + " to " + (disabled ? "'disabled'" : "'enabled'"));
+                updateCachedServiceLocked(userId, disabled);
+            }
+        }
+    }
+
     private void setContentCaptureFeatureEnabledForUser(@UserIdInt int userId, boolean enabled) {
         synchronized (mLock) {
             if (mDisabledUsers == null) {
@@ -338,6 +399,8 @@
         super.dumpLocked(prefix, pw);
 
         pw.print(prefix); pw.print("Disabled users: "); pw.println(mDisabledUsers);
+        pw.print(prefix); pw.print("Disabled by DeviceConfig: ");
+        pw.println(mDisabledByDeviceConfig);
     }
 
     final class ContentCaptureManagerServiceStub extends IContentCaptureManager.Stub {
@@ -406,7 +469,7 @@
                         "isContentCaptureFeatureEnabled()", userId, Binder.getCallingUid(), result);
                 if (!isService) return;
 
-                enabled = !isDisabledBySettingsLocked(userId);
+                enabled = !mDisabledByDeviceConfig && !isDisabledBySettingsLocked(userId);
             }
             try {
                 result.send(enabled ? ContentCaptureManager.RESULT_CODE_TRUE
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerServiceShellCommand.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerServiceShellCommand.java
index 2f78276..39d5c9d 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerServiceShellCommand.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerServiceShellCommand.java
@@ -77,6 +77,15 @@
             pw.println("    Temporarily (for DURATION ms) changes the service implemtation.");
             pw.println("    To reset, call with just the USER_ID argument.");
             pw.println("");
+            pw.println("");
+            pw.println("  set default-service-enabled USER_ID [true|false]");
+            pw.println("    Enable / disable the default service for the user.");
+            pw.println("");
+            pw.println("");
+            pw.println("  get default-service-enabled USER_ID");
+            pw.println("    Checks whether the default service is enabled for the user.");
+            pw.println("");
+            pw.println("");
             pw.println("  list sessions [--user USER_ID]");
             pw.println("    Lists all pending sessions.");
             pw.println("");
@@ -91,6 +100,8 @@
         switch(what) {
             case "bind-instant-service-allowed":
                 return getBindInstantService(pw);
+            case "default-service-enabled":
+                return getDefaultServiceEnabled(pw);
             default:
                 pw.println("Invalid set: " + what);
                 return -1;
@@ -105,6 +116,8 @@
                 return setBindInstantService(pw);
             case "temporary-service":
                 return setTemporaryService(pw);
+            case "default-service-enabled":
+                return setDefaultServiceEnabled();
             default:
                 pw.println("Invalid set: " + what);
                 return -1;
@@ -149,6 +162,20 @@
         return 0;
     }
 
+    private int setDefaultServiceEnabled() {
+        final int userId = getNextIntArgRequired();
+        final boolean enabled = Boolean.parseBoolean(getNextArg());
+        mService.setDefaultServiceEnabled(userId, enabled);
+        return 0;
+    }
+
+    private int getDefaultServiceEnabled(PrintWriter pw) {
+        final int userId = getNextIntArgRequired();
+        final boolean enabled = mService.isDefaultServiceEnabled(userId);
+        pw.println(enabled);
+        return 0;
+    }
+
     private int requestDestroy(PrintWriter pw) {
         if (!isNextArgSessions(pw)) {
             return -1;
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 1cb2c4a..fe4411c 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1833,14 +1833,20 @@
                 "ConnectivityService");
     }
 
-    private void enforceAnyPermissionOf(String... permissions) {
+    private boolean checkAnyPermissionOf(String... permissions) {
         for (String permission : permissions) {
             if (mContext.checkCallingOrSelfPermission(permission) == PERMISSION_GRANTED) {
-                return;
+                return true;
             }
         }
-        throw new SecurityException(
-            "Requires one of the following permissions: " + String.join(", ", permissions) + ".");
+        return false;
+    }
+
+    private void enforceAnyPermissionOf(String... permissions) {
+        if (!checkAnyPermissionOf(permissions)) {
+            throw new SecurityException("Requires one of the following permissions: "
+                    + String.join(", ", permissions) + ".");
+        }
     }
 
     private void enforceInternetPermission() {
@@ -1860,19 +1866,22 @@
     }
 
     private void enforceSettingsPermission() {
-        mContext.enforceCallingOrSelfPermission(
+        enforceAnyPermissionOf(
                 android.Manifest.permission.NETWORK_SETTINGS,
-                "ConnectivityService");
+                NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK);
     }
 
     private boolean checkSettingsPermission() {
-        return PERMISSION_GRANTED == mContext.checkCallingOrSelfPermission(
-                android.Manifest.permission.NETWORK_SETTINGS);
+        return checkAnyPermissionOf(
+                android.Manifest.permission.NETWORK_SETTINGS,
+                NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK);
     }
 
     private boolean checkSettingsPermission(int pid, int uid) {
         return PERMISSION_GRANTED == mContext.checkPermission(
-                android.Manifest.permission.NETWORK_SETTINGS, pid, uid);
+                android.Manifest.permission.NETWORK_SETTINGS, pid, uid)
+                || PERMISSION_GRANTED == mContext.checkPermission(
+                NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK, pid, uid);
     }
 
     private void enforceTetherAccessPermission() {
@@ -1882,9 +1891,9 @@
     }
 
     private void enforceConnectivityInternalPermission() {
-        mContext.enforceCallingOrSelfPermission(
+        enforceAnyPermissionOf(
                 android.Manifest.permission.CONNECTIVITY_INTERNAL,
-                "ConnectivityService");
+                NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK);
     }
 
     private void enforceControlAlwaysOnVpnPermission() {
@@ -1895,20 +1904,16 @@
 
     private void enforceNetworkStackSettingsOrSetup() {
         enforceAnyPermissionOf(
-            android.Manifest.permission.NETWORK_SETTINGS,
-            android.Manifest.permission.NETWORK_SETUP_WIZARD,
-            android.Manifest.permission.NETWORK_STACK);
-    }
-
-    private void enforceNetworkStackPermission() {
-        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.NETWORK_SETTINGS,
+                android.Manifest.permission.NETWORK_SETUP_WIZARD,
                 android.Manifest.permission.NETWORK_STACK,
-                "ConnectivityService");
+                NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK);
     }
 
     private boolean checkNetworkStackPermission() {
-        return PERMISSION_GRANTED == mContext.checkCallingOrSelfPermission(
-                android.Manifest.permission.NETWORK_STACK);
+        return checkAnyPermissionOf(
+                android.Manifest.permission.NETWORK_STACK,
+                NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK);
     }
 
     private void enforceConnectivityRestrictedNetworksPermission() {
@@ -3240,6 +3245,25 @@
         });
     }
 
+    /**
+     * NetworkStack endpoint to start the captive portal app. The NetworkStack needs to use this
+     * endpoint as it does not have INTERACT_ACROSS_USERS_FULL itself.
+     * @param appExtras Bundle to use as intent extras for the captive portal application.
+     *                  Must be treated as opaque to avoid preventing the captive portal app to
+     *                  update its arguments.
+     */
+    @Override
+    public void startCaptivePortalAppInternal(Bundle appExtras) {
+        mContext.checkCallingOrSelfPermission(NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK);
+
+        final Intent appIntent = new Intent(ConnectivityManager.ACTION_CAPTIVE_PORTAL_SIGN_IN);
+        appIntent.putExtras(appExtras);
+        appIntent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT | Intent.FLAG_ACTIVITY_NEW_TASK);
+
+        Binder.withCleanCallingIdentity(() ->
+                mContext.startActivityAsUser(appIntent, UserHandle.CURRENT));
+    }
+
     public boolean avoidBadWifi() {
         return mMultinetworkPolicyTracker.getAvoidBadWifi();
     }
@@ -6377,6 +6401,14 @@
     }
 
     @Override
+    public void startTcpKeepalive(Network network, FileDescriptor fd, int intervalSeconds,
+            Messenger messenger, IBinder binder) {
+        enforceKeepalivePermission();
+        mKeepaliveTracker.startTcpKeepalive(
+                getNetworkAgentInfoForNetwork(network), fd, intervalSeconds, messenger, binder);
+    }
+
+    @Override
     public void stopKeepalive(Network network, int slot) {
         mHandler.sendMessage(mHandler.obtainMessage(
                 NetworkAgent.CMD_STOP_SOCKET_KEEPALIVE, slot, SocketKeepalive.SUCCESS, network));
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 5278bbb..4834ce0 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -792,7 +792,7 @@
         String[] testProviderStrings = resources.getStringArray(
                 com.android.internal.R.array.config_testLocationProviders);
         for (String testProviderString : testProviderStrings) {
-            String fragments[] = testProviderString.split(",");
+            String[] fragments = testProviderString.split(",");
             String name = fragments[0].trim();
             ProviderProperties properties = new ProviderProperties(
                     Boolean.parseBoolean(fragments[1]) /* requiresNetwork */,
@@ -816,12 +816,6 @@
             return;
         }
 
-        // this call has the side effect of forcing a write to the LOCATION_MODE setting in an OS
-        // upgrade case, and ensures that if anyone checks the LOCATION_MODE setting directly, they
-        // will see it in an appropriate state (at least after that user becomes foreground for the
-        // first time...)
-        isLocationEnabledForUser(userId);
-
         // let providers know the current user is on the way out before changing the user
         for (LocationProvider p : mProviders) {
             p.onUserChangingLocked();
@@ -934,17 +928,22 @@
 
         @GuardedBy("mLock")
         public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args) {
-            pw.println(mName + " provider:");
+            pw.print("  " + mName + " provider");
             if (isMock()) {
-                pw.println(" mock=true");
+                pw.print(" [mock]");
             }
-            pw.println(" attached=" + (mProvider != null));
-            if (mIsManagedBySettings) {
-                pw.println(" allowed=" + mAllowed);
+            pw.println(":");
+
+            pw.println("    useable=" + mUseable);
+            if (!mUseable) {
+                pw.println("    attached=" + (mProvider != null));
+                if (mIsManagedBySettings) {
+                    pw.println("    allowed=" + mAllowed);
+                }
+                pw.println("    enabled=" + mEnabled);
             }
-            pw.println(" enabled=" + mEnabled);
-            pw.println(" useable=" + mUseable);
-            pw.println(" properties=" + mProperties);
+
+            pw.println("    properties=" + mProperties);
 
             if (mProvider != null) {
                 long identity = Binder.clearCallingIdentity();
@@ -1397,14 +1396,10 @@
         public boolean callStatusChangedLocked(String provider, int status, Bundle extras) {
             if (mListener != null) {
                 try {
-                    synchronized (this) {
-                        // synchronize to ensure incrementPendingBroadcastsLocked()
-                        // is called before decrementPendingBroadcasts()
-                        mListener.onStatusChanged(provider, status, extras);
-                        // call this after broadcasting so we do not increment
-                        // if we throw an exeption.
-                        incrementPendingBroadcastsLocked();
-                    }
+                    mListener.onStatusChanged(provider, status, extras);
+                    // call this after broadcasting so we do not increment
+                    // if we throw an exception.
+                    incrementPendingBroadcastsLocked();
                 } catch (RemoteException e) {
                     return false;
                 }
@@ -1413,16 +1408,12 @@
                 statusChanged.putExtras(new Bundle(extras));
                 statusChanged.putExtra(LocationManager.KEY_STATUS_CHANGED, status);
                 try {
-                    synchronized (this) {
-                        // synchronize to ensure incrementPendingBroadcastsLocked()
-                        // is called before decrementPendingBroadcasts()
-                        mPendingIntent.send(mContext, 0, statusChanged, this, mHandler,
-                                getResolutionPermission(mAllowedResolutionLevel),
-                                PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
-                        // call this after broadcasting so we do not increment
-                        // if we throw an exeption.
-                        incrementPendingBroadcastsLocked();
-                    }
+                    mPendingIntent.send(mContext, 0, statusChanged, this, mHandler,
+                            getResolutionPermission(mAllowedResolutionLevel),
+                            PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
+                    // call this after broadcasting so we do not increment
+                    // if we throw an exception.
+                    incrementPendingBroadcastsLocked();
                 } catch (PendingIntent.CanceledException e) {
                     return false;
                 }
@@ -1433,14 +1424,10 @@
         public boolean callLocationChangedLocked(Location location) {
             if (mListener != null) {
                 try {
-                    synchronized (this) {
-                        // synchronize to ensure incrementPendingBroadcastsLocked()
-                        // is called before decrementPendingBroadcasts()
-                        mListener.onLocationChanged(new Location(location));
-                        // call this after broadcasting so we do not increment
-                        // if we throw an exeption.
-                        incrementPendingBroadcastsLocked();
-                    }
+                    mListener.onLocationChanged(new Location(location));
+                    // call this after broadcasting so we do not increment
+                    // if we throw an exception.
+                    incrementPendingBroadcastsLocked();
                 } catch (RemoteException e) {
                     return false;
                 }
@@ -1449,16 +1436,12 @@
                 locationChanged.putExtra(LocationManager.KEY_LOCATION_CHANGED,
                         new Location(location));
                 try {
-                    synchronized (this) {
-                        // synchronize to ensure incrementPendingBroadcastsLocked()
-                        // is called before decrementPendingBroadcasts()
-                        mPendingIntent.send(mContext, 0, locationChanged, this, mHandler,
-                                getResolutionPermission(mAllowedResolutionLevel),
-                                PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
-                        // call this after broadcasting so we do not increment
-                        // if we throw an exeption.
-                        incrementPendingBroadcastsLocked();
-                    }
+                    mPendingIntent.send(mContext, 0, locationChanged, this, mHandler,
+                            getResolutionPermission(mAllowedResolutionLevel),
+                            PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
+                    // call this after broadcasting so we do not increment
+                    // if we throw an exception.
+                    incrementPendingBroadcastsLocked();
                 } catch (PendingIntent.CanceledException e) {
                     return false;
                 }
@@ -1473,18 +1456,14 @@
 
             if (mListener != null) {
                 try {
-                    synchronized (this) {
-                        // synchronize to ensure incrementPendingBroadcastsLocked()
-                        // is called before decrementPendingBroadcasts()
-                        if (enabled) {
-                            mListener.onProviderEnabled(provider);
-                        } else {
-                            mListener.onProviderDisabled(provider);
-                        }
-                        // call this after broadcasting so we do not increment
-                        // if we throw an exeption.
-                        incrementPendingBroadcastsLocked();
+                    if (enabled) {
+                        mListener.onProviderEnabled(provider);
+                    } else {
+                        mListener.onProviderDisabled(provider);
                     }
+                    // call this after broadcasting so we do not increment
+                    // if we throw an exception.
+                    incrementPendingBroadcastsLocked();
                 } catch (RemoteException e) {
                     return false;
                 }
@@ -1492,16 +1471,12 @@
                 Intent providerIntent = new Intent();
                 providerIntent.putExtra(LocationManager.KEY_PROVIDER_ENABLED, enabled);
                 try {
-                    synchronized (this) {
-                        // synchronize to ensure incrementPendingBroadcastsLocked()
-                        // is called before decrementPendingBroadcasts()
-                        mPendingIntent.send(mContext, 0, providerIntent, this, mHandler,
-                                getResolutionPermission(mAllowedResolutionLevel),
-                                PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
-                        // call this after broadcasting so we do not increment
-                        // if we throw an exeption.
-                        incrementPendingBroadcastsLocked();
-                    }
+                    mPendingIntent.send(mContext, 0, providerIntent, this, mHandler,
+                            getResolutionPermission(mAllowedResolutionLevel),
+                            PendingIntentUtils.createDontSendToRestrictedAppsBundle(null));
+                    // call this after broadcasting so we do not increment
+                    // if we throw an exception.
+                    incrementPendingBroadcastsLocked();
                 } catch (PendingIntent.CanceledException e) {
                     return false;
                 }
@@ -1515,8 +1490,6 @@
 
             synchronized (mLock) {
                 removeUpdatesLocked(this);
-            }
-            synchronized (this) {
                 clearPendingBroadcastsLocked();
             }
         }
@@ -1524,7 +1497,7 @@
         @Override
         public void onSendFinished(PendingIntent pendingIntent, Intent intent,
                 int resultCode, String resultData, Bundle resultExtras) {
-            synchronized (this) {
+            synchronized (mLock) {
                 decrementPendingBroadcastsLocked();
             }
         }
@@ -1533,13 +1506,25 @@
         // containing the sending of the broadcaset
         private void incrementPendingBroadcastsLocked() {
             mPendingBroadcasts++;
-            mWakeLock.acquire(WAKELOCK_TIMEOUT_MILLIS);
+            // so wakelock calls will succeed
+            long identity = Binder.clearCallingIdentity();
+            try {
+                mWakeLock.acquire(WAKELOCK_TIMEOUT_MILLIS);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
         }
 
         private void decrementPendingBroadcastsLocked() {
             if (--mPendingBroadcasts == 0) {
-                if (mWakeLock.isHeld()) {
-                    mWakeLock.release();
+                // so wakelock calls will succeed
+                long identity = Binder.clearCallingIdentity();
+                try {
+                    if (mWakeLock.isHeld()) {
+                        mWakeLock.release();
+                    }
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
                 }
             }
         }
@@ -1547,8 +1532,14 @@
         public void clearPendingBroadcastsLocked() {
             if (mPendingBroadcasts > 0) {
                 mPendingBroadcasts = 0;
-                if (mWakeLock.isHeld()) {
-                    mWakeLock.release();
+                // so wakelock calls will succeed
+                long identity = Binder.clearCallingIdentity();
+                try {
+                    if (mWakeLock.isHeld()) {
+                        mWakeLock.release();
+                    }
+                } finally {
+                    Binder.restoreCallingIdentity(identity);
                 }
             }
         }
@@ -1561,18 +1552,9 @@
         //LocationListener was removed when it had a pending broadcast and should
         //not be added back.
         synchronized (mLock) {
-            IBinder binder = listener.asBinder();
-            Receiver receiver = mReceivers.get(binder);
+            Receiver receiver = mReceivers.get(listener.asBinder());
             if (receiver != null) {
-                synchronized (receiver) {
-                    // so wakelock calls will succeed
-                    long identity = Binder.clearCallingIdentity();
-                    try {
-                        receiver.decrementPendingBroadcastsLocked();
-                    } finally {
-                        Binder.restoreCallingIdentity(identity);
-                    }
-                }
+                receiver.decrementPendingBroadcastsLocked();
             }
         }
     }
@@ -2072,6 +2054,7 @@
                 if (!provider.isUseableLocked()) {
                     if (isSettingsExemptLocked(record)) {
                         providerRequest.forceLocation = true;
+                        providerRequest.lowPowerMode = false;
                     } else {
                         continue;
                     }
@@ -2080,7 +2063,9 @@
                 LocationRequest locationRequest = record.mRealRequest;
                 long interval = locationRequest.getInterval();
 
-                if (!isThrottlingExemptLocked(record.mReceiver.mCallerIdentity)) {
+                // if we're forcing location, don't apply any throttling
+                if (!providerRequest.forceLocation && !isThrottlingExemptLocked(
+                        record.mReceiver.mCallerIdentity)) {
                     if (!record.mIsForegroundUid) {
                         interval = Math.max(interval, backgroundThrottleInterval);
                     }
@@ -2174,11 +2159,8 @@
             return true;
         }
 
-        if (isProviderPackage(callerIdentity.mPackageName)) {
-            return true;
-        }
+        return isProviderPackage(callerIdentity.mPackageName);
 
-        return false;
     }
 
     @GuardedBy("mLock")
@@ -2192,11 +2174,8 @@
             return true;
         }
 
-        if (isProviderPackage(record.mReceiver.mCallerIdentity.mPackageName)) {
-            return true;
-        }
+        return isProviderPackage(record.mReceiver.mCallerIdentity.mPackageName);
 
-        return false;
     }
 
     private class UpdateRecord {
@@ -2504,9 +2483,7 @@
 
         if (mReceivers.remove(receiver.mKey) != null && receiver.isListener()) {
             receiver.getListener().asBinder().unlinkToDeath(receiver, 0);
-            synchronized (receiver) {
-                receiver.clearPendingBroadcastsLocked();
-            }
+            receiver.clearPendingBroadcastsLocked();
         }
 
         receiver.updateMonitoring(false);
@@ -2682,7 +2659,6 @@
 
             // geo-fence manager uses the public location API, need to clear identity
             int uid = Binder.getCallingUid();
-            // TODO: http://b/23822629
             if (UserHandle.getUserId(uid) != UserHandle.USER_SYSTEM) {
                 // temporary measure until geofences work for secondary users
                 Log.w(TAG, "proximity alerts are currently available only to the primary user");
@@ -2723,8 +2699,6 @@
             return false;
         }
 
-        // TODO(b/120449926): The GNSS status listeners should be handled similar to the GNSS
-        // measurements listeners.
         return mGnssStatusProvider.addListener(callback, new CallerIdentity(Binder.getCallingUid(),
                 Binder.getCallingPid(), packageName));
     }
@@ -2744,7 +2718,6 @@
         synchronized (mLock) {
             CallerIdentity callerIdentity = new CallerIdentity(Binder.getCallingUid(),
                     Binder.getCallingPid(), packageName);
-            // TODO(b/120481270): Register for client death notification and update map.
             mGnssMeasurementsListeners.put(listener.asBinder(), callerIdentity);
             long identity = Binder.clearCallingIdentity();
             try {
@@ -2768,9 +2741,9 @@
                 android.Manifest.permission.LOCATION_HARDWARE,
                 "Location Hardware permission not granted to inject GNSS measurement corrections.");
         if (!hasGnssPermissions(packageName) || mGnssMeasurementsProvider == null) {
-            mGnssMeasurementsProvider.injectGnssMeasurementCorrections(measurementCorrections);
-        } else {
             Slog.e(TAG, "Can not inject GNSS corrections due to no permission.");
+        } else {
+            mGnssMeasurementsProvider.injectGnssMeasurementCorrections(measurementCorrections);
         }
     }
 
@@ -2809,7 +2782,6 @@
             CallerIdentity callerIdentity = new CallerIdentity(Binder.getCallingUid(),
                     Binder.getCallingPid(), packageName);
 
-            // TODO(b/120481270): Register for client death notification and update map.
             mGnssNavigationMessageListeners.put(listener.asBinder(), callerIdentity);
             long identity = Binder.clearCallingIdentity();
             try {
@@ -3382,7 +3354,9 @@
                 return;
             }
             pw.println("Current Location Manager state:");
-            pw.println("  Location Mode: " + isLocationEnabled());
+            pw.println("  Current user: " + mCurrentUserId + " " + Arrays.toString(
+                    mCurrentUserProfiles));
+            pw.println("  Location mode: " + isLocationEnabled());
             pw.println("  Location Listeners:");
             for (Receiver receiver : mReceivers.values()) {
                 pw.println("    " + receiver);
@@ -3406,14 +3380,6 @@
                         + callerIdentity.mPackageName + ": "
                         + isThrottlingExemptLocked(callerIdentity));
             }
-            pw.println("  Overlay Provider Packages:");
-            for (LocationProvider provider : mProviders) {
-                if (provider.mProvider instanceof LocationProviderProxy) {
-                    pw.println("    " + provider.getName() + ": "
-                            + ((LocationProviderProxy) provider.mProvider)
-                            .getProviderPackages());
-                }
-            }
             pw.println("  Historical Records by Provider:");
             for (Map.Entry<PackageProviderKey, PackageStatistics> entry
                     : mRequestStatistics.statistics.entrySet()) {
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index f2329d3..e7d7434 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -4013,7 +4013,7 @@
                     return;
                 }
                 userPackages.add(packageName);
-                sandboxId = getSandboxId(packageName, sharedUserId);
+                sandboxId = StorageManagerService.this.getSandboxId(packageName, sharedUserId);
             }
 
             try {
@@ -4028,7 +4028,8 @@
             if (!ENABLE_ISOLATED_STORAGE) {
                 return;
             }
-            final String sandboxId = getSandboxId(packageName, sharedUserId);
+            final String sandboxId = StorageManagerService.this.getSandboxId(
+                    packageName, sharedUserId);
             synchronized (mPackagesLock) {
                 final ArraySet<String> userPackages = mPackages.get(userId);
                 // If the userPackages is null, it means the user is not started but we still
@@ -4056,6 +4057,12 @@
             return visibleVolsForUser.toArray(new String[visibleVolsForUser.size()]);
         }
 
+        @Override
+        public String getSandboxId(String packageName) {
+            return StorageManagerService.this.getSandboxId(packageName,
+                    mPmInternal.getSharedUserIdForPackage(packageName));
+        }
+
         private String getVolumeLabel(VolumeInfo vol) {
             // STOPSHIP: Label needs to part of VolumeInfo and need to be passed on from vold
             switch (vol.getType()) {
diff --git a/services/core/java/com/android/server/adb/AdbDebuggingManager.java b/services/core/java/com/android/server/adb/AdbDebuggingManager.java
index c7b9a3c..eaf790b 100644
--- a/services/core/java/com/android/server/adb/AdbDebuggingManager.java
+++ b/services/core/java/com/android/server/adb/AdbDebuggingManager.java
@@ -82,6 +82,9 @@
     private static final String ADB_DIRECTORY = "misc/adb";
     // This file contains keys that will always be allowed to connect to the device via adb.
     private static final String ADB_KEYS_FILE = "adb_keys";
+    // This file contains keys that will be allowed to connect without user interaction as long
+    // as a subsequent connection occurs within the allowed duration.
+    private static final String ADB_TEMP_KEYS_FILE = "adb_temp_keys.xml";
     private static final int BUFFER_SIZE = 4096;
 
     private final Context mContext;
@@ -263,7 +266,6 @@
 
         AdbDebuggingHandler(Looper looper) {
             super(looper);
-            mAdbKeyStore = new AdbKeyStore();
         }
 
         /**
@@ -289,6 +291,7 @@
                     mThread = new AdbDebuggingThread();
                     mThread.start();
 
+                    mAdbKeyStore = new AdbKeyStore();
                     break;
 
                 case MESSAGE_ADB_DISABLED:
@@ -303,6 +306,9 @@
                         mThread = null;
                     }
 
+                    cancelJobToUpdateAdbKeyStore();
+                    mAdbKeyStore = null;
+                    mConnectedKey = null;
                     break;
 
                 case MESSAGE_ADB_ALLOW: {
@@ -532,7 +538,11 @@
         return new File(adbDir, fileName);
     }
 
-    private File getUserKeyFile() {
+    File getAdbTempKeysFile() {
+        return getAdbFile(ADB_TEMP_KEYS_FILE);
+    }
+
+    File getUserKeyFile() {
         return getAdbFile(ADB_KEYS_FILE);
     }
 
@@ -668,9 +678,6 @@
         private Map<String, Long> mKeyMap;
         private File mKeyFile;
         private AtomicFile mAtomicKeyFile;
-        // This file contains keys that will be allowed to connect without user interaction as long
-        // as a subsequent connection occurs within the allowed duration.
-        private static final String ADB_TEMP_KEYS_FILE = "adb_temp_keys.xml";
         private static final String XML_TAG_ADB_KEY = "adbKey";
         private static final String XML_ATTRIBUTE_KEY = "key";
         private static final String XML_ATTRIBUTE_LAST_CONNECTION = "lastConnection";
@@ -704,9 +711,9 @@
          */
         private void initKeyFile() {
             if (mKeyFile == null) {
-                mKeyFile = getAdbFile(ADB_TEMP_KEYS_FILE);
+                mKeyFile = getAdbTempKeysFile();
             }
-            // getAdbFile can return null if the adb file cannot be obtained
+            // getAdbTempKeysFile can return null if the adb file cannot be obtained
             if (mKeyFile != null) {
                 mAtomicKeyFile = new AtomicFile(mKeyFile);
             }
@@ -767,7 +774,8 @@
         public void persistKeyStore() {
             // if there is nothing in the key map then ensure any keys left in the key store files
             // are deleted as well.
-            if (mKeyMap.size() == 0) {
+            filterOutOldKeys();
+            if (mKeyMap.isEmpty()) {
                 deleteKeyStore();
                 return;
             }
@@ -784,22 +792,15 @@
                 keyStream = mAtomicKeyFile.startWrite();
                 serializer.setOutput(keyStream, StandardCharsets.UTF_8.name());
                 serializer.startDocument(null, true);
-                long allowedTime = getAllowedConnectionTime();
-                long systemTime = System.currentTimeMillis();
-                Iterator keyMapIterator = mKeyMap.entrySet().iterator();
-                while (keyMapIterator.hasNext()) {
-                    Map.Entry<String, Long> keyEntry = (Map.Entry) keyMapIterator.next();
-                    long connectionTime = keyEntry.getValue();
-                    if (systemTime < (connectionTime + allowedTime)) {
-                        serializer.startTag(null, XML_TAG_ADB_KEY);
-                        serializer.attribute(null, XML_ATTRIBUTE_KEY, keyEntry.getKey());
-                        serializer.attribute(null, XML_ATTRIBUTE_LAST_CONNECTION,
-                                String.valueOf(keyEntry.getValue()));
-                        serializer.endTag(null, XML_TAG_ADB_KEY);
-                    } else {
-                        keyMapIterator.remove();
-                    }
+
+                for (Map.Entry<String, Long> keyEntry : mKeyMap.entrySet()) {
+                    serializer.startTag(null, XML_TAG_ADB_KEY);
+                    serializer.attribute(null, XML_ATTRIBUTE_KEY, keyEntry.getKey());
+                    serializer.attribute(null, XML_ATTRIBUTE_LAST_CONNECTION,
+                            String.valueOf(keyEntry.getValue()));
+                    serializer.endTag(null, XML_TAG_ADB_KEY);
                 }
+
                 serializer.endDocument();
                 mAtomicKeyFile.finishWrite(keyStream);
             } catch (IOException e) {
@@ -808,6 +809,19 @@
             }
         }
 
+        private void filterOutOldKeys() {
+            long allowedTime = getAllowedConnectionTime();
+            long systemTime = System.currentTimeMillis();
+            Iterator<Map.Entry<String, Long>> keyMapIterator = mKeyMap.entrySet().iterator();
+            while (keyMapIterator.hasNext()) {
+                Map.Entry<String, Long> keyEntry = keyMapIterator.next();
+                long connectionTime = keyEntry.getValue();
+                if (allowedTime != 0 && systemTime > (connectionTime + allowedTime)) {
+                    keyMapIterator.remove();
+                }
+            }
+        }
+
         /**
          * Removes all of the entries in the key map and deletes the key file.
          */
diff --git a/services/core/java/com/android/server/adb/AdbService.java b/services/core/java/com/android/server/adb/AdbService.java
index c316915..7fd98e0 100644
--- a/services/core/java/com/android/server/adb/AdbService.java
+++ b/services/core/java/com/android/server/adb/AdbService.java
@@ -45,6 +45,7 @@
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
 
+import java.io.File;
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.Collections;
@@ -95,6 +96,16 @@
         public boolean isAdbEnabled() {
             return mAdbEnabled;
         }
+
+        @Override
+        public File getAdbKeysFile() {
+            return mDebuggingManager.getUserKeyFile();
+        }
+
+        @Override
+        public File getAdbTempKeysFile() {
+            return mDebuggingManager.getAdbTempKeysFile();
+        }
     }
 
     private final class AdbHandler extends Handler {
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 2f1f91e..026430b 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -333,7 +333,8 @@
                 }
                 r.delayed = false;
                 try {
-                    startServiceInnerLocked(this, r.pendingStarts.get(0).intent, r, false, true);
+                    startServiceInnerLocked(this, r.pendingStarts.get(0).intent, r, false, true,
+                            false);
                 } catch (TransactionTooLargeException e) {
                     // Ignore, nobody upstack cares.
                 }
@@ -643,7 +644,8 @@
                         SERVICE_BG_ACTIVITY_START_TIMEOUT_MS);
             }
         }
-        ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting);
+        ComponentName cmp = startServiceInnerLocked(smap, service, r, callerFg, addToStarting,
+                allowBackgroundActivityStarts);
         return cmp;
     }
 
@@ -702,7 +704,8 @@
     }
 
     ComponentName startServiceInnerLocked(ServiceMap smap, Intent service, ServiceRecord r,
-            boolean callerFg, boolean addToStarting) throws TransactionTooLargeException {
+            boolean callerFg, boolean addToStarting, boolean allowBackgroundActivityStarts)
+            throws TransactionTooLargeException {
         ServiceState stracker = r.getTracker();
         if (stracker != null) {
             stracker.setStarted(true, mAm.mProcessStats.getMemFactorLocked(), r.lastActivity);
@@ -713,7 +716,8 @@
         synchronized (r.stats.getBatteryStats()) {
             r.stats.startRunningLocked();
         }
-        String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false);
+        String error = bringUpServiceLocked(r, service.getFlags(), callerFg, false, false,
+                allowBackgroundActivityStarts);
         if (error != null) {
             return new ComponentName("!!", error);
         }
@@ -1645,7 +1649,7 @@
                                 try {
                                     bringUpServiceLocked(serviceRecord,
                                             serviceIntent.getFlags(),
-                                            callerFg, false, false);
+                                            callerFg, false, false, false);
                                 } catch (RemoteException e) {
                                     /* ignore - local call */
                                 }
@@ -1748,7 +1752,7 @@
             if ((flags&Context.BIND_AUTO_CREATE) != 0) {
                 s.lastActivity = SystemClock.uptimeMillis();
                 if (bringUpServiceLocked(s, service.getFlags(), callerFg, false,
-                        permissionsReviewRequired) != null) {
+                        permissionsReviewRequired, false) != null) {
                     return 0;
                 }
             }
@@ -2418,7 +2422,8 @@
             return;
         }
         try {
-            bringUpServiceLocked(r, r.intent.getIntent().getFlags(), r.createdFromFg, true, false);
+            bringUpServiceLocked(r, r.intent.getIntent().getFlags(), r.createdFromFg, true, false,
+                    false);
         } catch (TransactionTooLargeException e) {
             // Ignore, it's been logged and nothing upstack cares.
         }
@@ -2463,8 +2468,8 @@
     }
 
     private String bringUpServiceLocked(ServiceRecord r, int intentFlags, boolean execInFg,
-            boolean whileRestarting, boolean permissionsReviewRequired)
-            throws TransactionTooLargeException {
+            boolean whileRestarting, boolean permissionsReviewRequired,
+            boolean allowBackgroundActivityStarts) throws TransactionTooLargeException {
         //Slog.i(TAG, "Bring up service:");
         //r.dump("  ");
 
@@ -2575,6 +2580,13 @@
             }
         }
 
+        if (app != null && allowBackgroundActivityStarts) {
+            app.addAllowBackgroundActivityStartsToken(r);
+            // schedule removal of the whitelisting token after the timeout
+            removeAllowBackgroundActivityStartsServiceToken(app, r,
+                    SERVICE_BG_ACTIVITY_START_TIMEOUT_MS);
+        }
+
         if (r.fgRequired) {
             if (DEBUG_FOREGROUND_SERVICE) {
                 Slog.v(TAG, "Whitelisting " + UserHandle.formatUid(r.appInfo.uid)
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 94fc552..60a45bf 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2226,7 +2226,7 @@
         mConstants = hasHandlerThread ? new ActivityManagerConstants(this, mHandler) : null;
         final ActiveUids activeUids = new ActiveUids(this, false /* postChangesToAtm */);
         mProcessList.init(this, activeUids);
-        mOomAdjuster = new OomAdjuster(this, mProcessList, activeUids, new Object());
+        mOomAdjuster = new OomAdjuster(this, mProcessList, activeUids);
 
         mIntentFirewall = hasHandlerThread
                 ? new IntentFirewall(new IntentFirewallInterface(), mHandler) : null;
@@ -2274,7 +2274,7 @@
         mConstants = new ActivityManagerConstants(this, mHandler);
         final ActiveUids activeUids = new ActiveUids(this, true /* postChangesToAtm */);
         mProcessList.init(this, activeUids);
-        mOomAdjuster = new OomAdjuster(this, mProcessList, activeUids, atm.getGlobalLock());
+        mOomAdjuster = new OomAdjuster(this, mProcessList, activeUids);
 
         // Broadcast policy parameters
         final BroadcastConstants foreConstants = new BroadcastConstants(
@@ -3495,7 +3495,7 @@
             if (!app.killedByAm) {
                 reportUidInfoMessageLocked(TAG,
                         "Process " + app.processName + " (pid " + pid + ") has died: "
-                                + ProcessList.makeOomAdjString(app.setAdj)
+                                + ProcessList.makeOomAdjString(app.setAdj, true) + " "
                                 + ProcessList.makeProcStateString(app.setProcState), app.info.uid);
                 mAllowLowerMemLevel = true;
             } else {
@@ -6549,7 +6549,7 @@
                 conn = incProviderCountLocked(r, cpr, token, callingUid, callingPackage, callingTag,
                         stable);
                 if (conn != null && (conn.stableCount+conn.unstableCount) == 1) {
-                    if (cpr.proc != null && r.setAdj <= ProcessList.PERCEPTIBLE_APP_ADJ) {
+                    if (cpr.proc != null && r.setAdj <= ProcessList.PERCEPTIBLE_LOW_APP_ADJ) {
                         // If this is a perceptible app accessing the provider,
                         // make sure to count it as being accessed and thus
                         // back up on the LRU list.  This is good because
@@ -10029,7 +10029,7 @@
         pw.print("    #");
         pw.print(index);
         pw.print(": ");
-        pw.print(ProcessList.makeOomAdjString(proc.setAdj));
+        pw.print(ProcessList.makeOomAdjString(proc.setAdj, false));
         pw.print(" ");
         pw.print(ProcessList.makeProcStateString(proc.getCurProcState()));
         pw.print(" ");
@@ -10828,6 +10828,7 @@
             printOomLevel(pw, "FOREGROUND_APP_ADJ", ProcessList.FOREGROUND_APP_ADJ);
             printOomLevel(pw, "VISIBLE_APP_ADJ", ProcessList.VISIBLE_APP_ADJ);
             printOomLevel(pw, "PERCEPTIBLE_APP_ADJ", ProcessList.PERCEPTIBLE_APP_ADJ);
+            printOomLevel(pw, "PERCEPTIBLE_LOW_APP_ADJ", ProcessList.PERCEPTIBLE_LOW_APP_ADJ);
             printOomLevel(pw, "BACKUP_APP_ADJ", ProcessList.BACKUP_APP_ADJ);
             printOomLevel(pw, "HEAVY_WEIGHT_APP_ADJ", ProcessList.HEAVY_WEIGHT_APP_ADJ);
             printOomLevel(pw, "SERVICE_ADJ", ProcessList.SERVICE_ADJ);
@@ -10878,16 +10879,17 @@
         pw.println("  Total number of kills: " + cnt);
 
         return reportLmkKillAtOrBelow(pw, ProcessList.CACHED_APP_MAX_ADJ) &&
-            reportLmkKillAtOrBelow(pw, ProcessList.CACHED_APP_MIN_ADJ) &&
-            reportLmkKillAtOrBelow(pw, ProcessList.SERVICE_B_ADJ) &&
-            reportLmkKillAtOrBelow(pw, ProcessList.PREVIOUS_APP_ADJ) &&
-            reportLmkKillAtOrBelow(pw, ProcessList.HOME_APP_ADJ) &&
-            reportLmkKillAtOrBelow(pw, ProcessList.SERVICE_ADJ) &&
-            reportLmkKillAtOrBelow(pw, ProcessList.HEAVY_WEIGHT_APP_ADJ) &&
-            reportLmkKillAtOrBelow(pw, ProcessList.BACKUP_APP_ADJ) &&
-            reportLmkKillAtOrBelow(pw, ProcessList.PERCEPTIBLE_APP_ADJ) &&
-            reportLmkKillAtOrBelow(pw, ProcessList.VISIBLE_APP_ADJ) &&
-            reportLmkKillAtOrBelow(pw, ProcessList.FOREGROUND_APP_ADJ);
+                reportLmkKillAtOrBelow(pw, ProcessList.CACHED_APP_MIN_ADJ) &&
+                reportLmkKillAtOrBelow(pw, ProcessList.SERVICE_B_ADJ) &&
+                reportLmkKillAtOrBelow(pw, ProcessList.PREVIOUS_APP_ADJ) &&
+                reportLmkKillAtOrBelow(pw, ProcessList.HOME_APP_ADJ) &&
+                reportLmkKillAtOrBelow(pw, ProcessList.SERVICE_ADJ) &&
+                reportLmkKillAtOrBelow(pw, ProcessList.HEAVY_WEIGHT_APP_ADJ) &&
+                reportLmkKillAtOrBelow(pw, ProcessList.BACKUP_APP_ADJ) &&
+                reportLmkKillAtOrBelow(pw, ProcessList.PERCEPTIBLE_LOW_APP_ADJ) &&
+                reportLmkKillAtOrBelow(pw, ProcessList.PERCEPTIBLE_APP_ADJ) &&
+                reportLmkKillAtOrBelow(pw, ProcessList.VISIBLE_APP_ADJ) &&
+                reportLmkKillAtOrBelow(pw, ProcessList.FOREGROUND_APP_ADJ);
     }
 
     /**
@@ -11334,7 +11336,7 @@
         for (int i = list.size() - 1; i >= 0; i--) {
             ProcessRecord r = list.get(i).first;
             long token = proto.start(fieldId);
-            String oomAdj = ProcessList.makeOomAdjString(r.setAdj);
+            String oomAdj = ProcessList.makeOomAdjString(r.setAdj, true);
             proto.write(ProcessOomProto.PERSISTENT, r.isPersistent());
             proto.write(ProcessOomProto.NUM, (origList.size()-1)-list.get(i).second);
             proto.write(ProcessOomProto.OOM_ADJ, oomAdj);
@@ -11434,7 +11436,7 @@
 
         for (int i=list.size()-1; i>=0; i--) {
             ProcessRecord r = list.get(i).first;
-            String oomAdj = ProcessList.makeOomAdjString(r.setAdj);
+            String oomAdj = ProcessList.makeOomAdjString(r.setAdj, false);
             char schedGroup;
             switch (r.setSchedGroup) {
                 case ProcessList.SCHED_GROUP_BACKGROUND:
@@ -11760,7 +11762,8 @@
             ProcessList.NATIVE_ADJ,
             ProcessList.SYSTEM_ADJ, ProcessList.PERSISTENT_PROC_ADJ,
             ProcessList.PERSISTENT_SERVICE_ADJ, ProcessList.FOREGROUND_APP_ADJ,
-            ProcessList.VISIBLE_APP_ADJ, ProcessList.PERCEPTIBLE_APP_ADJ,
+            ProcessList.VISIBLE_APP_ADJ,
+            ProcessList.PERCEPTIBLE_APP_ADJ, ProcessList.PERCEPTIBLE_LOW_APP_ADJ,
             ProcessList.BACKUP_APP_ADJ, ProcessList.HEAVY_WEIGHT_APP_ADJ,
             ProcessList.SERVICE_ADJ, ProcessList.HOME_APP_ADJ,
             ProcessList.PREVIOUS_APP_ADJ, ProcessList.SERVICE_B_ADJ, ProcessList.CACHED_APP_MIN_ADJ
@@ -11768,7 +11771,7 @@
     static final String[] DUMP_MEM_OOM_LABEL = new String[] {
             "Native",
             "System", "Persistent", "Persistent Service", "Foreground",
-            "Visible", "Perceptible",
+            "Visible", "Perceptible", "Perceptible Low",
             "Heavy Weight", "Backup",
             "A Services", "Home",
             "Previous", "B Services", "Cached"
@@ -11776,7 +11779,7 @@
     static final String[] DUMP_MEM_OOM_COMPACT_LABEL = new String[] {
             "native",
             "sys", "pers", "persvc", "fore",
-            "vis", "percept",
+            "vis", "percept", "perceptl",
             "heavy", "backup",
             "servicea", "home",
             "prev", "serviceb", "cached"
@@ -12871,7 +12874,7 @@
     private void appendBasicMemEntry(StringBuilder sb, int oomAdj, int procState, long pss,
             long memtrack, String name) {
         sb.append("  ");
-        sb.append(ProcessList.makeOomAdjString(oomAdj));
+        sb.append(ProcessList.makeOomAdjString(oomAdj, false));
         sb.append(' ');
         sb.append(ProcessList.makeProcStateString(procState));
         sb.append(' ');
@@ -14997,7 +15000,7 @@
                         oldQueue.performReceiveLocked(oldRecord.callerApp, oldRecord.resultTo,
                                 oldRecord.intent,
                                 Activity.RESULT_CANCELED, null, null,
-                                false, false, oldRecord.userId);
+                                false, false, oldRecord.userId, oldRecord);
                     } catch (RemoteException e) {
                         Slog.w(TAG, "Failure ["
                                 + queue.mQueueName + "] sending broadcast result of "
diff --git a/services/core/java/com/android/server/am/AppCompactor.java b/services/core/java/com/android/server/am/AppCompactor.java
index 1118014..c7e4fc7 100644
--- a/services/core/java/com/android/server/am/AppCompactor.java
+++ b/services/core/java/com/android/server/am/AppCompactor.java
@@ -55,6 +55,8 @@
     private static final int COMPACT_ACTION_FILE_FLAG = 1;
     private static final int COMPACT_ACTION_ANON_FLAG = 2;
     private static final int COMPACT_ACTION_FULL_FLAG = 3;
+    private static final int COMPACT_ACTION_NONE_FLAG = 4;
+    private static final String COMPACT_ACTION_NONE = "";
     private static final String COMPACT_ACTION_FILE = "file";
     private static final String COMPACT_ACTION_ANON = "anon";
     private static final String COMPACT_ACTION_FULL = "all";
@@ -170,6 +172,9 @@
             updateCompactionThrottles();
             updateStatsdSampleRate();
         }
+        Process.setThreadGroupAndCpuset(mCompactionThread.getThreadId(),
+                Process.THREAD_GROUP_SYSTEM);
+
     }
 
     /**
@@ -317,6 +322,8 @@
     @VisibleForTesting
     static String compactActionIntToString(int action) {
         switch(action) {
+            case COMPACT_ACTION_NONE_FLAG:
+                return COMPACT_ACTION_NONE;
             case COMPACT_ACTION_FILE_FLAG:
                 return COMPACT_ACTION_FILE;
             case COMPACT_ACTION_ANON_FLAG:
@@ -324,7 +331,7 @@
             case COMPACT_ACTION_FULL_FLAG:
                 return COMPACT_ACTION_FULL;
             default:
-                return COMPACT_ACTION_FILE;
+                return COMPACT_ACTION_NONE;
         }
     }
 
@@ -395,6 +402,10 @@
                         action = mCompactActionFull;
                     }
 
+                    if (action.equals(COMPACT_ACTION_NONE)) {
+                        return;
+                    }
+
                     try {
                         Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Compact "
                                 + ((pendingAction == COMPACT_PROCESS_SOME) ? "some" : "full")
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index a11ebfd..f0b137a 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -74,6 +74,9 @@
     static final int MAX_BROADCAST_SUMMARY_HISTORY
             = ActivityManager.isLowRamDeviceStatic() ? 25 : 300;
 
+    // For how long after a whitelisted receiver's start its process can start a background activity
+    private static final int RECEIVER_BG_ACTIVITY_START_TIMEOUT_MS = 10_000;
+
     final ActivityManagerService mService;
 
     /**
@@ -551,13 +554,23 @@
 
     void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
             Intent intent, int resultCode, String data, Bundle extras,
-            boolean ordered, boolean sticky, int sendingUser) throws RemoteException {
+            boolean ordered, boolean sticky, int sendingUser, BroadcastRecord br)
+            throws RemoteException {
         // Send the intent to the receiver asynchronously using one-way binder calls.
         if (app != null) {
             if (app.thread != null) {
                 // If we have an app thread, do the call through that so it is
                 // correctly ordered with other one-way calls.
                 try {
+                    if (br.allowBackgroundActivityStarts) {
+                        app.addAllowBackgroundActivityStartsToken(br);
+                        // schedule removal of the whitelisting token after the timeout
+                        mHandler.postDelayed(() -> {
+                            if (app != null) {
+                                app.removeAllowBackgroundActivityStartsToken(br);
+                            }
+                        }, RECEIVER_BG_ACTIVITY_START_TIMEOUT_MS);
+                    }
                     app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
                             data, extras, ordered, sticky, sendingUser, app.getReportedProcState());
                 // TODO: Uncomment this when (b/28322359) is fixed and we aren't getting
@@ -783,7 +796,7 @@
             } else {
                 performReceiveLocked(filter.receiverList.app, filter.receiverList.receiver,
                         new Intent(r.intent), r.resultCode, r.resultData,
-                        r.resultExtras, r.ordered, r.initialSticky, r.userId);
+                        r.resultExtras, r.ordered, r.initialSticky, r.userId, r);
             }
             if (ordered) {
                 r.state = BroadcastRecord.CALL_DONE_RECEIVE;
@@ -1082,7 +1095,7 @@
                             }
                             performReceiveLocked(r.callerApp, r.resultTo,
                                     new Intent(r.intent), r.resultCode,
-                                    r.resultData, r.resultExtras, false, false, r.userId);
+                                    r.resultData, r.resultExtras, false, false, r.userId, r);
                             // Set this to null so that the reference
                             // (local and remote) isn't kept in the mBroadcastHistory.
                             r.resultTo = null;
diff --git a/services/core/java/com/android/server/am/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java
index 360d296..0194624 100644
--- a/services/core/java/com/android/server/am/CoreSettingsObserver.java
+++ b/services/core/java/com/android/server/am/CoreSettingsObserver.java
@@ -56,6 +56,8 @@
 
         sGlobalSettingToTypeMap.put(Settings.Global.DEBUG_VIEW_ATTRIBUTES, int.class);
         sGlobalSettingToTypeMap.put(
+                Settings.Global.DEBUG_VIEW_ATTRIBUTES_APPLICATION_PACKAGE, String.class);
+        sGlobalSettingToTypeMap.put(
                 Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_ALL_ANGLE, String.class);
         sGlobalSettingToTypeMap.put(
                 Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_PKGS, String.class);
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 03c5c93..93a71e5 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -127,18 +127,8 @@
     private final ActivityManagerService mService;
     private final ProcessList mProcessList;
 
-    /**
-     * Used to lock {@link #updateOomAdjImpl} for state consistency. It also reduces frequency lock
-     * and unlock when getting and setting value to {@link ProcessRecord#mWindowProcessController}.
-     * Note it is declared as Object type so the locked-region-code-injection won't wrap the
-     * unnecessary priority booster.
-     */
-    private final Object mAtmGlobalLock;
-
-    OomAdjuster(ActivityManagerService service, ProcessList processList, ActiveUids activeUids,
-            Object atmGlobalLock) {
+    OomAdjuster(ActivityManagerService service, ProcessList processList, ActiveUids activeUids) {
         mService = service;
-        mAtmGlobalLock = atmGlobalLock;
         mProcessList = processList;
         mActiveUids = activeUids;
 
@@ -196,13 +186,6 @@
 
     @GuardedBy("mService")
     final void updateOomAdjLocked() {
-        synchronized (mAtmGlobalLock) {
-            updateOomAdjImpl();
-        }
-    }
-
-    @GuardedBy({"mService", "mAtmGlobalLock"})
-    private void updateOomAdjImpl() {
         Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "updateOomAdj");
         mService.mOomAdjProfiler.oomAdjStarted();
         final ProcessRecord TOP_APP = mService.getTopAppLocked();
@@ -1224,8 +1207,8 @@
                                     }
                                 } else if ((cr.flags & Context.BIND_ADJUST_BELOW_PERCEPTIBLE) != 0
                                         && clientAdj < ProcessList.PERCEPTIBLE_APP_ADJ
-                                        && adj > ProcessList.PERCEPTIBLE_APP_ADJ + 1) {
-                                    newAdj = ProcessList.PERCEPTIBLE_APP_ADJ + 1;
+                                        && adj > ProcessList.PERCEPTIBLE_LOW_APP_ADJ) {
+                                    newAdj = ProcessList.PERCEPTIBLE_LOW_APP_ADJ;
                                 } else if ((cr.flags&Context.BIND_NOT_VISIBLE) != 0
                                         && clientAdj < ProcessList.PERCEPTIBLE_APP_ADJ
                                         && adj > ProcessList.PERCEPTIBLE_APP_ADJ) {
@@ -1610,7 +1593,7 @@
         //      " adj=" + adj + " curAdj=" + app.curAdj + " maxAdj=" + app.maxAdj);
         if (adj > app.maxAdj) {
             adj = app.maxAdj;
-            if (app.maxAdj <= ProcessList.PERCEPTIBLE_APP_ADJ) {
+            if (app.maxAdj <= ProcessList.PERCEPTIBLE_LOW_APP_ADJ) {
                 schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
             }
         }
@@ -1709,8 +1692,9 @@
                         (app.curAdj == ProcessList.PREVIOUS_APP_ADJ ||
                                 app.curAdj == ProcessList.HOME_APP_ADJ)) {
                     mAppCompact.compactAppSome(app);
-                } else if (app.setAdj < ProcessList.CACHED_APP_MIN_ADJ &&
-                        app.curAdj >= ProcessList.CACHED_APP_MIN_ADJ) {
+                } else if (app.setAdj < ProcessList.CACHED_APP_MIN_ADJ
+                        && app.curAdj >= ProcessList.CACHED_APP_MIN_ADJ
+                        && app.curAdj <= ProcessList.CACHED_APP_MAX_ADJ) {
                     mAppCompact.compactAppFull(app);
                 }
             }
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index 0b27a8a..af56352 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -384,6 +384,9 @@
             final boolean allowTrampoline = uid != callingUid
                     && controller.mAtmInternal.isUidForeground(callingUid);
 
+            // note: we on purpose don't pass in the information about the PendingIntent's creator,
+            // like pid or ProcessRecord, to the ActivityTaskManagerInternal calls below, because
+            // it's not unusual for the creator's process to not be alive at this time
             switch (key.type) {
                 case ActivityManager.INTENT_SENDER_ACTIVITY:
                     try {
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index f90c0ca..f01305e 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -183,6 +183,10 @@
     // is not entirely fatal but is generally a bad idea.
     static final int BACKUP_APP_ADJ = 300;
 
+    // This is a process bound by the system that's more important than services but not so
+    // perceptible that it affects the user immediately if killed.
+    static final int PERCEPTIBLE_LOW_APP_ADJ = 250;
+
     // This is a process only hosting components that are perceptible to the
     // user, and we really want to avoid killing them, but they are not
     // immediately visible. An example is background music playback.
@@ -679,47 +683,68 @@
         return totalProcessLimit/2;
     }
 
-    private static String buildOomTag(String prefix, String space, int val, int base) {
+    private static String buildOomTag(String prefix, String compactPrefix, String space, int val,
+            int base, boolean compact) {
         final int diff = val - base;
         if (diff == 0) {
+            if (compact) {
+                return compactPrefix;
+            }
             if (space == null) return prefix;
             return prefix + space;
         }
         if (diff < 10) {
-            return prefix + "+ " + Integer.toString(diff);
+            return prefix + (compact ? "+" : "+ ") + Integer.toString(diff);
         }
         return prefix + "+" + Integer.toString(diff);
     }
 
-    public static String makeOomAdjString(int setAdj) {
+    public static String makeOomAdjString(int setAdj, boolean compact) {
         if (setAdj >= ProcessList.CACHED_APP_MIN_ADJ) {
-            return buildOomTag("cch", "   ", setAdj, ProcessList.CACHED_APP_MIN_ADJ);
+            return buildOomTag("cch", "cch", "   ", setAdj,
+                    ProcessList.CACHED_APP_MIN_ADJ, compact);
         } else if (setAdj >= ProcessList.SERVICE_B_ADJ) {
-            return buildOomTag("svcb  ", null, setAdj, ProcessList.SERVICE_B_ADJ);
+            return buildOomTag("svcb  ", "svcb", null, setAdj,
+                    ProcessList.SERVICE_B_ADJ, compact);
         } else if (setAdj >= ProcessList.PREVIOUS_APP_ADJ) {
-            return buildOomTag("prev  ", null, setAdj, ProcessList.PREVIOUS_APP_ADJ);
+            return buildOomTag("prev  ", "prev", null, setAdj,
+                    ProcessList.PREVIOUS_APP_ADJ, compact);
         } else if (setAdj >= ProcessList.HOME_APP_ADJ) {
-            return buildOomTag("home  ", null, setAdj, ProcessList.HOME_APP_ADJ);
+            return buildOomTag("home  ", "home", null, setAdj,
+                    ProcessList.HOME_APP_ADJ, compact);
         } else if (setAdj >= ProcessList.SERVICE_ADJ) {
-            return buildOomTag("svc   ", null, setAdj, ProcessList.SERVICE_ADJ);
+            return buildOomTag("svc   ", "svc", null, setAdj,
+                    ProcessList.SERVICE_ADJ, compact);
         } else if (setAdj >= ProcessList.HEAVY_WEIGHT_APP_ADJ) {
-            return buildOomTag("hvy   ", null, setAdj, ProcessList.HEAVY_WEIGHT_APP_ADJ);
+            return buildOomTag("hvy   ", "hvy", null, setAdj,
+                    ProcessList.HEAVY_WEIGHT_APP_ADJ, compact);
         } else if (setAdj >= ProcessList.BACKUP_APP_ADJ) {
-            return buildOomTag("bkup  ", null, setAdj, ProcessList.BACKUP_APP_ADJ);
+            return buildOomTag("bkup  ", "bkup", null, setAdj,
+                    ProcessList.BACKUP_APP_ADJ, compact);
+        } else if (setAdj >= ProcessList.PERCEPTIBLE_LOW_APP_ADJ) {
+            return buildOomTag("prcl  ", "prcl", null, setAdj,
+                    ProcessList.PERCEPTIBLE_LOW_APP_ADJ, compact);
         } else if (setAdj >= ProcessList.PERCEPTIBLE_APP_ADJ) {
-            return buildOomTag("prcp  ", null, setAdj, ProcessList.PERCEPTIBLE_APP_ADJ);
+            return buildOomTag("prcp  ", "prcp", null, setAdj,
+                    ProcessList.PERCEPTIBLE_APP_ADJ, compact);
         } else if (setAdj >= ProcessList.VISIBLE_APP_ADJ) {
-            return buildOomTag("vis", "   ", setAdj, ProcessList.VISIBLE_APP_ADJ);
+            return buildOomTag("vis", "vis", "   ", setAdj,
+                    ProcessList.VISIBLE_APP_ADJ, compact);
         } else if (setAdj >= ProcessList.FOREGROUND_APP_ADJ) {
-            return buildOomTag("fore  ", null, setAdj, ProcessList.FOREGROUND_APP_ADJ);
+            return buildOomTag("fore  ", "fore", null, setAdj,
+                    ProcessList.FOREGROUND_APP_ADJ, compact);
         } else if (setAdj >= ProcessList.PERSISTENT_SERVICE_ADJ) {
-            return buildOomTag("psvc  ", null, setAdj, ProcessList.PERSISTENT_SERVICE_ADJ);
+            return buildOomTag("psvc  ", "psvc", null, setAdj,
+                    ProcessList.PERSISTENT_SERVICE_ADJ, compact);
         } else if (setAdj >= ProcessList.PERSISTENT_PROC_ADJ) {
-            return buildOomTag("pers  ", null, setAdj, ProcessList.PERSISTENT_PROC_ADJ);
+            return buildOomTag("pers  ", "pers", null, setAdj,
+                    ProcessList.PERSISTENT_PROC_ADJ, compact);
         } else if (setAdj >= ProcessList.SYSTEM_ADJ) {
-            return buildOomTag("sys   ", null, setAdj, ProcessList.SYSTEM_ADJ);
+            return buildOomTag("sys   ", "sys", null, setAdj,
+                    ProcessList.SYSTEM_ADJ, compact);
         } else if (setAdj >= ProcessList.NATIVE_ADJ) {
-            return buildOomTag("ntv  ", null, setAdj, ProcessList.NATIVE_ADJ);
+            return buildOomTag("ntv  ", "ntv", null, setAdj,
+                    ProcessList.NATIVE_ADJ, compact);
         } else {
             return Integer.toString(setAdj);
         }
@@ -1722,8 +1747,11 @@
         try {
             final String[] packageNames = mService.mContext.getPackageManager()
                     .getPackagesForUid(uid);
-            final String[] visibleVolIds = LocalServices.getService(StorageManagerInternal.class)
+            final StorageManagerInternal storageManagerInternal =
+                    LocalServices.getService(StorageManagerInternal.class);
+            final String[] visibleVolIds = storageManagerInternal
                     .getVisibleVolumesForUser(UserHandle.getUserId(uid));
+            final String sandboxId = storageManagerInternal.getSandboxId(app.info.packageName);
             Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
                     app.processName);
             checkSlow(startTime, "startProcess: asking zygote to start proc");
@@ -1733,7 +1761,7 @@
                         app.processName, uid, uid, gids, runtimeFlags, mountExternal,
                         app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                         app.info.dataDir, null, app.info.packageName,
-                        packageNames, visibleVolIds,
+                        packageNames, visibleVolIds, sandboxId,
                         new String[] {PROC_START_SEQ_IDENT + app.startSeq});
             } else if (hostingType.equals("app_zygote")) {
                 final AppZygote appZygote = createAppZygoteForProcessIfNeeded(app);
@@ -1742,14 +1770,14 @@
                         app.processName, uid, uid, gids, runtimeFlags, mountExternal,
                         app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                         app.info.dataDir, null, app.info.packageName,
-                        packageNames, visibleVolIds, /*useBlastulaPool=*/ false,
+                        packageNames, visibleVolIds, sandboxId, /*useBlastulaPool=*/ false,
                         new String[] {PROC_START_SEQ_IDENT + app.startSeq});
             } else {
                 startResult = Process.start(entryPoint,
                         app.processName, uid, uid, gids, runtimeFlags, mountExternal,
                         app.info.targetSdkVersion, seInfo, requiredAbi, instructionSet,
                         app.info.dataDir, invokeWith, app.info.packageName,
-                        packageNames, visibleVolIds,
+                        packageNames, visibleVolIds, sandboxId,
                         new String[] {PROC_START_SEQ_IDENT + app.startSeq});
             }
             checkSlow(startTime, "startProcess: returned from zygote!");
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 5dccaf1..fcc857b 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -713,6 +713,8 @@
                 adj = ProcessList.VISIBLE_APP_ADJ;
             } else if (adj < ProcessList.PERCEPTIBLE_APP_ADJ) {
                 adj = ProcessList.PERCEPTIBLE_APP_ADJ;
+            } else if (adj < ProcessList.PERCEPTIBLE_LOW_APP_ADJ) {
+                adj = ProcessList.PERCEPTIBLE_LOW_APP_ADJ;
             } else if (adj < ProcessList.CACHED_APP_MIN_ADJ) {
                 adj = ProcessList.CACHED_APP_MIN_ADJ;
             } else if (adj < ProcessList.CACHED_APP_MAX_ADJ) {
diff --git a/services/core/java/com/android/server/appbinding/AppBindingService.java b/services/core/java/com/android/server/appbinding/AppBindingService.java
index 3131255..0b6a432 100644
--- a/services/core/java/com/android/server/appbinding/AppBindingService.java
+++ b/services/core/java/com/android/server/appbinding/AppBindingService.java
@@ -47,7 +47,7 @@
 import com.android.server.SystemService;
 import com.android.server.am.PersistentConnection;
 import com.android.server.appbinding.finders.AppServiceFinder;
-import com.android.server.appbinding.finders.SmsAppServiceFinder;
+import com.android.server.appbinding.finders.CarrierMessagingClientServiceFinder;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
@@ -147,7 +147,7 @@
         mIPackageManager = injector.getIPackageManager();
 
         mHandler = BackgroundThread.getHandler();
-        mApps.add(new SmsAppServiceFinder(context, this::onAppChanged, mHandler));
+        mApps.add(new CarrierMessagingClientServiceFinder(context, this::onAppChanged, mHandler));
 
         // Initialize with the default value to make it non-null.
         mConstants = AppBindingConstants.initializeFromString("");
diff --git a/services/core/java/com/android/server/appbinding/finders/SmsAppServiceFinder.java b/services/core/java/com/android/server/appbinding/finders/CarrierMessagingClientServiceFinder.java
similarity index 79%
rename from services/core/java/com/android/server/appbinding/finders/SmsAppServiceFinder.java
rename to services/core/java/com/android/server/appbinding/finders/CarrierMessagingClientServiceFinder.java
index fcc28f8..4c5f1a1 100644
--- a/services/core/java/com/android/server/appbinding/finders/SmsAppServiceFinder.java
+++ b/services/core/java/com/android/server/appbinding/finders/CarrierMessagingClientServiceFinder.java
@@ -19,8 +19,6 @@
 import static android.provider.Telephony.Sms.Intents.ACTION_DEFAULT_SMS_PACKAGE_CHANGED_INTERNAL;
 
 import android.Manifest.permission;
-import android.app.ISmsAppService;
-import android.app.SmsAppService;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
@@ -30,6 +28,8 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.UserHandle;
+import android.service.carrier.CarrierMessagingClientService;
+import android.service.carrier.ICarrierMessagingClientService;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.Slog;
@@ -41,10 +41,11 @@
 import java.util.function.BiConsumer;
 
 /**
- * Find the SmsAppService service within the default SMS app.
+ * Find the CarrierMessagingClientService service within the default SMS app.
  */
-public class SmsAppServiceFinder extends AppServiceFinder<SmsAppService, ISmsAppService> {
-    public SmsAppServiceFinder(Context context,
+public class CarrierMessagingClientServiceFinder
+        extends AppServiceFinder<CarrierMessagingClientService, ICarrierMessagingClientService> {
+    public CarrierMessagingClientServiceFinder(Context context,
             BiConsumer<AppServiceFinder, Integer> listener,
             Handler callbackHandler) {
         super(context, listener, callbackHandler);
@@ -62,23 +63,23 @@
     }
 
     @Override
-    protected Class<SmsAppService> getServiceClass() {
-        return SmsAppService.class;
+    protected Class<CarrierMessagingClientService> getServiceClass() {
+        return CarrierMessagingClientService.class;
     }
 
     @Override
-    public ISmsAppService asInterface(IBinder obj) {
-        return ISmsAppService.Stub.asInterface(obj);
+    public ICarrierMessagingClientService asInterface(IBinder obj) {
+        return ICarrierMessagingClientService.Stub.asInterface(obj);
     }
 
     @Override
     protected String getServiceAction() {
-        return TelephonyManager.ACTION_SMS_APP_SERVICE;
+        return TelephonyManager.ACTION_CARRIER_MESSAGING_CLIENT_SERVICE;
     }
 
     @Override
     protected String getServicePermission() {
-        return permission.BIND_SMS_APP_SERVICE;
+        return permission.BIND_CARRIER_MESSAGING_CLIENT_SERVICE;
     }
 
     @Override
@@ -121,7 +122,7 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             if (ACTION_DEFAULT_SMS_PACKAGE_CHANGED_INTERNAL.equals(intent.getAction())) {
-                mListener.accept(SmsAppServiceFinder.this, getSendingUserId());
+                mListener.accept(CarrierMessagingClientServiceFinder.this, getSendingUserId());
             }
         }
     };
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index a3bae52..6df60d6 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -21,6 +21,8 @@
 import android.annotation.NonNull;
 import android.bluetooth.BluetoothA2dp;
 import android.bluetooth.BluetoothDevice;
+import android.bluetooth.BluetoothHeadset;
+import android.bluetooth.BluetoothHearingAid;
 import android.bluetooth.BluetoothProfile;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -381,11 +383,11 @@
 
     //---------------------------------------------------------------------
     // Message handling on behalf of helper classes
-    /*package*/ void broadcastScoConnectionState(int state) {
+    /*package*/ void postBroadcastScoConnectionState(int state) {
         sendIMsgNoDelay(MSG_I_BROADCAST_BT_CONNECTION_STATE, SENDMSG_QUEUE, state);
     }
 
-    /*package*/ void broadcastBecomingNoisy() {
+    /*package*/ void postBroadcastBecomingNoisy() {
         sendMsgNoDelay(MSG_BROADCAST_AUDIO_BECOMING_NOISY, SENDMSG_REPLACE);
     }
 
@@ -415,6 +417,39 @@
                 delay);
     }
 
+    /*package*/ void postDisconnectA2dp() {
+        sendMsgNoDelay(MSG_DISCONNECT_A2DP, SENDMSG_QUEUE);
+    }
+
+    /*package*/ void postDisconnectA2dpSink() {
+        sendMsgNoDelay(MSG_DISCONNECT_A2DP_SINK, SENDMSG_QUEUE);
+    }
+
+    /*package*/ void postDisconnectHearingAid() {
+        sendMsgNoDelay(MSG_DISCONNECT_BT_HEARING_AID, SENDMSG_QUEUE);
+    }
+
+    /*package*/ void postDisconnectHeadset() {
+        sendMsgNoDelay(MSG_DISCONNECT_BT_HEADSET, SENDMSG_QUEUE);
+    }
+
+    /*package*/ void postBtA2dpProfileConnected(BluetoothA2dp a2dpProfile) {
+        sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP, SENDMSG_QUEUE, a2dpProfile);
+    }
+
+    /*package*/ void postBtA2dpSinkProfileConnected(BluetoothProfile profile) {
+        sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP_SINK, SENDMSG_QUEUE, profile);
+    }
+
+    /*package*/ void postBtHeasetProfileConnected(BluetoothHeadset headsetProfile) {
+        sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEADSET, SENDMSG_QUEUE, headsetProfile);
+    }
+
+    /*package*/ void postBtHearingAidProfileConnected(BluetoothHearingAid hearingAidProfile) {
+        sendLMsgNoDelay(MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEARING_AID, SENDMSG_QUEUE,
+                hearingAidProfile);
+    }
+
     //---------------------------------------------------------------------
     // Method forwarding between the helper classes (BtHelper, AudioDeviceInventory)
     // only call from a "handle"* method or "on"* method
@@ -444,33 +479,14 @@
         }
     }
 
-    /*package*/ void handleDisconnectA2dp() {
-        synchronized (mDeviceStateLock) {
-            mDeviceInventory.disconnectA2dp();
-        }
-    }
-    /*package*/ void handleDisconnectA2dpSink() {
-        synchronized (mDeviceStateLock) {
-            mDeviceInventory.disconnectA2dpSink();
-        }
-    }
-
-    /*package*/ void handleDisconnectHearingAid() {
-        synchronized (mDeviceStateLock) {
-            mDeviceInventory.disconnectHearingAid();
-        }
-    }
-
+    @GuardedBy("mDeviceStateLock")
     /*package*/ void handleSetA2dpSinkConnectionState(@BluetoothProfile.BtProfileState int state,
                 @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo) {
         final int intState = (state == BluetoothA2dp.STATE_CONNECTED)
                 ? CONNECTION_STATE_CONNECTED : CONNECTION_STATE_DISCONNECTED;
-        final int delay;
-        synchronized (mDeviceStateLock) {
-            delay = mDeviceInventory.checkSendBecomingNoisyIntent(
+        final int delay = mDeviceInventory.checkSendBecomingNoisyIntent(
                     AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, intState,
                     AudioSystem.DEVICE_NONE);
-        }
         final String addr = btDeviceInfo == null ? "null" : btDeviceInfo.getBtDevice().getAddress();
 
         if (AudioService.DEBUG_DEVICES) {
@@ -482,7 +498,7 @@
                 state, btDeviceInfo, delay);
     }
 
-    /*package*/ void handleSetA2dpSourceConnectionState(@BluetoothProfile.BtProfileState int state,
+    /*package*/ void postSetA2dpSourceConnectionState(@BluetoothProfile.BtProfileState int state,
             @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo) {
         final int intState = (state == BluetoothA2dp.STATE_CONNECTED) ? 1 : 0;
         sendILMsgNoDelay(MSG_IL_SET_A2DP_SOURCE_CONNECTION_STATE, SENDMSG_QUEUE, state,
@@ -710,6 +726,46 @@
                                 (BtHelper.BluetoothA2dpDeviceInfo) msg.obj);
                     }
                     break;
+                case MSG_DISCONNECT_A2DP:
+                    synchronized (mDeviceStateLock) {
+                        mDeviceInventory.disconnectA2dp();
+                    }
+                    break;
+                case MSG_DISCONNECT_A2DP_SINK:
+                    synchronized (mDeviceStateLock) {
+                        mDeviceInventory.disconnectA2dpSink();
+                    }
+                    break;
+                case MSG_DISCONNECT_BT_HEARING_AID:
+                    synchronized (mDeviceStateLock) {
+                        mDeviceInventory.disconnectHearingAid();
+                    }
+                    break;
+                case MSG_DISCONNECT_BT_HEADSET:
+                    synchronized (mDeviceStateLock) {
+                        mBtHelper.disconnectHeadset();
+                    }
+                    break;
+                case MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP:
+                    synchronized (mDeviceStateLock) {
+                        mBtHelper.onA2dpProfileConnected((BluetoothA2dp) msg.obj);
+                    }
+                    break;
+                case MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP_SINK:
+                    synchronized (mDeviceStateLock) {
+                        mBtHelper.onA2dpSinkProfileConnected((BluetoothProfile) msg.obj);
+                    }
+                    break;
+                case MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEARING_AID:
+                    synchronized (mDeviceStateLock) {
+                        mBtHelper.onHearingAidProfileConnected((BluetoothHearingAid) msg.obj);
+                    }
+                    break;
+                case MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEADSET:
+                    synchronized (mDeviceStateLock) {
+                        mBtHelper.onHeadsetProfileConnected((BluetoothHeadset) msg.obj);
+                    }
+                    break;
                 default:
                     Log.wtf(TAG, "Invalid message " + msg.what);
             }
@@ -745,6 +801,14 @@
     private static final int MSG_I_DISCONNECT_BT_SCO = 16;
     private static final int MSG_TOGGLE_HDMI = 17;
     private static final int MSG_L_A2DP_ACTIVE_DEVICE_CHANGE = 18;
+    private static final int MSG_DISCONNECT_A2DP = 19;
+    private static final int MSG_DISCONNECT_A2DP_SINK = 20;
+    private static final int MSG_DISCONNECT_BT_HEARING_AID = 21;
+    private static final int MSG_DISCONNECT_BT_HEADSET = 22;
+    private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP = 23;
+    private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_A2DP_SINK = 24;
+    private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEARING_AID = 25;
+    private static final int MSG_L_BT_SERVICE_CONNECTED_PROFILE_HEADSET = 26;
 
 
     private static boolean isMessageHandledUnderWakelock(int msgId) {
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index 11fdc8f..37f0496 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -859,7 +859,7 @@
         // also checks whether media routing if affected by a dynamic policy
         if (((device == musicDevice) || mDeviceBroker.isInCommunication())
                 && (device == devices) && !mDeviceBroker.hasMediaDynamicPolicy()) {
-            mDeviceBroker.broadcastBecomingNoisy();
+            mDeviceBroker.postBroadcastBecomingNoisy();
             delay = 1000;
         }
 
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index de63d0e..a6643d4 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -5120,7 +5120,7 @@
                 if (mUserSwitchedReceived) {
                     // attempt to stop music playback for background user except on first user
                     // switch (i.e. first boot)
-                    mDeviceBroker.broadcastBecomingNoisy();
+                    mDeviceBroker.postBroadcastBecomingNoisy();
                 }
                 mUserSwitchedReceived = true;
                 // the current audio focus owner is no longer valid
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index b63af8a..58c1882 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -374,10 +374,10 @@
     }
 
     /*package*/ synchronized void disconnectAllBluetoothProfiles() {
-        mDeviceBroker.handleDisconnectA2dp();
-        mDeviceBroker.handleDisconnectA2dpSink();
-        disconnectHeadset();
-        mDeviceBroker.handleDisconnectHearingAid();
+        mDeviceBroker.postDisconnectA2dp();
+        mDeviceBroker.postDisconnectA2dpSink();
+        mDeviceBroker.postDisconnectHeadset();
+        mDeviceBroker.postDisconnectHearingAid();
     }
 
     /*package*/ synchronized void resetBluetoothSco() {
@@ -388,9 +388,92 @@
         mDeviceBroker.setBluetoothScoOn(false, "resetBluetoothSco");
     }
 
+    /*package*/ synchronized void disconnectHeadset() {
+        setBtScoActiveDevice(null);
+        mBluetoothHeadset = null;
+    }
+
+    /*package*/ synchronized void onA2dpProfileConnected(BluetoothA2dp a2dp) {
+        mA2dp = a2dp;
+        final List<BluetoothDevice> deviceList = mA2dp.getConnectedDevices();
+        if (deviceList.isEmpty()) {
+            return;
+        }
+        final BluetoothDevice btDevice = deviceList.get(0);
+        final @BluetoothProfile.BtProfileState int state = mA2dp.getConnectionState(btDevice);
+        mDeviceBroker.handleSetA2dpSinkConnectionState(
+                state, new BluetoothA2dpDeviceInfo(btDevice));
+    }
+
+    /*package*/ synchronized void onA2dpSinkProfileConnected(BluetoothProfile profile) {
+        final List<BluetoothDevice> deviceList = profile.getConnectedDevices();
+        if (deviceList.isEmpty()) {
+            return;
+        }
+        final BluetoothDevice btDevice = deviceList.get(0);
+        final @BluetoothProfile.BtProfileState int state =
+                profile.getConnectionState(btDevice);
+        mDeviceBroker.postSetA2dpSourceConnectionState(
+                state, new BluetoothA2dpDeviceInfo(btDevice));
+    }
+
+    /*package*/ synchronized void onHearingAidProfileConnected(BluetoothHearingAid hearingAid) {
+        mHearingAid = hearingAid;
+        final List<BluetoothDevice> deviceList = mHearingAid.getConnectedDevices();
+        if (deviceList.isEmpty()) {
+            return;
+        }
+        final BluetoothDevice btDevice = deviceList.get(0);
+        final @BluetoothProfile.BtProfileState int state =
+                mHearingAid.getConnectionState(btDevice);
+        mDeviceBroker.setBluetoothHearingAidDeviceConnectionState(
+                btDevice, state,
+                /*suppressNoisyIntent*/ false,
+                /*musicDevice*/ android.media.AudioSystem.DEVICE_NONE,
+                /*eventSource*/ "mBluetoothProfileServiceListener");
+    }
+
+    /*package*/ synchronized void onHeadsetProfileConnected(BluetoothHeadset headset) {
+        // Discard timeout message
+        mDeviceBroker.handleCancelFailureToConnectToBtHeadsetService();
+        mBluetoothHeadset = headset;
+        setBtScoActiveDevice(mBluetoothHeadset.getActiveDevice());
+        // Refresh SCO audio state
+        checkScoAudioState();
+        if (mScoAudioState != SCO_STATE_ACTIVATE_REQ
+                && mScoAudioState != SCO_STATE_DEACTIVATE_REQ) {
+            return;
+        }
+        boolean status = false;
+        if (mBluetoothHeadsetDevice != null) {
+            switch (mScoAudioState) {
+                case SCO_STATE_ACTIVATE_REQ:
+                    status = connectBluetoothScoAudioHelper(
+                            mBluetoothHeadset,
+                            mBluetoothHeadsetDevice, mScoAudioMode);
+                    if (status) {
+                        mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
+                    }
+                    break;
+                case SCO_STATE_DEACTIVATE_REQ:
+                    status = disconnectBluetoothScoAudioHelper(
+                            mBluetoothHeadset,
+                            mBluetoothHeadsetDevice, mScoAudioMode);
+                    if (status) {
+                        mScoAudioState = SCO_STATE_DEACTIVATING;
+                    }
+                    break;
+            }
+        }
+        if (!status) {
+            mScoAudioState = SCO_STATE_INACTIVE;
+            broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
+        }
+    }
+
     //----------------------------------------------------------------------
     private void broadcastScoConnectionState(int state) {
-        mDeviceBroker.broadcastScoConnectionState(state);
+        mDeviceBroker.postBroadcastScoConnectionState(state);
     }
 
     private boolean handleBtScoActiveDeviceChange(BluetoothDevice btDevice, boolean isActive) {
@@ -457,99 +540,36 @@
         }
     }
 
+    // NOTE this listener is NOT called from AudioDeviceBroker event thread, only call async
+    //      methods inside listener.
     private BluetoothProfile.ServiceListener mBluetoothProfileServiceListener =
             new BluetoothProfile.ServiceListener() {
                 public void onServiceConnected(int profile, BluetoothProfile proxy) {
-                    final BluetoothDevice btDevice;
-                    List<BluetoothDevice> deviceList;
                     switch(profile) {
                         case BluetoothProfile.A2DP:
-                            synchronized (BtHelper.this) {
-                                mA2dp = (BluetoothA2dp) proxy;
-                                deviceList = mA2dp.getConnectedDevices();
-                                if (deviceList.size() > 0) {
-                                    btDevice = deviceList.get(0);
-                                    if (btDevice == null) {
-                                        Log.e(TAG, "Invalid null device in BT profile listener");
-                                        return;
-                                    }
-                                    final @BluetoothProfile.BtProfileState int state =
-                                            mA2dp.getConnectionState(btDevice);
-                                    mDeviceBroker.handleSetA2dpSinkConnectionState(
-                                            state, new BluetoothA2dpDeviceInfo(btDevice));
-                                }
-                            }
+                            AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(
+                                    "BT profile service: connecting A2DP profile"));
+                            mDeviceBroker.postBtA2dpProfileConnected((BluetoothA2dp) proxy);
                             break;
 
                         case BluetoothProfile.A2DP_SINK:
-                            deviceList = proxy.getConnectedDevices();
-                            if (deviceList.size() > 0) {
-                                btDevice = deviceList.get(0);
-                                final @BluetoothProfile.BtProfileState int state =
-                                        proxy.getConnectionState(btDevice);
-                                mDeviceBroker.handleSetA2dpSourceConnectionState(
-                                        state, new BluetoothA2dpDeviceInfo(btDevice));
-                            }
+                            AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(
+                                    "BT profile service: connecting A2DP_SINK profile"));
+                            mDeviceBroker.postBtA2dpSinkProfileConnected(proxy);
                             break;
 
                         case BluetoothProfile.HEADSET:
-                            synchronized (BtHelper.this) {
-                                // Discard timeout message
-                                mDeviceBroker.handleCancelFailureToConnectToBtHeadsetService();
-                                mBluetoothHeadset = (BluetoothHeadset) proxy;
-                                setBtScoActiveDevice(mBluetoothHeadset.getActiveDevice());
-                                // Refresh SCO audio state
-                                checkScoAudioState();
-                                // Continue pending action if any
-                                if (mScoAudioState == SCO_STATE_ACTIVATE_REQ
-                                        || mScoAudioState == SCO_STATE_DEACTIVATE_REQ) {
-                                    boolean status = false;
-                                    if (mBluetoothHeadsetDevice != null) {
-                                        switch (mScoAudioState) {
-                                            case SCO_STATE_ACTIVATE_REQ:
-                                                status = connectBluetoothScoAudioHelper(
-                                                        mBluetoothHeadset,
-                                                        mBluetoothHeadsetDevice, mScoAudioMode);
-                                                if (status) {
-                                                    mScoAudioState = SCO_STATE_ACTIVE_INTERNAL;
-                                                }
-                                                break;
-                                            case SCO_STATE_DEACTIVATE_REQ:
-                                                status = disconnectBluetoothScoAudioHelper(
-                                                        mBluetoothHeadset,
-                                                        mBluetoothHeadsetDevice, mScoAudioMode);
-                                                if (status) {
-                                                    mScoAudioState = SCO_STATE_DEACTIVATING;
-                                                }
-                                                break;
-                                        }
-                                    }
-                                    if (!status) {
-                                        mScoAudioState = SCO_STATE_INACTIVE;
-                                        broadcastScoConnectionState(
-                                                AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
-                                    }
-                                }
-                            }
+                            AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(
+                                    "BT profile service: connecting HEADSET profile"));
+                            mDeviceBroker.postBtHeasetProfileConnected((BluetoothHeadset) proxy);
                             break;
 
                         case BluetoothProfile.HEARING_AID:
-                            synchronized (BtHelper.this) {
-                                mHearingAid = (BluetoothHearingAid) proxy;
-                                deviceList = mHearingAid.getConnectedDevices();
-                                if (deviceList.size() > 0) {
-                                    btDevice = deviceList.get(0);
-                                    final @BluetoothProfile.BtProfileState int state =
-                                            mHearingAid.getConnectionState(btDevice);
-                                    mDeviceBroker.setBluetoothHearingAidDeviceConnectionState(
-                                            btDevice, state,
-                                            /*suppressNoisyIntent*/ false,
-                                            /*musicDevice*/ android.media.AudioSystem.DEVICE_NONE,
-                                            /*eventSource*/ "mBluetoothProfileServiceListener");
-                                }
-                            }
+                            AudioService.sDeviceLogger.log(new AudioEventLogger.StringEvent(
+                                    "BT profile service: connecting HEARING_AID profile"));
+                            mDeviceBroker.postBtHearingAidProfileConnected(
+                                    (BluetoothHearingAid) proxy);
                             break;
-
                         default:
                             break;
                     }
@@ -558,19 +578,19 @@
 
                     switch (profile) {
                         case BluetoothProfile.A2DP:
-                            mDeviceBroker.handleDisconnectA2dp();
+                            mDeviceBroker.postDisconnectA2dp();
                             break;
 
                         case BluetoothProfile.A2DP_SINK:
-                            mDeviceBroker.handleDisconnectA2dpSink();
+                            mDeviceBroker.postDisconnectA2dpSink();
                             break;
 
                         case BluetoothProfile.HEADSET:
-                            disconnectHeadset();
+                            mDeviceBroker.postDisconnectHeadset();
                             break;
 
                         case BluetoothProfile.HEARING_AID:
-                            mDeviceBroker.handleDisconnectHearingAid();
+                            mDeviceBroker.postDisconnectHearingAid();
                             break;
 
                         default:
@@ -579,11 +599,6 @@
                 }
             };
 
-    private void disconnectHeadset() {
-        setBtScoActiveDevice(null);
-        mBluetoothHeadset = null;
-    }
-
     //----------------------------------------------------------------------
     private class ScoClient implements IBinder.DeathRecipient {
         private IBinder mCb; // To be notified of client's death
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index b50b800..bca84f7 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -391,10 +391,11 @@
         private final Random mRandom = new Random();
 
         // TODO(b/123378871): Remove when moved.
-        // When BiometricPrompt#setEnableFallback is set to true, we need to store the client (app)
-        // receiver. BiometricService internally launches CDCA which invokes BiometricService to
-        // start authentication (normal path). When auth is success/rejected, CDCA will use an aidl
-        // method to poke BiometricService - the result will then be forwarded to this receiver.
+        // When BiometricPrompt#setAllowDeviceCredentials is set to true, we need to store the
+        // client (app) receiver. BiometricService internally launches CDCA which invokes
+        // BiometricService to start authentication (normal path). When auth is success/rejected,
+        // CDCA will use an aidl method to poke BiometricService - the result will then be forwarded
+        // to this receiver.
         private IBiometricServiceReceiver mConfirmDeviceCredentialReceiver;
 
         // The current authentication session, null if idle/done. We need to track both the current
@@ -803,11 +804,21 @@
             // we can't get activity results. Store the receiver somewhere so we can forward the
             // result back to the client.
             // TODO(b/123378871): Remove when moved.
-            if (bundle.getBoolean(BiometricPrompt.KEY_ENABLE_FALLBACK)) {
+            if (bundle.getBoolean(BiometricPrompt.KEY_ALLOW_DEVICE_CREDENTIAL)) {
                 mHandler.post(() -> {
-                    mConfirmDeviceCredentialReceiver = receiver;
                     final KeyguardManager kgm = getContext().getSystemService(
                             KeyguardManager.class);
+                    if (!kgm.isDeviceSecure()) {
+                        try {
+                            receiver.onError(BiometricConstants.BIOMETRIC_ERROR_NO_DEVICE_CREDENTIAL,
+                                    getContext().getString(
+                                            R.string.biometric_error_device_not_secured));
+                        } catch (RemoteException e) {
+                            Slog.e(TAG, "Remote exception", e);
+                        }
+                        return;
+                    }
+                    mConfirmDeviceCredentialReceiver = receiver;
                     // Use this so we don't need to duplicate logic..
                     final Intent intent = kgm.createConfirmDeviceCredentialIntent(null /* title */,
                             null /* description */);
diff --git a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
index b65535a..9e0f2fc 100644
--- a/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
+++ b/services/core/java/com/android/server/biometrics/BiometricServiceBase.java
@@ -624,7 +624,8 @@
         handleError(getHalDeviceId(), BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,
                 0 /*vendorCode */);
 
-        StatsLog.write(StatsLog.BIOMETRIC_HAL_DEATH_REPORTED, statsModality());
+        StatsLog.write(StatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED, statsModality(),
+                BiometricsProtoEnums.ISSUE_HAL_DEATH);
     }
 
     protected ClientMonitor getCurrentClient() {
diff --git a/services/core/java/com/android/server/biometrics/LoggableMonitor.java b/services/core/java/com/android/server/biometrics/LoggableMonitor.java
index 91c924d..3b75b95 100644
--- a/services/core/java/com/android/server/biometrics/LoggableMonitor.java
+++ b/services/core/java/com/android/server/biometrics/LoggableMonitor.java
@@ -28,7 +28,7 @@
 public abstract class LoggableMonitor {
 
     public static final String TAG = "BiometricStats";
-    public static final boolean DEBUG = true;
+    public static final boolean DEBUG = false;
 
     private long mFirstAcquireTimeMs;
 
@@ -137,6 +137,8 @@
                     + ", RequireConfirmation: " + requireConfirmation
                     + ", State: " + authState
                     + ", Latency: " + latency);
+        } else {
+            Slog.v(TAG, "Authentication latency: " + latency);
         }
 
         StatsLog.write(StatsLog.BIOMETRIC_AUTHENTICATED,
diff --git a/services/core/java/com/android/server/biometrics/face/FaceService.java b/services/core/java/com/android/server/biometrics/face/FaceService.java
index 90342ee..8995068 100644
--- a/services/core/java/com/android/server/biometrics/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/face/FaceService.java
@@ -168,6 +168,7 @@
                 String opPackageName, int cookie, int callingUid, int callingPid,
                 int callingUserId) {
             checkPermission(USE_BIOMETRIC_INTERNAL);
+            updateActiveGroup(groupId, opPackageName);
             final boolean restricted = true; // BiometricPrompt is always restricted
             final AuthenticationClientImpl client = new FaceAuthClient(getContext(),
                     mDaemonWrapper, mHalDeviceId, token,
@@ -704,6 +705,8 @@
     public void serviceDied(long cookie) {
         super.serviceDied(cookie);
         mDaemon = null;
+
+        mCurrentUserId = UserHandle.USER_NULL; // Force updateActiveGroup() to re-evaluate
     }
 
     @Override
diff --git a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
index 62947c7..d8544e3 100644
--- a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
@@ -49,6 +49,7 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.util.Slog;
+import android.util.StatsLog;
 import android.util.proto.ProtoOutputStream;
 
 import com.android.internal.annotations.GuardedBy;
@@ -192,6 +193,7 @@
                 IBiometricServiceReceiverInternal wrapperReceiver, String opPackageName,
                 int cookie, int callingUid, int callingPid, int callingUserId) {
             checkPermission(MANAGE_BIOMETRIC);
+            updateActiveGroup(groupId, opPackageName);
             final boolean restricted = true; // BiometricPrompt is always restricted
             final AuthenticationClientImpl client = new FingerprintAuthClient(getContext(),
                     mDaemonWrapper, mHalDeviceId, token,
@@ -553,6 +555,8 @@
                         + " " + f.getDeviceId());
                 FingerprintUtils.getInstance().removeBiometricForUser(getContext(),
                         getTargetUserId(), f.getBiometricId());
+                StatsLog.write(StatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED,
+                        BiometricsProtoEnums.ISSUE_UNKNOWN_TEMPLATE_ENROLLED_FRAMEWORK);
             }
             mEnrolledList.clear();
         }
@@ -1002,6 +1006,8 @@
                     mHalDeviceId, mToken, new ServiceListenerImpl(null), uf.f.getBiometricId(),
                     uf.f.getGroupId(), uf.userId, restricted, getContext().getOpPackageName());
             removeInternal(client);
+            StatsLog.write(StatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED, statsModality(),
+                    BiometricsProtoEnums.ISSUE_UNKNOWN_TEMPLATE_ENROLLED_HAL);
         } else {
             clearEnumerateState();
         }
diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
index d872e4d..6cff57d 100644
--- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
+++ b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
@@ -17,6 +17,8 @@
 package com.android.server.connectivity;
 
 import static android.net.NattSocketKeepalive.NATT_PORT;
+import static android.net.NetworkAgent.CMD_ADD_KEEPALIVE_PACKET_FILTER;
+import static android.net.NetworkAgent.CMD_REMOVE_KEEPALIVE_PACKET_FILTER;
 import static android.net.NetworkAgent.CMD_START_SOCKET_KEEPALIVE;
 import static android.net.NetworkAgent.CMD_STOP_SOCKET_KEEPALIVE;
 import static android.net.NetworkAgent.EVENT_SOCKET_KEEPALIVE;
@@ -37,6 +39,9 @@
 import android.net.NetworkAgent;
 import android.net.NetworkUtils;
 import android.net.SocketKeepalive.InvalidPacketException;
+import android.net.SocketKeepalive.InvalidSocketException;
+import android.net.TcpKeepalivePacketData;
+import android.net.TcpKeepalivePacketData.TcpSocketInfo;
 import android.net.util.IpUtils;
 import android.os.Binder;
 import android.os.Handler;
@@ -65,7 +70,7 @@
  *
  * Provides methods to stop and start keepalive requests, and keeps track of keepalives across all
  * networks. This class is tightly coupled to ConnectivityService. It is not thread-safe and its
- * methods must be called only from the ConnectivityService handler thread.
+ * handle* methods must be called only from the ConnectivityService handler thread.
  */
 public class KeepaliveTracker {
 
@@ -78,9 +83,12 @@
     private final HashMap <NetworkAgentInfo, HashMap<Integer, KeepaliveInfo>> mKeepalives =
             new HashMap<> ();
     private final Handler mConnectivityServiceHandler;
+    @NonNull
+    private final TcpKeepaliveController mTcpController;
 
     public KeepaliveTracker(Handler handler) {
         mConnectivityServiceHandler = handler;
+        mTcpController = new TcpKeepaliveController(handler);
     }
 
     /**
@@ -96,20 +104,33 @@
         private final int mUid;
         private final int mPid;
         private final NetworkAgentInfo mNai;
+        private final int mType;
+        private final FileDescriptor mFd;
 
-        /** Keepalive slot. A small integer that identifies this keepalive among the ones handled
-          * by this network. */
+        public static final int TYPE_NATT = 1;
+        public static final int TYPE_TCP = 2;
+
+        // Keepalive slot. A small integer that identifies this keepalive among the ones handled
+        // by this network.
         private int mSlot = NO_KEEPALIVE;
 
         // Packet data.
         private final KeepalivePacketData mPacket;
         private final int mInterval;
 
-        // Whether the keepalive is started or not.
-        public boolean isStarted;
+        // Whether the keepalive is started or not. The initial state is NOT_STARTED.
+        private static final int NOT_STARTED = 1;
+        private static final int STARTING = 2;
+        private static final int STARTED = 3;
+        private int mStartedState = NOT_STARTED;
 
-        public KeepaliveInfo(Messenger messenger, IBinder binder, NetworkAgentInfo nai,
-                KeepalivePacketData packet, int interval) {
+        KeepaliveInfo(@NonNull Messenger messenger,
+                @NonNull IBinder binder,
+                @NonNull NetworkAgentInfo nai,
+                @NonNull KeepalivePacketData packet,
+                int interval,
+                int type,
+                @NonNull FileDescriptor fd) {
             mMessenger = messenger;
             mBinder = binder;
             mPid = Binder.getCallingPid();
@@ -118,6 +139,8 @@
             mNai = nai;
             mPacket = packet;
             mInterval = interval;
+            mType = type;
+            mFd = fd;
 
             try {
                 mBinder.linkToDeath(this, 0);
@@ -130,32 +153,40 @@
             return mNai;
         }
 
+        private String startedStateString(final int state) {
+            switch (state) {
+                case NOT_STARTED : return "NOT_STARTED";
+                case STARTING : return "STARTING";
+                case STARTED : return "STARTED";
+            }
+            throw new IllegalArgumentException("Unknown state");
+        }
+
         public String toString() {
-            return new StringBuffer("KeepaliveInfo [")
-                    .append(" network=").append(mNai.network)
-                    .append(" isStarted=").append(isStarted)
-                    .append(" ")
-                    .append(IpUtils.addressAndPortToString(mPacket.srcAddress, mPacket.srcPort))
-                    .append("->")
-                    .append(IpUtils.addressAndPortToString(mPacket.dstAddress, mPacket.dstPort))
-                    .append(" interval=" + mInterval)
-                    .append(" packetData=" + HexDump.toHexString(mPacket.getPacket()))
-                    .append(" uid=").append(mUid).append(" pid=").append(mPid)
-                    .append(" ]")
-                    .toString();
+            return "KeepaliveInfo ["
+                    + " network=" + mNai.network
+                    + " startedState=" + startedStateString(mStartedState)
+                    + " "
+                    + IpUtils.addressAndPortToString(mPacket.srcAddress, mPacket.srcPort)
+                    + "->"
+                    + IpUtils.addressAndPortToString(mPacket.dstAddress, mPacket.dstPort)
+                    + " interval=" + mInterval
+                    + " uid=" + mUid + " pid=" + mPid
+                    + " packetData=" + HexDump.toHexString(mPacket.getPacket())
+                    + " ]";
         }
 
         /** Sends a message back to the application via its SocketKeepalive.Callback. */
         void notifyMessenger(int slot, int err) {
+            if (DBG) {
+                Log.d(TAG, "notify keepalive " + mSlot + " on " + mNai.network + " for " + err);
+            }
             KeepaliveTracker.this.notifyMessenger(mMessenger, slot, err);
         }
 
         /** Called when the application process is killed. */
         public void binderDied() {
-            // Not called from ConnectivityService handler thread, so send it a message.
-            mConnectivityServiceHandler.obtainMessage(
-                    NetworkAgent.CMD_STOP_SOCKET_KEEPALIVE,
-                    mSlot, BINDER_DIED, mNai.network).sendToTarget();
+            stop(BINDER_DIED);
         }
 
         void unlinkDeathRecipient() {
@@ -202,7 +233,26 @@
             int error = isValid();
             if (error == SUCCESS) {
                 Log.d(TAG, "Starting keepalive " + mSlot + " on " + mNai.name());
-                mNai.asyncChannel.sendMessage(CMD_START_SOCKET_KEEPALIVE, slot, mInterval, mPacket);
+                switch (mType) {
+                    case TYPE_NATT:
+                        mNai.asyncChannel
+                                .sendMessage(CMD_START_SOCKET_KEEPALIVE, slot, mInterval, mPacket);
+                        break;
+                    case TYPE_TCP:
+                        mTcpController.startSocketMonitor(mFd, this, mSlot);
+                        mNai.asyncChannel
+                                .sendMessage(CMD_ADD_KEEPALIVE_PACKET_FILTER, slot, 0 /* Unused */,
+                                        mPacket);
+                        // TODO: check result from apf and notify of failure as needed.
+                        mNai.asyncChannel
+                                .sendMessage(CMD_START_SOCKET_KEEPALIVE, slot, mInterval, mPacket);
+                        break;
+                    default:
+                        Log.wtf(TAG, "Starting keepalive with unknown type: " + mType);
+                        handleStopKeepalive(mNai, mSlot, error);
+                        return;
+                }
+                mStartedState = STARTING;
             } else {
                 handleStopKeepalive(mNai, mSlot, error);
                 return;
@@ -216,15 +266,27 @@
                     Log.e(TAG, "Cannot stop unowned keepalive " + mSlot + " on " + mNai.network);
                 }
             }
-            if (isStarted) {
+            if (NOT_STARTED != mStartedState) {
                 Log.d(TAG, "Stopping keepalive " + mSlot + " on " + mNai.name());
-                mNai.asyncChannel.sendMessage(CMD_STOP_SOCKET_KEEPALIVE, mSlot);
+                if (mType == TYPE_NATT) {
+                    mNai.asyncChannel.sendMessage(CMD_STOP_SOCKET_KEEPALIVE, mSlot);
+                } else if (mType == TYPE_TCP) {
+                    mNai.asyncChannel.sendMessage(CMD_STOP_SOCKET_KEEPALIVE, mSlot);
+                    mNai.asyncChannel.sendMessage(CMD_REMOVE_KEEPALIVE_PACKET_FILTER, mSlot);
+                    mTcpController.stopSocketMonitor(mSlot);
+                } else {
+                    Log.wtf(TAG, "Stopping keepalive with unknown type: " + mType);
+                }
             }
             // TODO: at the moment we unconditionally return failure here. In cases where the
             // NetworkAgent is alive, should we ask it to reply, so it can return failure?
             notifyMessenger(mSlot, reason);
             unlinkDeathRecipient();
         }
+
+        void onFileDescriptorInitiatedStop(final int socketKeepaliveReason) {
+            handleStopKeepalive(mNai, mSlot, socketKeepaliveReason);
+        }
     }
 
     void notifyMessenger(Messenger messenger, int slot, int err) {
@@ -328,20 +390,38 @@
             return;
         }
 
-        if (reason == SUCCESS && !ki.isStarted) {
+        // This can be called in a number of situations :
+        // - startedState is STARTING.
+        //   - reason is SUCCESS => go to STARTED.
+        //   - reason isn't SUCCESS => it's an error starting. Go to NOT_STARTED and stop keepalive.
+        // - startedState is STARTED.
+        //   - reason is SUCCESS => it's a success stopping. Go to NOT_STARTED and stop keepalive.
+        //   - reason isn't SUCCESS => it's an error in exec. Go to NOT_STARTED and stop keepalive.
+        // The control is not supposed to ever come here if the state is NOT_STARTED. This is
+        // because in NOT_STARTED state, the code will switch to STARTING before sending messages
+        // to start, and the only way to NOT_STARTED is this function, through the edges outlined
+        // above : in all cases, keepalive gets stopped and can't restart without going into
+        // STARTING as messages are ordered. This also depends on the hardware processing the
+        // messages in order.
+        // TODO : clarify this code and get rid of mStartedState. Using a StateMachine is an
+        // option.
+        if (reason == SUCCESS && KeepaliveInfo.STARTING == ki.mStartedState) {
             // Keepalive successfully started.
             if (DBG) Log.d(TAG, "Started keepalive " + slot + " on " + nai.name());
-            ki.isStarted = true;
+            ki.mStartedState = KeepaliveInfo.STARTED;
             ki.notifyMessenger(slot, reason);
         } else {
             // Keepalive successfully stopped, or error.
-            ki.isStarted = false;
+            ki.mStartedState = KeepaliveInfo.NOT_STARTED;
             if (reason == SUCCESS) {
+                // The message indicated success stopping : don't call handleStopKeepalive.
                 if (DBG) Log.d(TAG, "Successfully stopped keepalive " + slot + " on " + nai.name());
             } else {
+                // The message indicated some error trying to start or during the course of
+                // keepalive : do call handleStopKeepalive.
+                handleStopKeepalive(nai, slot, reason);
                 if (DBG) Log.d(TAG, "Keepalive " + slot + " on " + nai.name() + " error " + reason);
             }
-            handleStopKeepalive(nai, slot, reason);
         }
     }
 
@@ -379,7 +459,47 @@
             notifyMessenger(messenger, NO_KEEPALIVE, e.error);
             return;
         }
-        KeepaliveInfo ki = new KeepaliveInfo(messenger, binder, nai, packet, intervalSeconds);
+        KeepaliveInfo ki = new KeepaliveInfo(messenger, binder, nai, packet, intervalSeconds,
+                KeepaliveInfo.TYPE_NATT, null);
+        mConnectivityServiceHandler.obtainMessage(
+                NetworkAgent.CMD_START_SOCKET_KEEPALIVE, ki).sendToTarget();
+    }
+
+    /**
+     * Called by ConnectivityService to start TCP keepalive on a file descriptor.
+     *
+     * In order to offload keepalive for application correctly, sequence number, ack number and
+     * other fields are needed to form the keepalive packet. Thus, this function synchronously
+     * puts the socket into repair mode to get the necessary information. After the socket has been
+     * put into repair mode, the application cannot access the socket until reverted to normal.
+     *
+     * See {@link android.net.SocketKeepalive}.
+     **/
+    public void startTcpKeepalive(@Nullable NetworkAgentInfo nai,
+            @NonNull FileDescriptor fd,
+            int intervalSeconds,
+            @NonNull Messenger messenger,
+            @NonNull IBinder binder) {
+        if (nai == null) {
+            notifyMessenger(messenger, NO_KEEPALIVE, ERROR_INVALID_NETWORK);
+            return;
+        }
+
+        TcpKeepalivePacketData packet = null;
+        try {
+            TcpSocketInfo tsi = TcpKeepaliveController.switchToRepairMode(fd);
+            packet = TcpKeepalivePacketData.tcpKeepalivePacket(tsi);
+        } catch (InvalidPacketException | InvalidSocketException e) {
+            try {
+                TcpKeepaliveController.switchOutOfRepairMode(fd);
+            } catch (ErrnoException e1) {
+                Log.e(TAG, "Couldn't move fd out of repair mode after failure to start keepalive");
+            }
+            notifyMessenger(messenger, NO_KEEPALIVE, e.error);
+            return;
+        }
+        KeepaliveInfo ki = new KeepaliveInfo(messenger, binder, nai, packet, intervalSeconds,
+                KeepaliveInfo.TYPE_TCP, fd);
         Log.d(TAG, "Created keepalive: " + ki.toString());
         mConnectivityServiceHandler.obtainMessage(CMD_START_SOCKET_KEEPALIVE, ki).sendToTarget();
     }
diff --git a/services/core/java/com/android/server/connectivity/TcpKeepaliveController.java b/services/core/java/com/android/server/connectivity/TcpKeepaliveController.java
index 640504f..8a9ac23 100644
--- a/services/core/java/com/android/server/connectivity/TcpKeepaliveController.java
+++ b/services/core/java/com/android/server/connectivity/TcpKeepaliveController.java
@@ -15,7 +15,6 @@
  */
 package com.android.server.connectivity;
 
-import static android.net.NetworkAgent.EVENT_SOCKET_KEEPALIVE;
 import static android.net.SocketKeepalive.DATA_RECEIVED;
 import static android.net.SocketKeepalive.ERROR_INVALID_SOCKET;
 import static android.net.SocketKeepalive.ERROR_SOCKET_NOT_IDLE;
@@ -31,10 +30,8 @@
 import android.net.TcpKeepalivePacketData.TcpSocketInfo;
 import android.net.TcpRepairWindow;
 import android.os.Handler;
-import android.os.Message;
 import android.os.MessageQueue;
 import android.os.Messenger;
-import android.os.RemoteException;
 import android.system.ErrnoException;
 import android.system.Int32Ref;
 import android.system.Os;
@@ -42,6 +39,7 @@
 import android.util.SparseArray;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.server.connectivity.KeepaliveTracker.KeepaliveInfo;
 
 import java.io.FileDescriptor;
 import java.net.InetAddress;
@@ -111,7 +109,7 @@
      * tcp/ip information.
      */
     // TODO : make this private. It's far too confusing that this gets called from outside
-    // at a time that nobody can understand, but the switch out is in this class only.
+    // at a time that nobody can understand.
     public static TcpSocketInfo switchToRepairMode(FileDescriptor fd)
             throws InvalidSocketException {
         if (DBG) Log.i(TAG, "switchToRepairMode to start tcp keepalive : " + fd);
@@ -199,7 +197,13 @@
                 trw.rcvWndScale);
     }
 
-    private static void switchOutOfRepairMode(@NonNull final FileDescriptor fd)
+    /**
+     * Switch the tcp socket out of repair mode.
+     *
+     * @param fd the fd of socket to switch back to normal.
+     */
+    // TODO : make this private.
+    public static void switchOutOfRepairMode(@NonNull final FileDescriptor fd)
             throws ErrnoException {
         Os.setsockoptInt(fd, IPPROTO_TCP, TCP_REPAIR, TCP_REPAIR_OFF);
     }
@@ -212,7 +216,7 @@
      * @param slot keepalive slot.
      */
     public void startSocketMonitor(@NonNull final FileDescriptor fd,
-            @NonNull final Messenger messenger, final int slot) {
+            @NonNull final KeepaliveInfo ki, final int slot) {
         synchronized (mListeners) {
             if (null != mListeners.get(slot)) {
                 throw new IllegalArgumentException("This slot is already taken");
@@ -226,31 +230,13 @@
                 // This can't be called twice because the queue guarantees that once the listener
                 // is unregistered it can't be called again, even for a message that arrived
                 // before it was unregistered.
-                int result;
-                try {
-                    // First move the socket out of repair mode.
-                    if (DBG) Log.d(TAG, "Moving socket out of repair mode for event : " + readyFd);
-                    switchOutOfRepairMode(readyFd);
-                    result = (0 != (events & EVENT_ERROR)) ? ERROR_INVALID_SOCKET : DATA_RECEIVED;
-                } catch (ErrnoException e) {
-                    // Could not move the socket out of repair mode. Still continue with notifying
-                    // the client
-                    Log.e(TAG, "Cannot switch socket out of repair mode", e);
-                    result = ERROR_INVALID_SOCKET;
+                final int reason;
+                if (0 != (events & EVENT_ERROR)) {
+                    reason = ERROR_INVALID_SOCKET;
+                } else {
+                    reason = DATA_RECEIVED;
                 }
-                // Prepare and send the message to the receiver.
-                final Message message = Message.obtain();
-                message.what = EVENT_SOCKET_KEEPALIVE;
-                message.arg1 = slot;
-                message.arg2 = result;
-                try {
-                    messenger.send(message);
-                } catch (RemoteException e) {
-                    // Remote process died
-                }
-                synchronized (mListeners) {
-                    mListeners.remove(slot);
-                }
+                ki.onFileDescriptorInitiatedStop(reason);
                 // The listener returns the new set of events to listen to. Because 0 means no
                 // event, the listener gets unregistered.
                 return 0;
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index e268e44..bfa7f9d 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -899,9 +899,20 @@
 
     @Override
     public void setIsSyncable(Account account, String providerName, int syncable) {
+        setIsSyncableAsUser(account, providerName, syncable, UserHandle.getCallingUserId());
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public void setIsSyncableAsUser(Account account, String providerName, int syncable,
+            int userId) {
         if (TextUtils.isEmpty(providerName)) {
             throw new IllegalArgumentException("Authority must not be empty");
         }
+        enforceCrossUserPermission(userId,
+                "no permission to set the sync settings for user " + userId);
         mContext.enforceCallingOrSelfPermission(Manifest.permission.WRITE_SYNC_SETTINGS,
                 "no permission to write the sync settings");
 
@@ -909,7 +920,6 @@
         final int callingUid = Binder.getCallingUid();
         final int callingPid = Binder.getCallingPid();
 
-        int userId = UserHandle.getCallingUserId();
         long identityToken = clearCallingIdentity();
         try {
             SyncManager syncManager = getSyncManager();
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 7096477..99e0707 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -3261,7 +3261,7 @@
                     if (Log.isLoggable(TAG, Log.DEBUG)) {
                         Log.d(TAG, "Account " + aau.account + " added, checking sync restore data");
                     }
-                    AccountSyncSettingsBackupHelper.accountAdded(mContext);
+                    AccountSyncSettingsBackupHelper.accountAdded(mContext, syncTargets.userId);
                     break;
                 }
             }
diff --git a/services/core/java/com/android/server/display/BrightnessTracker.java b/services/core/java/com/android/server/display/BrightnessTracker.java
index 727cf0e..126beef 100644
--- a/services/core/java/com/android/server/display/BrightnessTracker.java
+++ b/services/core/java/com/android/server/display/BrightnessTracker.java
@@ -34,6 +34,7 @@
 import android.hardware.SensorManager;
 import android.hardware.display.AmbientBrightnessDayStats;
 import android.hardware.display.BrightnessChangeEvent;
+import android.hardware.display.ColorDisplayManager;
 import android.hardware.display.DisplayManager;
 import android.hardware.display.DisplayManagerInternal;
 import android.hardware.display.DisplayedContentSample;
@@ -57,7 +58,6 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.app.ColorDisplayController;
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.RingBuffer;
@@ -382,9 +382,8 @@
             return;
         }
 
-        builder.setNightMode(mInjector.isNightModeActive(mContext, UserHandle.USER_CURRENT));
-        builder.setColorTemperature(mInjector.getColorTemperature(mContext,
-                UserHandle.USER_CURRENT));
+        builder.setNightMode(mInjector.isNightDisplayActivated(mContext));
+        builder.setColorTemperature(mInjector.getNightDisplayColorTemperature(mContext));
 
         if (mColorSamplingEnabled) {
             DisplayedContentSample sample = mInjector.sampleColor(mNoFramesToSample);
@@ -1096,12 +1095,13 @@
             return context.getSystemService(PowerManager.class).isInteractive();
         }
 
-        public int getColorTemperature(Context context, int userId) {
-            return new ColorDisplayController(context, userId).getColorTemperature();
+        public int getNightDisplayColorTemperature(Context context) {
+            return context.getSystemService(ColorDisplayManager.class)
+                    .getNightDisplayColorTemperature();
         }
 
-        public boolean isNightModeActive(Context context, int userId) {
-            return new ColorDisplayController(context, userId).isActivated();
+        public boolean isNightDisplayActivated(Context context) {
+            return context.getSystemService(ColorDisplayManager.class).isNightDisplayActivated();
         }
 
         public DisplayedContentSample sampleColor(int noFramesToSample) {
diff --git a/services/core/java/com/android/server/display/ColorDisplayService.java b/services/core/java/com/android/server/display/ColorDisplayService.java
index b3a1a06..9cb6eee 100644
--- a/services/core/java/com/android/server/display/ColorDisplayService.java
+++ b/services/core/java/com/android/server/display/ColorDisplayService.java
@@ -72,7 +72,6 @@
 
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.app.ColorDisplayController;
 import com.android.internal.util.DumpUtils;
 import com.android.server.DisplayThread;
 import com.android.server.SystemService;
@@ -115,6 +114,7 @@
     private static final int MSG_APPLY_NIGHT_DISPLAY_IMMEDIATE = 0;
     private static final int MSG_APPLY_NIGHT_DISPLAY_ANIMATED = 1;
     private static final int MSG_APPLY_GLOBAL_SATURATION = 2;
+    private static final int MSG_APPLY_DISPLAY_WHITE_BALANCE = 3;
 
     /**
      * Return value if a setting has not been set.
@@ -323,8 +323,7 @@
         }
 
         private ColorSpace.Rgb getDisplayColorSpaceFromSurfaceControl() {
-            IBinder displayToken = SurfaceControl.getBuiltInDisplay(
-                    SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN);
+            final IBinder displayToken = SurfaceControl.getInternalDisplayToken();
             if (displayToken == null) {
                 return null;
             }
@@ -448,7 +447,6 @@
     private ContentObserver mUserSetupObserver;
     private boolean mBootCompleted;
 
-    private ColorDisplayController mNightDisplayController;
     private ContentObserver mContentObserver;
 
     private DisplayWhiteBalanceListener mDisplayWhiteBalanceListener;
@@ -547,8 +545,6 @@
     private void setUp() {
         Slog.d(TAG, "setUp: currentUser=" + mCurrentUser);
 
-        mNightDisplayController = new ColorDisplayController(getContext(), mCurrentUser);
-
         // Listen for external changes to any of the settings.
         if (mContentObserver == null) {
             mContentObserver = new ContentObserver(new Handler(DisplayThread.get().getLooper())) {
@@ -586,7 +582,7 @@
                                         getNightDisplayCustomEndTimeInternal().getLocalTime());
                                 break;
                             case System.DISPLAY_COLOR_MODE:
-                                onDisplayColorModeChanged(mNightDisplayController.getColorMode());
+                                onDisplayColorModeChanged(getColorModeInternal());
                                 break;
                             case Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED:
                                 onAccessibilityInversionChanged();
@@ -634,7 +630,7 @@
 
         // Set the color mode, if valid, and immediately apply the updated tint matrix based on the
         // existing activated state. This ensures consistency of tint across the color mode change.
-        onDisplayColorModeChanged(mNightDisplayController.getColorMode());
+        onDisplayColorModeChanged(getColorModeInternal());
 
         if (mNightDisplayTintController.isAvailable(getContext())) {
             // Reset the activated state.
@@ -667,10 +663,6 @@
 
         getContext().getContentResolver().unregisterContentObserver(mContentObserver);
 
-        if (mNightDisplayController != null) {
-            mNightDisplayController = null;
-        }
-
         if (mNightDisplayTintController.isAvailable(getContext())) {
             if (mNightDisplayAutoMode != null) {
                 mNightDisplayAutoMode.onStop();
@@ -740,7 +732,7 @@
     }
 
     private void onAccessibilityActivated() {
-        onDisplayColorModeChanged(mNightDisplayController.getColorMode());
+        onDisplayColorModeChanged(getColorModeInternal());
     }
 
     /**
@@ -871,7 +863,7 @@
         // If disabled, clear the tint. If enabled, do nothing more here and let the next
         // temperature update set the correct tint.
         if (!activated) {
-            applyTint(mDisplayWhiteBalanceTintController, false);
+            mHandler.sendEmptyMessage(MSG_APPLY_DISPLAY_WHITE_BALANCE);
         }
     }
 
@@ -1003,8 +995,7 @@
                 mCurrentUser);
     }
 
-    private @ColorMode
-    int getColorModeInternal() {
+    private @ColorMode int getColorModeInternal() {
         final ContentResolver cr = getContext().getContentResolver();
         if (Secure.getIntForUser(cr, Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED,
                 0, mCurrentUser) == 1
@@ -1543,7 +1534,7 @@
             mDisplayWhiteBalanceTintController.setMatrix(cct);
 
             if (mDisplayWhiteBalanceTintController.isActivated()) {
-                applyTint(mDisplayWhiteBalanceTintController, false);
+                mHandler.sendEmptyMessage(MSG_APPLY_DISPLAY_WHITE_BALANCE);
                 return true;
             }
             return false;
@@ -1603,6 +1594,9 @@
                 case MSG_APPLY_NIGHT_DISPLAY_ANIMATED:
                     applyTint(mNightDisplayTintController, false);
                     break;
+                case MSG_APPLY_DISPLAY_WHITE_BALANCE:
+                    applyTint(mDisplayWhiteBalanceTintController, false);
+                    break;
             }
         }
     }
diff --git a/services/core/java/com/android/server/display/ColorFade.java b/services/core/java/com/android/server/display/ColorFade.java
index f2c539c..31b497d 100644
--- a/services/core/java/com/android/server/display/ColorFade.java
+++ b/services/core/java/com/android/server/display/ColorFade.java
@@ -27,6 +27,7 @@
 import android.opengl.EGLSurface;
 import android.opengl.GLES11Ext;
 import android.opengl.GLES20;
+import android.os.IBinder;
 import android.util.Slog;
 import android.view.DisplayInfo;
 import android.view.Surface;
@@ -474,8 +475,14 @@
             final SurfaceTexture st = new SurfaceTexture(mTexNames[0]);
             final Surface s = new Surface(st);
             try {
-                SurfaceControl.screenshot(SurfaceControl.getBuiltInDisplay(
-                        SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN), s);
+                final IBinder token = SurfaceControl.getInternalDisplayToken();
+                if (token == null) {
+                    Slog.e(TAG,
+                            "Failed to take screenshot because internal display is disconnected");
+                    return false;
+                }
+
+                SurfaceControl.screenshot(token, s);
                 st.updateTexImage();
                 st.getTransformMatrix(mTexMatrix);
             } finally {
@@ -629,7 +636,7 @@
             mSurfaceLayout = null;
             SurfaceControl.openTransaction();
             try {
-                mSurfaceControl.destroy();
+                mSurfaceControl.remove();
                 mSurface.release();
             } finally {
                 SurfaceControl.closeTransaction();
diff --git a/services/core/java/com/android/server/display/DisplayTransformManager.java b/services/core/java/com/android/server/display/DisplayTransformManager.java
index b1b7d3c..ef92401 100644
--- a/services/core/java/com/android/server/display/DisplayTransformManager.java
+++ b/services/core/java/com/android/server/display/DisplayTransformManager.java
@@ -87,7 +87,7 @@
      * Map of level -> color transformation matrix.
      */
     @GuardedBy("mColorMatrix")
-    private final SparseArray<float[]> mColorMatrix = new SparseArray<>(3);
+    private final SparseArray<float[]> mColorMatrix = new SparseArray<>(5);
     /**
      * Temporary matrix used internally by {@link #computeColorMatrixLocked()}.
      */
@@ -148,6 +148,21 @@
     }
 
     /**
+     * Sets the current Daltonization mode. This adjusts the color space to correct for or simulate
+     * various types of color blindness.
+     *
+     * @param mode the new Daltonization mode, or -1 to disable
+     */
+    public void setDaltonizerMode(int mode) {
+        synchronized (mDaltonizerModeLock) {
+            if (mDaltonizerMode != mode) {
+                mDaltonizerMode = mode;
+                applyDaltonizerMode(mode);
+            }
+        }
+    }
+
+    /**
      * Returns the composition of all current color matrices, or {@code null} if there are none.
      */
     @GuardedBy("mColorMatrix")
@@ -167,30 +182,6 @@
     }
 
     /**
-     * Returns the current Daltonization mode.
-     */
-    public int getDaltonizerMode() {
-        synchronized (mDaltonizerModeLock) {
-            return mDaltonizerMode;
-        }
-    }
-
-    /**
-     * Sets the current Daltonization mode. This adjusts the color space to correct for or simulate
-     * various types of color blindness.
-     *
-     * @param mode the new Daltonization mode, or -1 to disable
-     */
-    public void setDaltonizerMode(int mode) {
-        synchronized (mDaltonizerModeLock) {
-            if (mDaltonizerMode != mode) {
-                mDaltonizerMode = mode;
-                applyDaltonizerMode(mode);
-            }
-        }
-    }
-
-    /**
      * Propagates the provided color transformation matrix to the SurfaceFlinger.
      */
     private static void applyColorMatrix(float[] m) {
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 16d82df..28f21f63 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -17,12 +17,8 @@
 package com.android.server.display;
 
 import android.app.ActivityThread;
-import android.content.res.Resources;
-import com.android.server.LocalServices;
-import com.android.server.lights.Light;
-import com.android.server.lights.LightsManager;
-
 import android.content.Context;
+import android.content.res.Resources;
 import android.hardware.sidekick.SidekickInternal;
 import android.os.Build;
 import android.os.Handler;
@@ -31,6 +27,7 @@
 import android.os.PowerManager;
 import android.os.SystemProperties;
 import android.os.Trace;
+import android.util.LongSparseArray;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.view.Display;
@@ -38,6 +35,11 @@
 import android.view.DisplayEventReceiver;
 import android.view.Surface;
 import android.view.SurfaceControl;
+
+import com.android.server.LocalServices;
+import com.android.server.lights.Light;
+import com.android.server.lights.LightsManager;
+
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -58,13 +60,9 @@
 
     private static final String PROPERTY_EMULATOR_CIRCULAR = "ro.emulator.circular";
 
-    private static final int[] BUILT_IN_DISPLAY_IDS_TO_SCAN = new int[] {
-            SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN,
-            SurfaceControl.BUILT_IN_DISPLAY_ID_HDMI,
-    };
+    private final LongSparseArray<LocalDisplayDevice> mDevices =
+            new LongSparseArray<LocalDisplayDevice>();
 
-    private final SparseArray<LocalDisplayDevice> mDevices =
-            new SparseArray<LocalDisplayDevice>();
     @SuppressWarnings("unused")  // Becomes active at instantiation time.
     private HotplugDisplayEventReceiver mHotplugReceiver;
 
@@ -80,28 +78,26 @@
 
         mHotplugReceiver = new HotplugDisplayEventReceiver(getHandler().getLooper());
 
-        for (int builtInDisplayId : BUILT_IN_DISPLAY_IDS_TO_SCAN) {
-            tryConnectDisplayLocked(builtInDisplayId);
+        for (long physicalDisplayId : SurfaceControl.getPhysicalDisplayIds()) {
+            tryConnectDisplayLocked(physicalDisplayId);
         }
     }
 
-    private void tryConnectDisplayLocked(int builtInDisplayId) {
-        IBinder displayToken = SurfaceControl.getBuiltInDisplay(builtInDisplayId);
+    private void tryConnectDisplayLocked(long physicalDisplayId) {
+        final IBinder displayToken = SurfaceControl.getPhysicalDisplayToken(physicalDisplayId);
         if (displayToken != null) {
             SurfaceControl.PhysicalDisplayInfo[] configs =
                     SurfaceControl.getDisplayConfigs(displayToken);
             if (configs == null) {
                 // There are no valid configs for this device, so we can't use it
-                Slog.w(TAG, "No valid configs found for display device " +
-                        builtInDisplayId);
+                Slog.w(TAG, "No valid configs found for display device " + physicalDisplayId);
                 return;
             }
             int activeConfig = SurfaceControl.getActiveConfig(displayToken);
             if (activeConfig < 0) {
                 // There is no active config, and for now we don't have the
                 // policy to set one.
-                Slog.w(TAG, "No active config found for display device " +
-                        builtInDisplayId);
+                Slog.w(TAG, "No active config found for display device " + physicalDisplayId);
                 return;
             }
             int activeColorMode = SurfaceControl.getActiveColorMode(displayToken);
@@ -110,16 +106,17 @@
                 // configuration pass we'll go ahead and set it to whatever it was set to last (or
                 // COLOR_MODE_NATIVE if this is the first configuration).
                 Slog.w(TAG, "Unable to get active color mode for display device " +
-                        builtInDisplayId);
+                        physicalDisplayId);
                 activeColorMode = Display.COLOR_MODE_INVALID;
             }
             int[] colorModes = SurfaceControl.getDisplayColorModes(displayToken);
-            LocalDisplayDevice device = mDevices.get(builtInDisplayId);
+            LocalDisplayDevice device = mDevices.get(physicalDisplayId);
             if (device == null) {
                 // Display was added.
-                device = new LocalDisplayDevice(displayToken, builtInDisplayId,
-                        configs, activeConfig, colorModes, activeColorMode);
-                mDevices.put(builtInDisplayId, device);
+                final boolean isInternal = mDevices.size() == 0;
+                device = new LocalDisplayDevice(displayToken, physicalDisplayId,
+                        configs, activeConfig, colorModes, activeColorMode, isInternal);
+                mDevices.put(physicalDisplayId, device);
                 sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_ADDED);
             } else if (device.updatePhysicalDisplayInfoLocked(configs, activeConfig,
                         colorModes, activeColorMode)) {
@@ -133,11 +130,11 @@
         }
     }
 
-    private void tryDisconnectDisplayLocked(int builtInDisplayId) {
-        LocalDisplayDevice device = mDevices.get(builtInDisplayId);
+    private void tryDisconnectDisplayLocked(long physicalDisplayId) {
+        LocalDisplayDevice device = mDevices.get(physicalDisplayId);
         if (device != null) {
             // Display was removed.
-            mDevices.remove(builtInDisplayId);
+            mDevices.remove(physicalDisplayId);
             sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_REMOVED);
         }
     }
@@ -158,10 +155,11 @@
     }
 
     private final class LocalDisplayDevice extends DisplayDevice {
-        private final int mBuiltInDisplayId;
+        private final long mPhysicalDisplayId;
         private final Light mBacklight;
         private final SparseArray<DisplayModeRecord> mSupportedModes = new SparseArray<>();
         private final ArrayList<Integer> mSupportedColorModes = new ArrayList<>();
+        private final boolean mIsInternal;
 
         private DisplayDeviceInfo mInfo;
         private boolean mHavePendingChanges;
@@ -179,16 +177,17 @@
 
         private  SurfaceControl.PhysicalDisplayInfo mDisplayInfos[];
 
-        public LocalDisplayDevice(IBinder displayToken, int builtInDisplayId,
+        LocalDisplayDevice(IBinder displayToken, long physicalDisplayId,
                 SurfaceControl.PhysicalDisplayInfo[] physicalDisplayInfos, int activeDisplayInfo,
-                int[] colorModes, int activeColorMode) {
-            super(LocalDisplayAdapter.this, displayToken, UNIQUE_ID_PREFIX + builtInDisplayId);
-            mBuiltInDisplayId = builtInDisplayId;
+                int[] colorModes, int activeColorMode, boolean isInternal) {
+            super(LocalDisplayAdapter.this, displayToken, UNIQUE_ID_PREFIX + physicalDisplayId);
+            mPhysicalDisplayId = physicalDisplayId;
+            mIsInternal = isInternal;
             updatePhysicalDisplayInfoLocked(physicalDisplayInfos, activeDisplayInfo,
                     colorModes, activeColorMode);
             updateColorModesLocked(colorModes, activeColorMode);
             mSidekickInternal = LocalServices.getService(SidekickInternal.class);
-            if (mBuiltInDisplayId == SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN) {
+            if (mIsInternal) {
                 LightsManager lights = LocalServices.getService(LightsManager.class);
                 mBacklight = lights.getLight(LightsManager.LIGHT_ID_BACKLIGHT);
             } else {
@@ -392,7 +391,7 @@
                 }
 
                 final Resources res = getOverlayContext().getResources();
-                if (mBuiltInDisplayId == SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN) {
+                if (mIsInternal) {
                     mInfo.name = res.getString(
                             com.android.internal.R.string.display_manager_built_in_display_name);
                     mInfo.flags |= DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY
@@ -455,7 +454,7 @@
             final boolean stateChanged = (mState != state);
             final boolean brightnessChanged = (mBrightness != brightness) && mBacklight != null;
             if (stateChanged || brightnessChanged) {
-                final int displayId = mBuiltInDisplayId;
+                final long physicalDisplayId = mPhysicalDisplayId;
                 final IBinder token = getDisplayTokenLocked();
                 final int oldState = mState;
 
@@ -519,7 +518,7 @@
                     private void setVrMode(boolean isVrEnabled) {
                         if (DEBUG) {
                             Slog.d(TAG, "setVrMode("
-                                    + "id=" + displayId
+                                    + "id=" + physicalDisplayId
                                     + ", state=" + Display.stateToString(state) + ")");
                         }
                         mBacklight.setVrMode(isVrEnabled);
@@ -528,7 +527,7 @@
                     private void setDisplayState(int state) {
                         if (DEBUG) {
                             Slog.d(TAG, "setDisplayState("
-                                    + "id=" + displayId
+                                    + "id=" + physicalDisplayId
                                     + ", state=" + Display.stateToString(state) + ")");
                         }
 
@@ -546,7 +545,7 @@
                         }
                         final int mode = getPowerModeForState(state);
                         Trace.traceBegin(Trace.TRACE_TAG_POWER, "setDisplayState("
-                                + "id=" + displayId
+                                + "id=" + physicalDisplayId
                                 + ", state=" + Display.stateToString(state) + ")");
                         try {
                             SurfaceControl.setDisplayPowerMode(token, mode);
@@ -571,11 +570,12 @@
                     private void setDisplayBrightness(int brightness) {
                         if (DEBUG) {
                             Slog.d(TAG, "setDisplayBrightness("
-                                    + "id=" + displayId + ", brightness=" + brightness + ")");
+                                    + "id=" + physicalDisplayId
+                                    + ", brightness=" + brightness + ")");
                         }
 
                         Trace.traceBegin(Trace.TRACE_TAG_POWER, "setDisplayBrightness("
-                                + "id=" + displayId + ", brightness=" + brightness + ")");
+                                + "id=" + physicalDisplayId + ", brightness=" + brightness + ")");
                         try {
                             mBacklight.setBrightness(brightness);
                             Trace.traceCounter(Trace.TRACE_TAG_POWER,
@@ -646,7 +646,7 @@
         @Override
         public void dumpLocked(PrintWriter pw) {
             super.dumpLocked(pw);
-            pw.println("mBuiltInDisplayId=" + mBuiltInDisplayId);
+            pw.println("mPhysicalDisplayId=" + mPhysicalDisplayId);
             pw.println("mActivePhysIndex=" + mActivePhysIndex);
             pw.println("mActiveModeId=" + mActiveModeId);
             pw.println("mActiveColorMode=" + mActiveColorMode);
@@ -731,12 +731,12 @@
         }
 
         @Override
-        public void onHotplug(long timestampNanos, int builtInDisplayId, boolean connected) {
+        public void onHotplug(long timestampNanos, long physicalDisplayId, boolean connected) {
             synchronized (getSyncRoot()) {
                 if (connected) {
-                    tryConnectDisplayLocked(builtInDisplayId);
+                    tryConnectDisplayLocked(physicalDisplayId);
                 } else {
-                    tryDisconnectDisplayLocked(builtInDisplayId);
+                    tryDisconnectDisplayLocked(physicalDisplayId);
                 }
             }
         }
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index 7376ed2..072238e 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -2412,7 +2412,8 @@
     void wakeUp() {
         assertRunOnServiceThread();
         mWakeUpMessageReceived = true;
-        mPowerManager.wakeUp(SystemClock.uptimeMillis(), "android.server.hdmi:WAKE");
+        mPowerManager.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_HDMI,
+                "android.server.hdmi:WAKE");
         // PowerManger will send the broadcast Intent.ACTION_SCREEN_ON and after this gets
         // the intent, the sequence will continue at onWakeUp().
     }
@@ -2637,7 +2638,8 @@
                 playback().sendStandby(0 /* unused */);
             }
         } else if (isPowerStandbyOrTransient() && !isStandbyModeOn) {
-            mPowerManager.wakeUp(SystemClock.uptimeMillis(), "android.server.hdmi:WAKE");
+            mPowerManager.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_HDMI,
+                    "android.server.hdmi:WAKE");
             if (playback() != null) {
                 oneTouchPlay(new IHdmiControlCallback.Stub() {
                     @Override
diff --git a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
index 532aa01..2bfb31f 100644
--- a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
+++ b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
@@ -286,6 +286,46 @@
     }
 
     /**
+     * Sets whether the default service should be used.
+     *
+     * <p>Typically used during CTS tests to make sure only the default service doesn't interfere
+     * with the test results.
+     *
+     * @throws SecurityException if caller is not allowed to manage this service's settings.
+     */
+    public final void setDefaultServiceEnabled(@UserIdInt int userId, boolean enabled) {
+        Slog.i(mTag, "setDefaultServiceEnabled() for userId " + userId + ": " + enabled);
+        enforceCallingPermissionForManagement();
+
+        synchronized (mLock) {
+            final S oldService = peekServiceForUserLocked(userId);
+            if (oldService != null) {
+                oldService.removeSelfFromCacheLocked();
+            }
+            mServiceNameResolver.setDefaultServiceEnabled(userId, enabled);
+
+            // Must update the service on cache so its initialization code is triggered
+            updateCachedServiceLocked(userId);
+        }
+    }
+
+    /**
+     * Checks whether the default service should be used.
+     *
+     * <p>Typically used during CTS tests to make sure only the default service doesn't interfere
+     * with the test results.
+     *
+     * @throws SecurityException if caller is not allowed to manage this service's settings.
+     */
+    public final boolean isDefaultServiceEnabled(@UserIdInt int userId) {
+        enforceCallingPermissionForManagement();
+
+        synchronized (mLock) {
+            return mServiceNameResolver.isDefaultServiceEnabled(userId);
+        }
+    }
+
+    /**
      * Gets the maximum time the service implementation can be changed.
      *
      * @throws UnsupportedOperationException if subclass doesn't override it.
diff --git a/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java b/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java
index 7f198ac..cf84e22 100644
--- a/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java
+++ b/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java
@@ -27,6 +27,7 @@
 import android.text.TextUtils;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.SparseBooleanArray;
 import android.util.TimeUtils;
 
 import com.android.internal.annotations.GuardedBy;
@@ -61,6 +62,15 @@
     private final SparseArray<String> mTemporaryServiceNames = new SparseArray<>();
 
     /**
+     * Map of default services that have been disabled by
+     * {@link #setDefaultServiceEnabled(int, boolean)},keyed by {@code userId}.
+     *
+     * <p>Typically used by Shell command and/or CTS tests.
+     */
+    @GuardedBy("mLock")
+    private final SparseBooleanArray mDefaultServicesDisabled = new SparseBooleanArray();
+
+    /**
      * When the temporary service will expire (and reset back to the default).
      */
     @GuardedBy("mLock")
@@ -99,12 +109,18 @@
             final String temporaryName = mTemporaryServiceNames.get(userId);
             if (temporaryName != null) {
                 // Always log it, as it should only be used on CTS or during development
-                Slog.w(TAG, "getComponentName(): using temporary name " + temporaryName
+                Slog.w(TAG, "getServiceName(): using temporary name " + temporaryName
                         + " for user " + userId);
                 return temporaryName;
-            } else {
-                return getDefaultServiceName(userId);
             }
+            final boolean disabled = mDefaultServicesDisabled.get(userId);
+            if (disabled) {
+                // Always log it, as it should only be used on CTS or during development
+                Slog.w(TAG, "getServiceName(): temporary name not set and default disabled for "
+                        + "user " + userId);
+                return null;
+            }
+            return getDefaultServiceName(userId);
         }
     }
 
@@ -158,6 +174,24 @@
     }
 
     @Override
+    public void setDefaultServiceEnabled(int userId, boolean enabled) {
+        synchronized (mLock) {
+            if (enabled) {
+                mDefaultServicesDisabled.removeAt(userId);
+            } else {
+                mDefaultServicesDisabled.put(userId, true);
+            }
+        }
+    }
+
+    @Override
+    public boolean isDefaultServiceEnabled(int userId) {
+        synchronized (mLock) {
+            return mDefaultServicesDisabled.get(userId);
+        }
+    }
+
+    @Override
     public String toString() {
         return "FrameworkResourcesServiceNamer[temps=" + mTemporaryServiceNames + "]";
     }
@@ -168,6 +202,7 @@
         synchronized (mLock) {
             pw.print("FrameworkResourcesServiceNamer: resId="); pw.print(mResourceId);
             pw.print(", numberTemps="); pw.print(mTemporaryServiceNames.size());
+            pw.print(", enabledDefaults="); pw.print(mDefaultServicesDisabled.size());
         }
     }
 
@@ -181,7 +216,9 @@
                 final long ttl = mTemporaryServiceExpiration - SystemClock.elapsedRealtime();
                 pw.print(" (expires in "); TimeUtils.formatDuration(ttl, pw); pw.print("), ");
             }
-            pw.print("defaultName="); pw.println(getDefaultServiceName(userId));
+            pw.print("defaultName="); pw.print(getDefaultServiceName(userId));
+            final boolean disabled = mDefaultServicesDisabled.get(userId);
+            pw.println(disabled ? " (disabled)" : " (enabled)");
         }
     }
 
diff --git a/services/core/java/com/android/server/infra/ServiceNameResolver.java b/services/core/java/com/android/server/infra/ServiceNameResolver.java
index bc11ff3..5b60413 100644
--- a/services/core/java/com/android/server/infra/ServiceNameResolver.java
+++ b/services/core/java/com/android/server/infra/ServiceNameResolver.java
@@ -108,6 +108,36 @@
     }
 
     /**
+     * Sets whether the default service should be used when the temporary service is not set.
+     *
+     * <p>Typically used during CTS tests to make sure only the default service doesn't interfere
+     * with the test results.
+     *
+     * @param userId user handle
+     * @param enabled whether the default service should be used when the temporary service is not
+     * set
+     *
+     * @throws UnsupportedOperationException if not implemented.
+     */
+    default void setDefaultServiceEnabled(@UserIdInt int userId, boolean enabled) {
+        throw new UnsupportedOperationException("changing default service not supported");
+    }
+
+    /**
+     * Checks whether the default service should be used when the temporary service is not set.
+     *
+     * <p>Typically used during CTS tests to make sure only the default service doesn't interfere
+     * with the test results.
+     *
+     * @param userId user handle
+     *
+     * @throws UnsupportedOperationException if not implemented.
+     */
+    default boolean isDefaultServiceEnabled(@UserIdInt int userId) {
+        throw new UnsupportedOperationException("checking default service not supported");
+    }
+
+    /**
      * Dumps the generic info in just one line (without calling {@code println}.
      */
     // TODO(b/117779333): support proto
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index 19d10ec..cefe583 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -509,7 +509,7 @@
         private static final float DEFAULT_CONN_CONGESTION_DELAY_FRAC = 0.5f;
         private static final float DEFAULT_CONN_PREFETCH_RELAX_FRAC = 0.5f;
         private static final boolean DEFAULT_USE_HEARTBEATS = false;
-        private static final boolean DEFAULT_TIME_CONTROLLER_SKIP_NOT_READY_JOBS = false;
+        private static final boolean DEFAULT_TIME_CONTROLLER_SKIP_NOT_READY_JOBS = true;
         private static final long DEFAULT_QUOTA_CONTROLLER_ALLOWED_TIME_PER_PERIOD_MS =
                 10 * 60 * 1000L; // 10 minutes
         private static final long DEFAULT_QUOTA_CONTROLLER_IN_QUOTA_BUFFER_MS =
diff --git a/services/core/java/com/android/server/job/controllers/StateController.java b/services/core/java/com/android/server/job/controllers/StateController.java
index 97c3bac..74628fb 100644
--- a/services/core/java/com/android/server/job/controllers/StateController.java
+++ b/services/core/java/com/android/server/job/controllers/StateController.java
@@ -110,6 +110,7 @@
         final boolean jobWouldBeReady = jobStatus.wouldBeReadyWithConstraint(constraint);
         if (DEBUG) {
             Slog.v(TAG, "wouldBeReadyWithConstraintLocked: " + jobStatus.toShortString()
+                    + " constraint=" + constraint
                     + " readyWithConstraint=" + jobWouldBeReady);
         }
         if (!jobWouldBeReady) {
diff --git a/services/core/java/com/android/server/job/controllers/TimeController.java b/services/core/java/com/android/server/job/controllers/TimeController.java
index 26f3caf..70deb38 100644
--- a/services/core/java/com/android/server/job/controllers/TimeController.java
+++ b/services/core/java/com/android/server/job/controllers/TimeController.java
@@ -149,8 +149,8 @@
 
     @Override
     public void onConstantsUpdatedLocked() {
-        checkExpiredDelaysAndResetAlarm();
         checkExpiredDeadlinesAndResetAlarm();
+        checkExpiredDelaysAndResetAlarm();
     }
 
     @Override
@@ -159,20 +159,47 @@
             return;
         }
 
-        if (job.hasTimingDelayConstraint()
-                && job.getEarliestRunTime() <= mNextDelayExpiredElapsedMillis) {
-            checkExpiredDelaysAndResetAlarm();
-        }
+        final long nowElapsedMillis = sElapsedRealtimeClock.millis();
+
+        // Check deadline constraint first because if it's satisfied, we avoid a little bit of
+        // unnecessary processing of the timing delay.
         if (job.hasDeadlineConstraint()
+                && !job.isConstraintSatisfied(JobStatus.CONSTRAINT_DEADLINE)
                 && job.getLatestRunTimeElapsed() <= mNextJobExpiredElapsedMillis) {
-            checkExpiredDeadlinesAndResetAlarm();
+            if (evaluateDeadlineConstraint(job, nowElapsedMillis)) {
+                checkExpiredDeadlinesAndResetAlarm();
+                checkExpiredDelaysAndResetAlarm();
+            } else {
+                final boolean isAlarmForJob =
+                        job.getLatestRunTimeElapsed() == mNextJobExpiredElapsedMillis;
+                final boolean wouldBeReady = wouldBeReadyWithConstraintLocked(
+                        job, JobStatus.CONSTRAINT_DEADLINE);
+                if ((isAlarmForJob && !wouldBeReady) || (!isAlarmForJob && wouldBeReady)) {
+                    checkExpiredDeadlinesAndResetAlarm();
+                }
+            }
+        }
+        if (job.hasTimingDelayConstraint()
+                && !job.isConstraintSatisfied(JobStatus.CONSTRAINT_TIMING_DELAY)
+                && job.getEarliestRunTime() <= mNextDelayExpiredElapsedMillis) {
+            if (evaluateTimingDelayConstraint(job, nowElapsedMillis)) {
+                checkExpiredDelaysAndResetAlarm();
+            } else {
+                final boolean isAlarmForJob =
+                        job.getEarliestRunTime() == mNextDelayExpiredElapsedMillis;
+                final boolean wouldBeReady = wouldBeReadyWithConstraintLocked(
+                        job, JobStatus.CONSTRAINT_TIMING_DELAY);
+                if ((isAlarmForJob && !wouldBeReady) || (!isAlarmForJob && wouldBeReady)) {
+                    checkExpiredDelaysAndResetAlarm();
+                }
+            }
         }
     }
 
     @Override
     public void reevaluateStateLocked(int uid) {
-        checkExpiredDelaysAndResetAlarm();
         checkExpiredDeadlinesAndResetAlarm();
+        checkExpiredDelaysAndResetAlarm();
     }
 
     /**
@@ -182,10 +209,10 @@
      * back and forth.
      */
     private boolean canStopTrackingJobLocked(JobStatus job) {
-        return (!job.hasTimingDelayConstraint() ||
-                (job.satisfiedConstraints&JobStatus.CONSTRAINT_TIMING_DELAY) != 0) &&
-                (!job.hasDeadlineConstraint() ||
-                        (job.satisfiedConstraints&JobStatus.CONSTRAINT_DEADLINE) != 0);
+        return (!job.hasTimingDelayConstraint()
+                        || job.isConstraintSatisfied(JobStatus.CONSTRAINT_TIMING_DELAY))
+                && (!job.hasDeadlineConstraint()
+                        || job.isConstraintSatisfied(JobStatus.CONSTRAINT_DEADLINE));
     }
 
     private void ensureAlarmServiceLocked() {
@@ -241,6 +268,7 @@
         }
     }
 
+    /** @return true if the job's deadline constraint is satisfied */
     private boolean evaluateDeadlineConstraint(JobStatus job, long nowElapsedMillis) {
         final long jobDeadline = job.getLatestRunTimeElapsed();
 
@@ -279,7 +307,7 @@
                     if (job.isReady()) {
                         ready = true;
                     }
-                } else if (!job.isConstraintSatisfied(JobStatus.CONSTRAINT_TIMING_DELAY)) {
+                } else {
                     if (mConstants.TIME_CONTROLLER_SKIP_NOT_READY_JOBS
                             && !wouldBeReadyWithConstraintLocked(
                             job, JobStatus.CONSTRAINT_TIMING_DELAY)) {
@@ -319,6 +347,7 @@
         }
     }
 
+    /** @return true if the job's delay constraint is satisfied */
     private boolean evaluateTimingDelayConstraint(JobStatus job, long nowElapsedMillis) {
         final long jobDelayTime = job.getEarliestRunTime();
         if (jobDelayTime <= nowElapsedMillis) {
@@ -347,6 +376,9 @@
      */
     private void setDelayExpiredAlarmLocked(long alarmTimeElapsedMillis, WorkSource ws) {
         alarmTimeElapsedMillis = maybeAdjustAlarmTime(alarmTimeElapsedMillis);
+        if (mNextDelayExpiredElapsedMillis == alarmTimeElapsedMillis) {
+            return;
+        }
         mNextDelayExpiredElapsedMillis = alarmTimeElapsedMillis;
         updateAlarmWithListenerLocked(DELAY_TAG, mNextDelayExpiredListener,
                 mNextDelayExpiredElapsedMillis, ws);
@@ -359,6 +391,9 @@
      */
     private void setDeadlineExpiredAlarmLocked(long alarmTimeElapsedMillis, WorkSource ws) {
         alarmTimeElapsedMillis = maybeAdjustAlarmTime(alarmTimeElapsedMillis);
+        if (mNextJobExpiredElapsedMillis == alarmTimeElapsedMillis) {
+            return;
+        }
         mNextJobExpiredElapsedMillis = alarmTimeElapsedMillis;
         updateAlarmWithListenerLocked(DEADLINE_TAG, mDeadlineExpiredListener,
                 mNextJobExpiredElapsedMillis, ws);
diff --git a/services/core/java/com/android/server/location/GnssConfiguration.java b/services/core/java/com/android/server/location/GnssConfiguration.java
index 7225926..91b5234 100644
--- a/services/core/java/com/android/server/location/GnssConfiguration.java
+++ b/services/core/java/com/android/server/location/GnssConfiguration.java
@@ -367,7 +367,7 @@
             return defaultValue;
         }
         try {
-            return Integer.parseInt(valueString);
+            return Integer.decode(valueString);
         } catch (NumberFormatException e) {
             Log.e(TAG, "Unable to parse config parameter " + configParameter + " value: "
                     + valueString + ". Using default value: " + defaultValue);
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index f368e7b..2f0b388 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -302,7 +302,7 @@
             MAX_RETRY_INTERVAL);
 
     // true if we are enabled, protected by this
-    private boolean mEnabled = true;
+    private boolean mEnabled;
 
     private boolean mShutdown;
 
diff --git a/services/core/java/com/android/server/location/LocationBasedCountryDetector.java b/services/core/java/com/android/server/location/LocationBasedCountryDetector.java
index 6527899f..8ee1285 100644
--- a/services/core/java/com/android/server/location/LocationBasedCountryDetector.java
+++ b/services/core/java/com/android/server/location/LocationBasedCountryDetector.java
@@ -235,18 +235,15 @@
      * Start a new thread to query the country from Geocoder.
      */
     private synchronized void queryCountryCode(final Location location) {
-        if (location == null) {
-            notifyListener(null);
-            return;
-        }
         if (mQueryThread != null) return;
         mQueryThread = new Thread(new Runnable() {
             @Override
             public void run() {
-                String countryIso = null;
-                if (location != null) {
-                    countryIso = getCountryFromLocation(location);
+                if (location == null) {
+                    notifyListener(null);
+                    return;
                 }
+                String countryIso = getCountryFromLocation(location);
                 if (countryIso != null) {
                     mDetectedCountry = new Country(countryIso, Country.COUNTRY_SOURCE_LOCATION);
                 } else {
diff --git a/services/core/java/com/android/server/location/LocationProviderProxy.java b/services/core/java/com/android/server/location/LocationProviderProxy.java
index 34c8786..afe3473 100644
--- a/services/core/java/com/android/server/location/LocationProviderProxy.java
+++ b/services/core/java/com/android/server/location/LocationProviderProxy.java
@@ -183,12 +183,17 @@
 
     @Override
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        pw.println(" service=" + mServiceWatcher);
+        pw.println("  service=" + mServiceWatcher);
+        synchronized (mProviderPackagesLock) {
+            if (mProviderPackages.size() > 1) {
+                pw.println("  additional packages=" + mProviderPackages);
+            }
+        }
         mServiceWatcher.runOnBinderBlocking(binder -> {
             try {
                 TransferPipe.dumpAsync(binder, fd, args);
             } catch (IOException | RemoteException e) {
-                pw.println(" failed to dump location provider");
+                pw.println("  <failed to dump location provider: " + e + ">");
             }
             return null;
         }, null);
diff --git a/services/core/java/com/android/server/notification/BubbleExtractor.java b/services/core/java/com/android/server/notification/BubbleExtractor.java
new file mode 100644
index 0000000..358bdb9
--- /dev/null
+++ b/services/core/java/com/android/server/notification/BubbleExtractor.java
@@ -0,0 +1,68 @@
+/**
+* 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.notification;
+
+import android.content.Context;
+import android.util.Slog;
+
+/**
+ * Determines whether a bubble can be shown for this notification
+ */
+public class BubbleExtractor implements NotificationSignalExtractor {
+    private static final String TAG = "BubbleExtractor";
+    private static final boolean DBG = false;
+
+    private RankingConfig mConfig;
+
+    public void initialize(Context ctx, NotificationUsageStats usageStats) {
+        if (DBG) Slog.d(TAG, "Initializing  " + getClass().getSimpleName() + ".");
+    }
+
+    public RankingReconsideration process(NotificationRecord record) {
+        if (record == null || record.getNotification() == null) {
+            if (DBG) Slog.d(TAG, "skipping empty notification");
+            return null;
+        }
+
+        if (mConfig == null) {
+            if (DBG) Slog.d(TAG, "missing config");
+            return null;
+        }
+        boolean userWantsBubbles = mConfig.bubblesEnabled(record.sbn.getUser());
+        boolean appCanShowBubble =
+                mConfig.areBubblesAllowed(record.sbn.getPackageName(), record.sbn.getUid());
+        if (!userWantsBubbles || !appCanShowBubble) {
+            record.setAllowBubble(false);
+        } else {
+            if (record.getChannel() != null) {
+                record.setAllowBubble(record.getChannel().canBubble() && appCanShowBubble);
+            } else {
+                record.setAllowBubble(appCanShowBubble);
+            }
+        }
+
+        return null;
+    }
+
+    @Override
+    public void setConfig(RankingConfig config) {
+        mConfig = config;
+    }
+
+    @Override
+    public void setZenHelper(ZenModeHelper helper) {
+    }
+}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index d04433a..3557fcf 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -1305,6 +1305,8 @@
     private final class SettingsObserver extends ContentObserver {
         private final Uri NOTIFICATION_BADGING_URI
                 = Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_BADGING);
+        private final Uri NOTIFICATION_BUBBLES_URI
+                = Settings.Secure.getUriFor(Settings.Secure.NOTIFICATION_BUBBLES);
         private final Uri NOTIFICATION_LIGHT_PULSE_URI
                 = Settings.System.getUriFor(Settings.System.NOTIFICATION_LIGHT_PULSE);
         private final Uri NOTIFICATION_RATE_LIMIT_URI
@@ -1322,6 +1324,8 @@
                     false, this, UserHandle.USER_ALL);
             resolver.registerContentObserver(NOTIFICATION_RATE_LIMIT_URI,
                     false, this, UserHandle.USER_ALL);
+            resolver.registerContentObserver(NOTIFICATION_BUBBLES_URI,
+                    false, this, UserHandle.USER_ALL);
             update(null);
         }
 
@@ -1347,6 +1351,9 @@
             if (uri == null || NOTIFICATION_BADGING_URI.equals(uri)) {
                 mPreferencesHelper.updateBadgingEnabled();
             }
+            if (uri == null || NOTIFICATION_BUBBLES_URI.equals(uri)) {
+                mPreferencesHelper.updateBubblesEnabled();
+            }
         }
     }
 
@@ -5862,6 +5869,7 @@
             ArrayList<String> orderBefore = new ArrayList<>(N);
             int[] visibilities = new int[N];
             boolean[] showBadges = new boolean[N];
+            boolean[] allowBubbles = new boolean[N];
             ArrayList<NotificationChannel> channelBefore = new ArrayList<>(N);
             ArrayList<String> groupKeyBefore = new ArrayList<>(N);
             ArrayList<ArrayList<String>> overridePeopleBefore = new ArrayList<>(N);
@@ -5876,6 +5884,7 @@
                 orderBefore.add(r.getKey());
                 visibilities[i] = r.getPackageVisibilityOverride();
                 showBadges[i] = r.canShowBadge();
+                allowBubbles[i] = r.canBubble();
                 channelBefore.add(r.getChannel());
                 groupKeyBefore.add(r.getGroupKey());
                 overridePeopleBefore.add(r.getPeopleOverride());
@@ -5893,6 +5902,7 @@
                 if (!orderBefore.get(i).equals(r.getKey())
                         || visibilities[i] != r.getPackageVisibilityOverride()
                         || showBadges[i] != r.canShowBadge()
+                        || allowBubbles[i] != r.canBubble()
                         || !Objects.equals(channelBefore.get(i), r.getChannel())
                         || !Objects.equals(groupKeyBefore.get(i), r.getGroupKey())
                         || !Objects.equals(overridePeopleBefore.get(i), r.getPeopleOverride())
@@ -6935,6 +6945,7 @@
         Bundle smartReplies = new Bundle();
         Bundle lastAudiblyAlerted = new Bundle();
         Bundle noisy = new Bundle();
+        ArrayList<Boolean> canBubble = new ArrayList<>(N);
         for (int i = 0; i < N; i++) {
             NotificationRecord record = mNotificationList.get(i);
             if (!isVisibleToListener(record.sbn, info)) {
@@ -6967,18 +6978,22 @@
             smartReplies.putCharSequenceArrayList(key, record.getSmartReplies());
             lastAudiblyAlerted.putLong(key, record.getLastAudiblyAlertedMs());
             noisy.putBoolean(key, record.getSound() != null || record.getVibration() != null);
+            canBubble.add(record.canBubble());
         }
         final int M = keys.size();
         String[] keysAr = keys.toArray(new String[M]);
         String[] interceptedKeysAr = interceptedKeys.toArray(new String[interceptedKeys.size()]);
         int[] importanceAr = new int[M];
+        boolean[] canBubbleAr = new boolean[M];
         for (int i = 0; i < M; i++) {
             importanceAr[i] = importance.get(i);
+            canBubbleAr[i] = canBubble.get(i);
         }
         return new NotificationRankingUpdate(keysAr, interceptedKeysAr, visibilityOverrides,
                 suppressedVisualEffects, importanceAr, explanation, overrideGroupKeys,
                 channels, overridePeople, snoozeCriteria, showBadge, userSentiment, hidden,
-                systemGeneratedSmartActions, smartReplies, lastAudiblyAlerted, noisy);
+                systemGeneratedSmartActions, smartReplies, lastAudiblyAlerted, noisy,
+                canBubbleAr);
     }
 
     boolean hasCompanionDevice(ManagedServiceInfo info) {
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index b3394b4..48818f5 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -161,6 +161,7 @@
     private ArrayList<String> mPeopleOverride;
     private ArrayList<SnoozeCriterion> mSnoozeCriteria;
     private boolean mShowBadge;
+    private boolean mAllowBubble;
     private Light mLight;
     /**
      * This list contains system generated smart actions from NAS, app-generated smart actions are
@@ -994,6 +995,14 @@
         mShowBadge = showBadge;
     }
 
+    public boolean canBubble() {
+        return mAllowBubble;
+    }
+
+    public void setAllowBubble(boolean allow) {
+        mAllowBubble = allow;
+    }
+
     public boolean canShowBadge() {
         return mShowBadge;
     }
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 5555936..2c47ec0 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -127,6 +127,7 @@
     private final ZenModeHelper mZenModeHelper;
 
     private SparseBooleanArray mBadgingEnabled;
+    private SparseBooleanArray mBubblesEnabled;
     private boolean mAreChannelsBypassingDnd;
     private boolean mHideSilentStatusBarIcons;
 
@@ -138,6 +139,7 @@
         mPm = pm;
 
         updateBadgingEnabled();
+        updateBubblesEnabled();
         syncChannelsBypassingDnd(mContext.getUserId());
     }
 
@@ -486,6 +488,7 @@
      * @param uid the uid to check if bubbles are allowed for.
      * @return whether bubbles are allowed.
      */
+    @Override
     public boolean areBubblesAllowed(String pkg, int uid) {
         return getOrCreatePackagePreferences(pkg, uid).allowBubble;
     }
@@ -1267,7 +1270,7 @@
         if (original.canShowBadge() != update.canShowBadge()) {
             update.lockFields(NotificationChannel.USER_LOCKED_SHOW_BADGE);
         }
-        if (original.isBubbleAllowed() != update.isBubbleAllowed()) {
+        if (original.canBubble() != update.canBubble()) {
             update.lockFields(NotificationChannel.USER_LOCKED_ALLOW_BUBBLE);
         }
     }
@@ -1639,6 +1642,40 @@
                 .setPackageName(pkg);
     }
 
+    public void updateBubblesEnabled() {
+        if (mBubblesEnabled == null) {
+            mBubblesEnabled = new SparseBooleanArray();
+        }
+        boolean changed = false;
+        // update the cached values
+        for (int index = 0; index < mBubblesEnabled.size(); index++) {
+            int userId = mBubblesEnabled.keyAt(index);
+            final boolean oldValue = mBubblesEnabled.get(userId);
+            final boolean newValue = Settings.Secure.getIntForUser(mContext.getContentResolver(),
+                    Settings.Secure.NOTIFICATION_BUBBLES,
+                    DEFAULT_ALLOW_BUBBLE ? 1 : 0, userId) != 0;
+            mBubblesEnabled.put(userId, newValue);
+            changed |= oldValue != newValue;
+        }
+        if (changed) {
+            updateConfig();
+        }
+    }
+
+    public boolean bubblesEnabled(UserHandle userHandle) {
+        int userId = userHandle.getIdentifier();
+        if (userId == UserHandle.USER_ALL) {
+            return false;
+        }
+        if (mBubblesEnabled.indexOfKey(userId) < 0) {
+            mBubblesEnabled.put(userId,
+                    Settings.Secure.getIntForUser(mContext.getContentResolver(),
+                            Settings.Secure.NOTIFICATION_BUBBLES,
+                            DEFAULT_ALLOW_BUBBLE ? 1 : 0, userId) != 0);
+        }
+        return mBubblesEnabled.get(userId, DEFAULT_ALLOW_BUBBLE);
+    }
+
 
     public void updateBadgingEnabled() {
         if (mBadgingEnabled == null) {
diff --git a/services/core/java/com/android/server/notification/RankingConfig.java b/services/core/java/com/android/server/notification/RankingConfig.java
index 605348b..72502acd 100644
--- a/services/core/java/com/android/server/notification/RankingConfig.java
+++ b/services/core/java/com/android/server/notification/RankingConfig.java
@@ -29,6 +29,8 @@
     void setShowBadge(String packageName, int uid, boolean showBadge);
     boolean canShowBadge(String packageName, int uid);
     boolean badgingEnabled(UserHandle userHandle);
+    boolean areBubblesAllowed(String packageName, int uid);
+    boolean bubblesEnabled(UserHandle userHandle);
     boolean isGroupBlocked(String packageName, int uid, String groupId);
 
     Collection<NotificationChannelGroup> getNotificationChannelGroups(String pkg,
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index a7f1146..e479a15 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -23,6 +23,9 @@
 import static android.content.Intent.ACTION_USER_ADDED;
 import static android.content.Intent.ACTION_USER_REMOVED;
 import static android.content.pm.PackageManager.SIGNATURE_MATCH;
+import static android.os.Trace.TRACE_TAG_RRO;
+import static android.os.Trace.traceBegin;
+import static android.os.Trace.traceEnd;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -223,36 +226,41 @@
     public OverlayManagerService(@NonNull final Context context,
             @NonNull final Installer installer) {
         super(context);
-        mSettingsFile = new AtomicFile(
-                new File(Environment.getDataSystemDirectory(), "overlays.xml"), "overlays");
-        mPackageManager = new PackageManagerHelper();
-        mUserManager = UserManagerService.getInstance();
-        IdmapManager im = new IdmapManager(installer);
-        mSettings = new OverlayManagerSettings();
-        mImpl = new OverlayManagerServiceImpl(mPackageManager, im, mSettings,
-                getDefaultOverlayPackages(), new OverlayChangeListener());
+        try {
+            traceBegin(TRACE_TAG_RRO, "OMS#OverlayManagerService");
+            mSettingsFile = new AtomicFile(
+                    new File(Environment.getDataSystemDirectory(), "overlays.xml"), "overlays");
+            mPackageManager = new PackageManagerHelper();
+            mUserManager = UserManagerService.getInstance();
+            IdmapManager im = new IdmapManager(installer);
+            mSettings = new OverlayManagerSettings();
+            mImpl = new OverlayManagerServiceImpl(mPackageManager, im, mSettings,
+                    getDefaultOverlayPackages(), new OverlayChangeListener());
 
-        final IntentFilter packageFilter = new IntentFilter();
-        packageFilter.addAction(ACTION_PACKAGE_ADDED);
-        packageFilter.addAction(ACTION_PACKAGE_CHANGED);
-        packageFilter.addAction(ACTION_PACKAGE_REMOVED);
-        packageFilter.addDataScheme("package");
-        getContext().registerReceiverAsUser(new PackageReceiver(), UserHandle.ALL,
-                packageFilter, null, null);
+            final IntentFilter packageFilter = new IntentFilter();
+            packageFilter.addAction(ACTION_PACKAGE_ADDED);
+            packageFilter.addAction(ACTION_PACKAGE_CHANGED);
+            packageFilter.addAction(ACTION_PACKAGE_REMOVED);
+            packageFilter.addDataScheme("package");
+            getContext().registerReceiverAsUser(new PackageReceiver(), UserHandle.ALL,
+                    packageFilter, null, null);
 
-        final IntentFilter userFilter = new IntentFilter();
-        userFilter.addAction(ACTION_USER_ADDED);
-        userFilter.addAction(ACTION_USER_REMOVED);
-        getContext().registerReceiverAsUser(new UserReceiver(), UserHandle.ALL,
-                userFilter, null, null);
+            final IntentFilter userFilter = new IntentFilter();
+            userFilter.addAction(ACTION_USER_ADDED);
+            userFilter.addAction(ACTION_USER_REMOVED);
+            getContext().registerReceiverAsUser(new UserReceiver(), UserHandle.ALL,
+                    userFilter, null, null);
 
-        restoreSettings();
+            restoreSettings();
 
-        initIfNeeded();
-        onSwitchUser(UserHandle.USER_SYSTEM);
+            initIfNeeded();
+            onSwitchUser(UserHandle.USER_SYSTEM);
 
-        publishBinderService(Context.OVERLAY_SERVICE, mService);
-        publishLocalService(OverlayManagerService.class, this);
+            publishBinderService(Context.OVERLAY_SERVICE, mService);
+            publishLocalService(OverlayManagerService.class, this);
+        } finally {
+            traceEnd(TRACE_TAG_RRO);
+        }
     }
 
     @Override
@@ -280,13 +288,18 @@
 
     @Override
     public void onSwitchUser(final int newUserId) {
-        // ensure overlays in the settings are up-to-date, and propagate
-        // any asset changes to the rest of the system
-        synchronized (mLock) {
-            final List<String> targets = mImpl.updateOverlaysForUser(newUserId);
-            updateAssets(newUserId, targets);
+        try {
+            traceBegin(TRACE_TAG_RRO, "OMS#onSwitchUser " + newUserId);
+            // ensure overlays in the settings are up-to-date, and propagate
+            // any asset changes to the rest of the system
+            synchronized (mLock) {
+                final List<String> targets = mImpl.updateOverlaysForUser(newUserId);
+                updateAssets(newUserId, targets);
+            }
+            schedulePersistSettings();
+        } finally {
+            traceEnd(TRACE_TAG_RRO);
         }
-        schedulePersistSettings();
     }
 
     private static String[] getDefaultOverlayPackages() {
@@ -350,85 +363,110 @@
 
         private void onPackageAdded(@NonNull final String packageName,
                 @NonNull final int[] userIds) {
-            for (final int userId : userIds) {
-                synchronized (mLock) {
-                    final PackageInfo pi = mPackageManager.getPackageInfo(packageName, userId,
-                            false);
-                    if (pi != null) {
-                        mPackageManager.cachePackageInfo(packageName, userId, pi);
-                        if (pi.isOverlayPackage()) {
-                            mImpl.onOverlayPackageAdded(packageName, userId);
-                        } else {
-                            mImpl.onTargetPackageAdded(packageName, userId);
+            try {
+                traceBegin(TRACE_TAG_RRO, "OMS#onPackageAdded " + packageName);
+                for (final int userId : userIds) {
+                    synchronized (mLock) {
+                        final PackageInfo pi = mPackageManager.getPackageInfo(packageName, userId,
+                                false);
+                        if (pi != null) {
+                            mPackageManager.cachePackageInfo(packageName, userId, pi);
+                            if (pi.isOverlayPackage()) {
+                                mImpl.onOverlayPackageAdded(packageName, userId);
+                            } else {
+                                mImpl.onTargetPackageAdded(packageName, userId);
+                            }
                         }
                     }
                 }
+            } finally {
+                traceEnd(TRACE_TAG_RRO);
             }
         }
 
         private void onPackageChanged(@NonNull final String packageName,
                 @NonNull final int[] userIds) {
-            for (int userId : userIds) {
-                synchronized (mLock) {
-                    final PackageInfo pi = mPackageManager.getPackageInfo(packageName, userId,
-                            false);
-                    if (pi != null) {
-                        mPackageManager.cachePackageInfo(packageName, userId, pi);
-                        if (pi.isOverlayPackage()) {
-                            mImpl.onOverlayPackageChanged(packageName, userId);
-                        }  else {
-                            mImpl.onTargetPackageChanged(packageName, userId);
+            try {
+                traceBegin(TRACE_TAG_RRO, "OMS#onPackageChanged " + packageName);
+                for (int userId : userIds) {
+                    synchronized (mLock) {
+                        final PackageInfo pi = mPackageManager.getPackageInfo(packageName, userId,
+                                false);
+                        if (pi != null) {
+                            mPackageManager.cachePackageInfo(packageName, userId, pi);
+                            if (pi.isOverlayPackage()) {
+                                mImpl.onOverlayPackageChanged(packageName, userId);
+                            }  else {
+                                mImpl.onTargetPackageChanged(packageName, userId);
+                            }
                         }
                     }
                 }
+            } finally {
+                traceEnd(TRACE_TAG_RRO);
             }
         }
 
         private void onPackageUpgrading(@NonNull final String packageName,
                 @NonNull final int[] userIds) {
-            for (int userId : userIds) {
-                synchronized (mLock) {
-                    mPackageManager.forgetPackageInfo(packageName, userId);
-                    final OverlayInfo oi = mImpl.getOverlayInfo(packageName, userId);
-                    if (oi != null) {
-                        mImpl.onOverlayPackageUpgrading(packageName, userId);
-                    } else {
-                        mImpl.onTargetPackageUpgrading(packageName, userId);
+            try {
+                traceBegin(TRACE_TAG_RRO, "OMS#onPackageUpgrading " + packageName);
+                for (int userId : userIds) {
+                    synchronized (mLock) {
+                        mPackageManager.forgetPackageInfo(packageName, userId);
+                        final OverlayInfo oi = mImpl.getOverlayInfo(packageName, userId);
+                        if (oi != null) {
+                            mImpl.onOverlayPackageUpgrading(packageName, userId);
+                        } else {
+                            mImpl.onTargetPackageUpgrading(packageName, userId);
+                        }
                     }
                 }
+            } finally {
+                traceEnd(TRACE_TAG_RRO);
             }
         }
 
         private void onPackageUpgraded(@NonNull final String packageName,
                 @NonNull final int[] userIds) {
-            for (int userId : userIds) {
-                synchronized (mLock) {
-                    final PackageInfo pi = mPackageManager.getPackageInfo(packageName, userId,
-                            false);
-                    if (pi != null) {
-                        mPackageManager.cachePackageInfo(packageName, userId, pi);
-                        if (pi.isOverlayPackage()) {
-                            mImpl.onOverlayPackageUpgraded(packageName, userId);
-                        } else {
-                            mImpl.onTargetPackageUpgraded(packageName, userId);
+            try {
+                traceBegin(TRACE_TAG_RRO, "OMS#onPackageUpgraded " + packageName);
+                for (int userId : userIds) {
+                    synchronized (mLock) {
+                        final PackageInfo pi = mPackageManager.getPackageInfo(packageName, userId,
+                                false);
+                        if (pi != null) {
+                            mPackageManager.cachePackageInfo(packageName, userId, pi);
+                            if (pi.isOverlayPackage()) {
+                                mImpl.onOverlayPackageUpgraded(packageName, userId);
+                            } else {
+                                mImpl.onTargetPackageUpgraded(packageName, userId);
+                            }
                         }
                     }
                 }
+            } finally {
+                traceEnd(TRACE_TAG_RRO);
             }
         }
 
         private void onPackageRemoved(@NonNull final String packageName,
                 @NonNull final int[] userIds) {
-            for (int userId : userIds) {
-                synchronized (mLock) {
-                    mPackageManager.forgetPackageInfo(packageName, userId);
-                    final OverlayInfo oi = mImpl.getOverlayInfo(packageName, userId);
-                    if (oi != null) {
-                        mImpl.onOverlayPackageRemoved(packageName, userId);
-                    } else {
-                        mImpl.onTargetPackageRemoved(packageName, userId);
+            try {
+                traceBegin(TRACE_TAG_RRO, "OMS#onPackageRemoved " + packageName);
+                for (int userId : userIds) {
+                    synchronized (mLock) {
+                        mPackageManager.forgetPackageInfo(packageName, userId);
+                        final OverlayInfo oi = mImpl.getOverlayInfo(packageName, userId);
+                        if (oi != null) {
+                            mImpl.onOverlayPackageRemoved(packageName, userId);
+                        } else {
+                            mImpl.onTargetPackageRemoved(packageName, userId);
+                        }
                     }
                 }
+            } finally {
+                traceEnd(TRACE_TAG_RRO);
             }
         }
     }
@@ -440,19 +478,29 @@
             switch (intent.getAction()) {
                 case ACTION_USER_ADDED:
                     if (userId != UserHandle.USER_NULL) {
-                        final ArrayList<String> targets;
-                        synchronized (mLock) {
-                            targets = mImpl.updateOverlaysForUser(userId);
+                        try {
+                            traceBegin(TRACE_TAG_RRO, "OMS ACTION_USER_ADDED");
+                            final ArrayList<String> targets;
+                            synchronized (mLock) {
+                                targets = mImpl.updateOverlaysForUser(userId);
+                            }
+                            updateOverlayPaths(userId, targets);
+                        } finally {
+                            traceEnd(TRACE_TAG_RRO);
                         }
-                        updateOverlayPaths(userId, targets);
                     }
                     break;
 
                 case ACTION_USER_REMOVED:
                     if (userId != UserHandle.USER_NULL) {
-                        synchronized (mLock) {
-                            mImpl.onUserRemoved(userId);
-                            mPackageManager.forgetAllPackageInfos(userId);
+                        try {
+                            traceBegin(TRACE_TAG_RRO, "OMS ACTION_USER_REMOVED");
+                            synchronized (mLock) {
+                                mImpl.onUserRemoved(userId);
+                                mPackageManager.forgetAllPackageInfos(userId);
+                            }
+                        } finally {
+                            traceEnd(TRACE_TAG_RRO);
                         }
                     }
                     break;
@@ -466,152 +514,198 @@
     private final IBinder mService = new IOverlayManager.Stub() {
         @Override
         public Map<String, List<OverlayInfo>> getAllOverlays(int userId) throws RemoteException {
-            userId = handleIncomingUser(userId, "getAllOverlays");
+            try {
+                traceBegin(TRACE_TAG_RRO, "OMS#getAllOverlays " + userId);
+                userId = handleIncomingUser(userId, "getAllOverlays");
 
-            synchronized (mLock) {
-                return mImpl.getOverlaysForUser(userId);
+                synchronized (mLock) {
+                    return mImpl.getOverlaysForUser(userId);
+                }
+            } finally {
+                traceEnd(TRACE_TAG_RRO);
             }
         }
 
         @Override
         public List<OverlayInfo> getOverlayInfosForTarget(@Nullable final String targetPackageName,
                 int userId) throws RemoteException {
-            userId = handleIncomingUser(userId, "getOverlayInfosForTarget");
-            if (targetPackageName == null) {
-                return Collections.emptyList();
-            }
+            try {
+                traceBegin(TRACE_TAG_RRO, "OMS#getOverlayInfosForTarget " + targetPackageName);
+                userId = handleIncomingUser(userId, "getOverlayInfosForTarget");
+                if (targetPackageName == null) {
+                    return Collections.emptyList();
+                }
 
-            synchronized (mLock) {
-                return mImpl.getOverlayInfosForTarget(targetPackageName, userId);
+                synchronized (mLock) {
+                    return mImpl.getOverlayInfosForTarget(targetPackageName, userId);
+                }
+            } finally {
+                traceEnd(TRACE_TAG_RRO);
             }
         }
 
         @Override
         public OverlayInfo getOverlayInfo(@Nullable final String packageName,
                 int userId) throws RemoteException {
-            userId = handleIncomingUser(userId, "getOverlayInfo");
-            if (packageName == null) {
-                return null;
-            }
+            try {
+                traceBegin(TRACE_TAG_RRO, "OMS#getOverlayInfo " + packageName);
+                userId = handleIncomingUser(userId, "getOverlayInfo");
+                if (packageName == null) {
+                    return null;
+                }
 
-            synchronized (mLock) {
-                return mImpl.getOverlayInfo(packageName, userId);
+                synchronized (mLock) {
+                    return mImpl.getOverlayInfo(packageName, userId);
+                }
+            } finally {
+                traceEnd(TRACE_TAG_RRO);
             }
         }
 
         @Override
         public boolean setEnabled(@Nullable final String packageName, final boolean enable,
                 int userId) throws RemoteException {
-            enforceChangeOverlayPackagesPermission("setEnabled");
-            userId = handleIncomingUser(userId, "setEnabled");
-            if (packageName == null) {
-                return false;
-            }
-
-            final long ident = Binder.clearCallingIdentity();
             try {
-                synchronized (mLock) {
-                    return mImpl.setEnabled(packageName, enable, userId);
+                traceBegin(TRACE_TAG_RRO, "OMS#setEnabled " + packageName + " " + enable);
+                enforceChangeOverlayPackagesPermission("setEnabled");
+                userId = handleIncomingUser(userId, "setEnabled");
+                if (packageName == null) {
+                    return false;
+                }
+
+                final long ident = Binder.clearCallingIdentity();
+                try {
+                    synchronized (mLock) {
+                        return mImpl.setEnabled(packageName, enable, userId);
+                    }
+                } finally {
+                    Binder.restoreCallingIdentity(ident);
                 }
             } finally {
-                Binder.restoreCallingIdentity(ident);
+                traceEnd(TRACE_TAG_RRO);
             }
         }
 
         @Override
         public boolean setEnabledExclusive(@Nullable final String packageName, final boolean enable,
                 int userId) throws RemoteException {
-            enforceChangeOverlayPackagesPermission("setEnabledExclusive");
-            userId = handleIncomingUser(userId, "setEnabledExclusive");
-            if (packageName == null || !enable) {
-                return false;
-            }
-
-            final long ident = Binder.clearCallingIdentity();
             try {
-                synchronized (mLock) {
-                    return mImpl.setEnabledExclusive(packageName, false /* withinCategory */,
-                            userId);
+                traceBegin(TRACE_TAG_RRO, "OMS#setEnabledExclusive " + packageName + " " + enable);
+                enforceChangeOverlayPackagesPermission("setEnabledExclusive");
+                userId = handleIncomingUser(userId, "setEnabledExclusive");
+                if (packageName == null || !enable) {
+                    return false;
+                }
+
+                final long ident = Binder.clearCallingIdentity();
+                try {
+                    synchronized (mLock) {
+                        return mImpl.setEnabledExclusive(packageName, false /* withinCategory */,
+                                userId);
+                    }
+                } finally {
+                    Binder.restoreCallingIdentity(ident);
                 }
             } finally {
-                Binder.restoreCallingIdentity(ident);
+                traceEnd(TRACE_TAG_RRO);
             }
         }
 
         @Override
         public boolean setEnabledExclusiveInCategory(@Nullable String packageName, int userId)
                 throws RemoteException {
-            enforceChangeOverlayPackagesPermission("setEnabledExclusiveInCategory");
-            userId = handleIncomingUser(userId, "setEnabledExclusiveInCategory");
-            if (packageName == null) {
-                return false;
-            }
-
-            final long ident = Binder.clearCallingIdentity();
             try {
-                synchronized (mLock) {
-                    return mImpl.setEnabledExclusive(packageName, true /* withinCategory */,
-                            userId);
+                traceBegin(TRACE_TAG_RRO, "OMS#setEnabledExclusiveInCategory " + packageName);
+                enforceChangeOverlayPackagesPermission("setEnabledExclusiveInCategory");
+                userId = handleIncomingUser(userId, "setEnabledExclusiveInCategory");
+                if (packageName == null) {
+                    return false;
+                }
+
+                final long ident = Binder.clearCallingIdentity();
+                try {
+                    synchronized (mLock) {
+                        return mImpl.setEnabledExclusive(packageName, true /* withinCategory */,
+                                userId);
+                    }
+                } finally {
+                    Binder.restoreCallingIdentity(ident);
                 }
             } finally {
-                Binder.restoreCallingIdentity(ident);
+                traceEnd(TRACE_TAG_RRO);
             }
         }
 
         @Override
         public boolean setPriority(@Nullable final String packageName,
                 @Nullable final String parentPackageName, int userId) throws RemoteException {
-            enforceChangeOverlayPackagesPermission("setPriority");
-            userId = handleIncomingUser(userId, "setPriority");
-            if (packageName == null || parentPackageName == null) {
-                return false;
-            }
-
-            final long ident = Binder.clearCallingIdentity();
             try {
-                synchronized (mLock) {
-                    return mImpl.setPriority(packageName, parentPackageName, userId);
+                traceBegin(TRACE_TAG_RRO, "OMS#setPriority " + packageName + " "
+                        + parentPackageName);
+                enforceChangeOverlayPackagesPermission("setPriority");
+                userId = handleIncomingUser(userId, "setPriority");
+                if (packageName == null || parentPackageName == null) {
+                    return false;
+                }
+
+                final long ident = Binder.clearCallingIdentity();
+                try {
+                    synchronized (mLock) {
+                        return mImpl.setPriority(packageName, parentPackageName, userId);
+                    }
+                } finally {
+                    Binder.restoreCallingIdentity(ident);
                 }
             } finally {
-                Binder.restoreCallingIdentity(ident);
+                traceEnd(TRACE_TAG_RRO);
             }
         }
 
         @Override
         public boolean setHighestPriority(@Nullable final String packageName, int userId)
                 throws RemoteException {
-            enforceChangeOverlayPackagesPermission("setHighestPriority");
-            userId = handleIncomingUser(userId, "setHighestPriority");
-            if (packageName == null) {
-                return false;
-            }
-
-            final long ident = Binder.clearCallingIdentity();
             try {
-                synchronized (mLock) {
-                    return mImpl.setHighestPriority(packageName, userId);
+                traceBegin(TRACE_TAG_RRO, "OMS#setHighestPriority " + packageName);
+                enforceChangeOverlayPackagesPermission("setHighestPriority");
+                userId = handleIncomingUser(userId, "setHighestPriority");
+                if (packageName == null) {
+                    return false;
+                }
+
+                final long ident = Binder.clearCallingIdentity();
+                try {
+                    synchronized (mLock) {
+                        return mImpl.setHighestPriority(packageName, userId);
+                    }
+                } finally {
+                    Binder.restoreCallingIdentity(ident);
                 }
             } finally {
-                Binder.restoreCallingIdentity(ident);
+                traceEnd(TRACE_TAG_RRO);
             }
         }
 
         @Override
         public boolean setLowestPriority(@Nullable final String packageName, int userId)
                 throws RemoteException {
-            enforceChangeOverlayPackagesPermission("setLowestPriority");
-            userId = handleIncomingUser(userId, "setLowestPriority");
-            if (packageName == null) {
-                return false;
-            }
-
-            final long ident = Binder.clearCallingIdentity();
             try {
-                synchronized (mLock) {
-                    return mImpl.setLowestPriority(packageName, userId);
+                traceBegin(TRACE_TAG_RRO, "OMS#setLowestPriority " + packageName);
+                enforceChangeOverlayPackagesPermission("setLowestPriority");
+                userId = handleIncomingUser(userId, "setLowestPriority");
+                if (packageName == null) {
+                    return false;
+                }
+
+                final long ident = Binder.clearCallingIdentity();
+                try {
+                    synchronized (mLock) {
+                        return mImpl.setLowestPriority(packageName, userId);
+                    }
+                } finally {
+                    Binder.restoreCallingIdentity(ident);
                 }
             } finally {
-                Binder.restoreCallingIdentity(ident);
+                traceEnd(TRACE_TAG_RRO);
             }
         }
 
@@ -705,45 +799,52 @@
      * Updates the target packages' set of enabled overlays in PackageManager.
      */
     private void updateOverlayPaths(int userId, List<String> targetPackageNames) {
-        if (DEBUG) {
-            Slog.d(TAG, "Updating overlay assets");
-        }
-        final PackageManagerInternal pm = LocalServices.getService(PackageManagerInternal.class);
-        final boolean updateFrameworkRes = targetPackageNames.contains("android");
-        if (updateFrameworkRes) {
-            targetPackageNames = pm.getTargetPackageNames(userId);
-        }
+        try {
+            traceBegin(TRACE_TAG_RRO, "OMS#updateOverlayPaths " + targetPackageNames);
+            if (DEBUG) {
+                Slog.d(TAG, "Updating overlay assets");
+            }
+            final PackageManagerInternal pm =
+                    LocalServices.getService(PackageManagerInternal.class);
+            final boolean updateFrameworkRes = targetPackageNames.contains("android");
+            if (updateFrameworkRes) {
+                targetPackageNames = pm.getTargetPackageNames(userId);
+            }
 
-        final Map<String, List<String>> pendingChanges = new ArrayMap<>(targetPackageNames.size());
-        synchronized (mLock) {
-            final List<String> frameworkOverlays =
-                    mImpl.getEnabledOverlayPackageNames("android", userId);
+            final Map<String, List<String>> pendingChanges =
+                    new ArrayMap<>(targetPackageNames.size());
+            synchronized (mLock) {
+                final List<String> frameworkOverlays =
+                        mImpl.getEnabledOverlayPackageNames("android", userId);
+                final int n = targetPackageNames.size();
+                for (int i = 0; i < n; i++) {
+                    final String targetPackageName = targetPackageNames.get(i);
+                    List<String> list = new ArrayList<>();
+                    if (!"android".equals(targetPackageName)) {
+                        list.addAll(frameworkOverlays);
+                    }
+                    list.addAll(mImpl.getEnabledOverlayPackageNames(targetPackageName, userId));
+                    pendingChanges.put(targetPackageName, list);
+                }
+            }
+
             final int n = targetPackageNames.size();
             for (int i = 0; i < n; i++) {
                 final String targetPackageName = targetPackageNames.get(i);
-                List<String> list = new ArrayList<>();
-                if (!"android".equals(targetPackageName)) {
-                    list.addAll(frameworkOverlays);
+                if (DEBUG) {
+                    Slog.d(TAG, "-> Updating overlay: target=" + targetPackageName + " overlays=["
+                            + TextUtils.join(",", pendingChanges.get(targetPackageName))
+                            + "] userId=" + userId);
                 }
-                list.addAll(mImpl.getEnabledOverlayPackageNames(targetPackageName, userId));
-                pendingChanges.put(targetPackageName, list);
-            }
-        }
 
-        final int n = targetPackageNames.size();
-        for (int i = 0; i < n; i++) {
-            final String targetPackageName = targetPackageNames.get(i);
-            if (DEBUG) {
-                Slog.d(TAG, "-> Updating overlay: target=" + targetPackageName + " overlays=["
-                        + TextUtils.join(",", pendingChanges.get(targetPackageName))
-                        + "] userId=" + userId);
+                if (!pm.setEnabledOverlayPackages(
+                        userId, targetPackageName, pendingChanges.get(targetPackageName))) {
+                    Slog.e(TAG, String.format("Failed to change enabled overlays for %s user %d",
+                            targetPackageName, userId));
+                }
             }
-
-            if (!pm.setEnabledOverlayPackages(
-                    userId, targetPackageName, pendingChanges.get(targetPackageName))) {
-                Slog.e(TAG, String.format("Failed to change enabled overlays for %s user %d",
-                        targetPackageName, userId));
-            }
+        } finally {
+            traceEnd(TRACE_TAG_RRO);
         }
     }
 
@@ -785,32 +886,37 @@
     }
 
     private void restoreSettings() {
-        synchronized (mLock) {
-            if (!mSettingsFile.getBaseFile().exists()) {
-                return;
-            }
-            try (FileInputStream stream = mSettingsFile.openRead()) {
-                mSettings.restore(stream);
-
-                // We might have data for dying users if the device was
-                // restarted before we received USER_REMOVED. Remove data for
-                // users that will not exist after the system is ready.
-
-                final List<UserInfo> liveUsers = mUserManager.getUsers(true /*excludeDying*/);
-                final int[] liveUserIds = new int[liveUsers.size()];
-                for (int i = 0; i < liveUsers.size(); i++) {
-                    liveUserIds[i] = liveUsers.get(i).getUserHandle().getIdentifier();
+        try {
+            traceBegin(TRACE_TAG_RRO, "OMS#restoreSettings");
+            synchronized (mLock) {
+                if (!mSettingsFile.getBaseFile().exists()) {
+                    return;
                 }
-                Arrays.sort(liveUserIds);
+                try (FileInputStream stream = mSettingsFile.openRead()) {
+                    mSettings.restore(stream);
 
-                for (int userId : mSettings.getUsers()) {
-                    if (Arrays.binarySearch(liveUserIds, userId) < 0) {
-                        mSettings.removeUser(userId);
+                    // We might have data for dying users if the device was
+                    // restarted before we received USER_REMOVED. Remove data for
+                    // users that will not exist after the system is ready.
+
+                    final List<UserInfo> liveUsers = mUserManager.getUsers(true /*excludeDying*/);
+                    final int[] liveUserIds = new int[liveUsers.size()];
+                    for (int i = 0; i < liveUsers.size(); i++) {
+                        liveUserIds[i] = liveUsers.get(i).getUserHandle().getIdentifier();
                     }
+                    Arrays.sort(liveUserIds);
+
+                    for (int userId : mSettings.getUsers()) {
+                        if (Arrays.binarySearch(liveUserIds, userId) < 0) {
+                            mSettings.removeUser(userId);
+                        }
+                    }
+                } catch (IOException | XmlPullParserException e) {
+                    Slog.e(TAG, "failed to restore overlay state", e);
                 }
-            } catch (IOException | XmlPullParserException e) {
-                Slog.e(TAG, "failed to restore overlay state", e);
             }
+        } finally {
+            traceEnd(TRACE_TAG_RRO);
         }
     }
 
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index efafdfa..c2a75ab 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -611,18 +611,43 @@
         }
     }
 
-    public boolean snapshotAppData(String pkg, @UserIdInt int userId, int storageFlags)
+    /**
+     * Snapshots user data of the given package.
+     *
+     * @param pkg name of the package to snapshot user data for.
+     * @param userId id of the user whose data to snapshot.
+     * @param storageFlags flags controlling which data (CE or DE) to snapshot.
+     *
+     * @return inode of the snapshot of users CE package data, or {@code 0} if a remote calls
+     *  shouldn't be continued. See {@link #checkBeforeRemote}.
+     *
+     * @throws InstallerException if failed to snapshot user data.
+     */
+    public long snapshotAppData(String pkg, @UserIdInt int userId, int storageFlags)
             throws InstallerException {
-        if (!checkBeforeRemote()) return false;
+        if (!checkBeforeRemote()) return 0;
 
         try {
-            mInstalld.snapshotAppData(null, pkg, userId, storageFlags);
-            return true;
+            return mInstalld.snapshotAppData(null, pkg, userId, storageFlags);
         } catch (Exception e) {
             throw InstallerException.from(e);
         }
     }
 
+    /**
+     * Restores user data snapshot of the given package.
+     *
+     * @param pkg name of the package to restore user data for.
+     * @param appId id of the package to restore user data for.
+     * @param ceDataInode inode of CE user data folder of this app.
+     * @param userId id of the user whose data to restore.
+     * @param storageFlags flags controlling which data (CE or DE) to restore.
+     *
+     * @return {@code true} if user data restore was successful, or {@code false} if a remote call
+     *  shouldn't be continued. See {@link #checkBeforeRemote}.
+     *
+     * @throws InstallerException if failed to restore user data.
+     */
     public boolean restoreAppDataSnapshot(String pkg, @AppIdInt  int appId, long ceDataInode,
             String seInfo, @UserIdInt int userId, int storageFlags) throws InstallerException {
         if (!checkBeforeRemote()) return false;
@@ -636,6 +661,31 @@
         }
     }
 
+    /**
+     * Deletes user data snapshot of the given package.
+     *
+     * @param pkg name of the package to delete user data snapshot for.
+     * @param userId id of the user whose user data snapshot to delete.
+     * @param ceSnapshotInode inode of CE user data snapshot.
+     * @param storageFlags flags controlling which user data snapshot (CE or DE) to delete.
+     *
+     * @return {@code true} if user data snapshot was successfully deleted, or {@code false} if a
+     *  remote call shouldn't be continued. See {@link #checkBeforeRemote}.
+     *
+     * @throws InstallerException if failed to delete user data snapshot.
+     */
+    public boolean destroyAppDataSnapshot(String pkg, @UserIdInt int userId, long ceSnapshotInode,
+            int storageFlags) throws InstallerException {
+        if (!checkBeforeRemote()) return false;
+
+        try {
+            mInstalld.destroyAppDataSnapshot(null, pkg, userId, ceSnapshotInode, storageFlags);
+            return true;
+        } catch (Exception e) {
+            throw InstallerException.from(e);
+        }
+    }
+
     private static void assertValidInstructionSet(String instructionSet)
             throws InstallerException {
         for (String abi : Build.SUPPORTED_ABIS) {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index d06fc51..1b71904 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -44,7 +44,6 @@
 import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.apex.IApexService;
 import android.app.admin.DevicePolicyManagerInternal;
 import android.content.Context;
 import android.content.IIntentReceiver;
@@ -80,7 +79,6 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.RevocableFileDescriptor;
-import android.os.ServiceManager;
 import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.os.storage.StorageManager;
@@ -1084,6 +1082,11 @@
             dispatchSessionFinished(PackageManager.INSTALL_SUCCEEDED, "Session staged", null);
             return;
         }
+        if ((params.installFlags & PackageManager.INSTALL_APEX) != 0) {
+            throw new PackageManagerException(
+                PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
+                "APEX packages can only be installed using staged sessions.");
+        }
         final PackageManagerService.ActiveInstallSession committingSession =
                 makeSessionActiveLocked();
         if (committingSession == null) {
@@ -1101,12 +1104,6 @@
                     final PackageManagerService.ActiveInstallSession activeSession =
                             session.makeSessionActiveLocked();
                     if (activeSession != null) {
-                        if ((activeSession.getSessionParams().installFlags
-                                & PackageManager.INSTALL_APEX) != 0) {
-                            throw new PackageManagerException(
-                                    PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
-                                    "Atomic install is not supported for APEX packages.");
-                        }
                         childSessions.add(activeSession);
                     }
                 } catch (PackageManagerException e) {
@@ -1124,27 +1121,7 @@
             }
             mPm.installStage(childSessions);
         } else {
-            if ((params.installFlags & PackageManager.INSTALL_APEX) != 0) {
-                commitApexLocked();
-            } else {
-                mPm.installStage(committingSession);
-            }
-        }
-    }
-
-    @GuardedBy("mLock")
-    private void commitApexLocked() throws PackageManagerException {
-        try {
-            IApexService apex = IApexService.Stub.asInterface(
-                    ServiceManager.getService("apexservice"));
-            apex.stagePackage(mResolvedBaseFile.toString());
-        } catch (Throwable e) {
-            // Convert all exceptions into package manager exceptions as only those are handled
-            // in the code above
-            throw new PackageManagerException(e);
-        } finally {
-            destroyInternal();
-            dispatchSessionFinished(PackageManager.INSTALL_SUCCEEDED, "APEX installed", null);
+            mPm.installStage(committingSession);
         }
     }
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index e18da7f..874d1a7 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -195,7 +195,6 @@
 import android.content.pm.Signature;
 import android.content.pm.SuspendDialogInfo;
 import android.content.pm.UserInfo;
-import android.content.pm.UsesPermissionInfo;
 import android.content.pm.VerifierDeviceIdentity;
 import android.content.pm.VerifierInfo;
 import android.content.pm.VersionedPackage;
@@ -11313,26 +11312,6 @@
                     }
                 }
             }
-
-            // Check permission usage info requirements.
-            if (pkg.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.Q) {
-                for (UsesPermissionInfo upi : pkg.usesPermissionInfos) {
-                    if (!mPermissionManager.isPermissionUsageInfoRequired(upi.getPermission())) {
-                        continue;
-                    }
-                    if (upi.getDataSentOffDevice() == UsesPermissionInfo.USAGE_UNDEFINED
-                            || upi.getDataSharedWithThirdParty()
-                                == UsesPermissionInfo.USAGE_UNDEFINED
-                            || upi.getDataUsedForMonetization()
-                                == UsesPermissionInfo.USAGE_UNDEFINED
-                            || upi.getDataRetention() == UsesPermissionInfo.RETENTION_UNDEFINED) {
-                        // STOPSHIP: Make this throw
-                        Slog.e(TAG, "Package " + pkg.packageName + " does not provide usage "
-                                + "information for permission " + upi.getPermission()
-                                + ". This will be a fatal error in Q.");
-                    }
-                }
-            }
         }
     }
 
@@ -14613,6 +14592,13 @@
                             PACKAGE_MIME_TYPE);
                     enableRollbackIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
 
+                    // Allow the broadcast to be sent before boot complete.
+                    // This is needed when committing the apk part of a staged
+                    // session in early boot. The rollback manager registers
+                    // its receiver early enough during the boot process that
+                    // it will not miss the broadcast.
+                    enableRollbackIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+
                     mContext.sendOrderedBroadcastAsUser(enableRollbackIntent, getUser(),
                             android.Manifest.permission.PACKAGE_ROLLBACK_AGENT,
                             new BroadcastReceiver() {
@@ -16335,7 +16321,6 @@
         final boolean onExternal = args.volumeUuid != null;
         final boolean instantApp = ((installFlags & PackageManager.INSTALL_INSTANT_APP) != 0);
         final boolean fullApp = ((installFlags & PackageManager.INSTALL_FULL_APP) != 0);
-        final boolean forceSdk = ((installFlags & PackageManager.INSTALL_FORCE_SDK) != 0);
         final boolean virtualPreload =
                 ((installFlags & PackageManager.INSTALL_VIRTUAL_PRELOAD) != 0);
         @ScanFlags int scanFlags = SCAN_NEW_INSTALL | SCAN_UPDATE_SIGNATURE;
@@ -16367,8 +16352,7 @@
         // Retrieve PackageSettings and parse package
         @ParseFlags final int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY
                 | PackageParser.PARSE_ENFORCE_CODE
-                | (onExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 0)
-                | (forceSdk ? PackageParser.PARSE_FORCE_SDK : 0);
+                | (onExternal ? PackageParser.PARSE_EXTERNAL_STORAGE : 0);
 
         PackageParser pp = new PackageParser();
         pp.setSeparateProcesses(mSeparateProcesses);
@@ -16789,19 +16773,6 @@
                                 "replacePackageLI: new=" + pkg + ", old=" + oldPackage);
                     }
 
-                    // don't allow upgrade to target a release SDK from a pre-release SDK
-                    final boolean oldTargetsPreRelease = oldPackage.applicationInfo.targetSdkVersion
-                            == Build.VERSION_CODES.CUR_DEVELOPMENT;
-                    final boolean newTargetsPreRelease = pkg.applicationInfo.targetSdkVersion
-                            == Build.VERSION_CODES.CUR_DEVELOPMENT;
-                    if (oldTargetsPreRelease
-                            && !newTargetsPreRelease
-                            && ((parseFlags & PackageParser.PARSE_FORCE_SDK) == 0)) {
-                        Slog.w(TAG, "Can't install package targeting released sdk");
-                        throw new PrepareFailure(
-                                PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE);
-                    }
-
                     ps = mSettings.mPackages.get(pkgName11);
                     disabledPs = mSettings.getDisabledSystemPkgLPr(ps);
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index dc18dfc..2eb762b 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -2383,8 +2383,7 @@
                         sessionParams.volumeUuid = null;
                     }
                     break;
-                case "--force-sdk":
-                    sessionParams.installFlags |= PackageManager.INSTALL_FORCE_SDK;
+                case "--force-sdk": // ignore
                     break;
                 case "--apex":
                     sessionParams.setInstallAsApex();
@@ -2961,8 +2960,6 @@
         pw.println("          0=unknown, 1=admin policy, 2=device restore,");
         pw.println("          3=device setup, 4=user request");
         pw.println("      --force-uuid: force install on to disk volume with given UUID");
-        pw.println("      --force-sdk: allow install even when existing app targets platform");
-        pw.println("          codename but new one targets a final API level");
         pw.println("      --apex: install an .apex file, not an .apk");
         pw.println("");
         pw.println("  install-create [-lrtsfdg] [-i PACKAGE] [--user USER_ID|all|current]");
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 89aea36..fa8360b 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -220,6 +220,7 @@
             session.setStagedSessionFailed(
                     SessionInfo.STAGED_SESSION_VERIFICATION_FAILED,
                     "APEX staging failed, check logcat messages from apexd for more details.");
+            return;
         }
 
         if (apexInfoList.apexInfos != null && apexInfoList.apexInfos.length > 0) {
diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
index 8d64b81..18e292f 100644
--- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
+++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java
@@ -743,6 +743,9 @@
 
             case android.provider.Settings.Global.PRIVATE_DNS_MODE:
             case android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER:
+                if (callingUid == Process.SYSTEM_UID) {
+                    return false;
+                }
                 restriction = UserManager.DISALLOW_CONFIG_PRIVATE_DNS;
                 break;
             default:
diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
index 23705db..9948a3a 100644
--- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java
+++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
@@ -480,10 +480,13 @@
             final String apkPath = pkg.baseCodePath;
             final ApplicationInfo appInfo = pkg.applicationInfo;
             final String outDexFile = appInfo.dataDir + "/code_cache/compiled_view.dex";
-            if (appInfo.isPrivilegedApp() || appInfo.isEmbeddedDexUsed()) {
+            if (appInfo.isPrivilegedApp() || appInfo.isEmbeddedDexUsed()
+                    || appInfo.isDefaultToDeviceProtectedStorage()) {
                 // Privileged apps prefer to load trusted code so they don't use compiled views.
                 // If the app is not privileged but prefers code integrity, also avoid compiling
                 // views.
+                // Also disable the view compiler for protected storage apps since there are
+                // selinux permissions required for writing to user_de.
                 return false;
             }
             Log.i("PackageManager", "Compiling layouts in " + packageName + " (" + apkPath +
diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java
index 2213901..ee6995b 100644
--- a/services/core/java/com/android/server/pm/dex/DexManager.java
+++ b/services/core/java/com/android/server/pm/dex/DexManager.java
@@ -228,8 +228,11 @@
                     continue;
                 }
 
-                mDexLogger.recordDex(loaderUserId, dexPath, searchResult.mOwningPackageName,
-                        loadingAppInfo.packageName);
+                if (!primaryOrSplit) {
+                    // Record loading of a DEX file from an app data directory.
+                    mDexLogger.recordDex(loaderUserId, dexPath, searchResult.mOwningPackageName,
+                            loadingAppInfo.packageName);
+                }
 
                 if (classLoaderContexts != null) {
 
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 173d9a0..1957eb8 100644
--- a/services/core/java/com/android/server/pm/permission/BasePermission.java
+++ b/services/core/java/com/android/server/pm/permission/BasePermission.java
@@ -105,8 +105,6 @@
      */
     private boolean perUser;
 
-    boolean usageInfoRequired;
-
     public BasePermission(String _name, String _sourcePackageName, @PermissionType int _type) {
         name = _name;
         sourcePackageName = _sourcePackageName;
@@ -375,7 +373,6 @@
         }
         if (bp.perm == p) {
             bp.protectionLevel = p.info.protectionLevel;
-            bp.usageInfoRequired = p.info.usageInfoRequired;
         }
         if (PackageManagerService.DEBUG_PACKAGE_SCANNING && r != null) {
             Log.d(TAG, "  Permissions: " + r);
@@ -455,7 +452,6 @@
         permissionInfo.packageName = sourcePackageName;
         permissionInfo.nonLocalizedLabel = name;
         permissionInfo.protectionLevel = protectionLevel;
-        permissionInfo.usageInfoRequired = usageInfoRequired;
         return permissionInfo;
     }
 
@@ -484,7 +480,6 @@
         bp.protectionLevel = readInt(parser, null, "protection",
                 PermissionInfo.PROTECTION_NORMAL);
         bp.protectionLevel = PermissionInfo.fixProtectionLevel(bp.protectionLevel);
-        bp.usageInfoRequired = readInt(parser, null, "usageInfoRequired", 0) != 0;
         if (dynamic) {
             final PermissionInfo pi = new PermissionInfo();
             pi.packageName = sourcePackage.intern();
@@ -492,7 +487,6 @@
             pi.icon = readInt(parser, null, "icon", 0);
             pi.nonLocalizedLabel = parser.getAttributeValue(null, "label");
             pi.protectionLevel = bp.protectionLevel;
-            pi.usageInfoRequired = bp.usageInfoRequired;
             bp.pendingPermissionInfo = pi;
         }
         out.put(bp.name, bp);
@@ -525,7 +519,6 @@
         if (protectionLevel != PermissionInfo.PROTECTION_NORMAL) {
             serializer.attribute(null, "protection", Integer.toString(protectionLevel));
         }
-        serializer.attribute(null, "usageInfoRequired", usageInfoRequired ? "1" : "0");
         if (type == BasePermission.TYPE_DYNAMIC) {
             final PermissionInfo pi = perm != null ? perm.info : pendingPermissionInfo;
             if (pi != null) {
@@ -562,7 +555,6 @@
         if (!compareStrings(pi1.nonLocalizedLabel, pi2.nonLocalizedLabel)) return false;
         // We'll take care of setting this one.
         if (!compareStrings(pi1.packageName, pi2.packageName)) return false;
-        if (pi1.usageInfoRequired != pi2.usageInfoRequired) return false;
         // These are not currently stored in settings.
         //if (!compareStrings(pi1.group, pi2.group)) return false;
         //if (!compareStrings(pi1.nonLocalizedDescription, pi2.nonLocalizedDescription)) return false;
@@ -610,8 +602,6 @@
             pw.print("    enforced=");
             pw.println(readEnforced);
         }
-        pw.print("    usageInfoRequired=");
-        pw.println(usageInfoRequired);
         return true;
     }
 }
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerInternal.java
index 189d0f4..f4979746 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerInternal.java
@@ -181,9 +181,4 @@
 
     /** HACK HACK methods to allow for partial migration of data to the PermissionManager class */
     public abstract @Nullable BasePermission getPermissionTEMP(@NonNull String permName);
-
-    /**
-     * Returns {@code true} if {@code permName} has {@code usageInfoRequired} set.
-     */
-    public abstract boolean isPermissionUsageInfoRequired(@NonNull String permName);
 }
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 a4413f9..38940d6 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -2737,12 +2737,5 @@
                 return mSettings.getPermissionLocked(permName);
             }
         }
-        @Override
-        public boolean isPermissionUsageInfoRequired(String permName) {
-            synchronized (PermissionManagerService.this.mLock) {
-                BasePermission bp = mSettings.getPermissionLocked(permName);
-                return bp != null && bp.usageInfoRequired;
-            }
-        }
     }
 }
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 0796a9c..b00193f 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -148,6 +148,7 @@
 import android.os.IDeviceIdleController;
 import android.os.Message;
 import android.os.PowerManager;
+import android.os.PowerManager.WakeReason;
 import android.os.PowerManagerInternal;
 import android.os.Process;
 import android.os.RemoteException;
@@ -189,6 +190,7 @@
 import android.view.WindowManager;
 import android.view.WindowManager.LayoutParams;
 import android.view.WindowManagerGlobal;
+import android.view.WindowManagerPolicyConstants;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 import android.view.animation.Animation;
@@ -809,7 +811,7 @@
                     performHapticFeedbackLw(null, HapticFeedbackConstants.VIRTUAL_KEY, false,
                             "Wake Up");
                     wakeUp(SystemClock.uptimeMillis(), mAllowTheaterModeWakeFromWakeGesture,
-                            "android.policy:GESTURE");
+                            PowerManager.WAKE_REASON_GESTURE, "android.policy:GESTURE");
                 }
             }
         }
@@ -3527,7 +3529,7 @@
 
         if (lidOpen) {
             wakeUp(SystemClock.uptimeMillis(), mAllowTheaterModeWakeFromLidSwitch,
-                    "android.policy:LID");
+                    PowerManager.WAKE_REASON_LID, "android.policy:LID");
         } else if (!mLidControlsSleep) {
             mPowerManager.userActivity(SystemClock.uptimeMillis(), false);
         }
@@ -3550,7 +3552,7 @@
                 intent = new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA);
             }
             wakeUp(whenNanos / 1000000, mAllowTheaterModeWakeFromCameraLens,
-                    "android.policy:CAMERA_COVER");
+                    PowerManager.WAKE_REASON_CAMERA_LAUNCH, "android.policy:CAMERA_COVER");
             startActivityAsUser(intent, UserHandle.CURRENT_OR_SELF);
         }
         mCameraLensCoverState = lensCoverState;
@@ -3679,7 +3681,8 @@
         if (isValidGlobalKey(keyCode)
                 && mGlobalKeyManager.shouldHandleGlobalKey(keyCode, event)) {
             if (isWakeKey) {
-                wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey, "android.policy:KEY");
+                wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey,
+                        PowerManager.WAKE_REASON_WAKE_KEY, "android.policy:KEY");
             }
             return result;
         }
@@ -4025,7 +4028,8 @@
         }
 
         if (isWakeKey) {
-            wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey, "android.policy:KEY");
+            wakeUp(event.getEventTime(), mAllowTheaterModeWakeFromKey,
+                    PowerManager.WAKE_REASON_WAKE_KEY, "android.policy:KEY");
         }
 
         return result;
@@ -4125,7 +4129,7 @@
     public int interceptMotionBeforeQueueingNonInteractive(long whenNanos, int policyFlags) {
         if ((policyFlags & FLAG_WAKE) != 0) {
             if (wakeUp(whenNanos / 1000000, mAllowTheaterModeWakeFromMotion,
-                    "android.policy:MOTION")) {
+                    PowerManager.WAKE_REASON_WAKE_MOTION, "android.policy:MOTION")) {
                 return 0;
             }
         }
@@ -4139,7 +4143,7 @@
         // wake up in this case.
         if (isTheaterModeEnabled() && (policyFlags & FLAG_WAKE) != 0) {
             wakeUp(whenNanos / 1000000, mAllowTheaterModeWakeFromMotionWhenNotDreaming,
-                    "android.policy:MOTION");
+                    PowerManager.WAKE_REASON_WAKE_MOTION, "android.policy:MOTION");
         }
 
         return 0;
@@ -4371,7 +4375,10 @@
     // Called on the PowerManager's Notifier thread.
     @Override
     public void startedGoingToSleep(int why) {
-        if (DEBUG_WAKEUP) Slog.i(TAG, "Started going to sleep... (why=" + why + ")");
+        if (DEBUG_WAKEUP) {
+            Slog.i(TAG, "Started going to sleep... (why="
+                    + WindowManagerPolicyConstants.offReasonToString(why) + ")");
+        }
 
         mGoingToSleep = true;
         mRequestedOrGoingToSleep = true;
@@ -4385,7 +4392,10 @@
     @Override
     public void finishedGoingToSleep(int why) {
         EventLog.writeEvent(70000, 0);
-        if (DEBUG_WAKEUP) Slog.i(TAG, "Finished going to sleep... (why=" + why + ")");
+        if (DEBUG_WAKEUP) {
+            Slog.i(TAG, "Finished going to sleep... (why="
+                    + WindowManagerPolicyConstants.offReasonToString(why) + ")");
+        }
         MetricsLogger.histogram(mContext, "screen_timeout", mLockScreenTimeout / 1000);
 
         mGoingToSleep = false;
@@ -4409,9 +4419,12 @@
 
     // Called on the PowerManager's Notifier thread.
     @Override
-    public void startedWakingUp() {
+    public void startedWakingUp(@OnReason int why) {
         EventLog.writeEvent(70000, 1);
-        if (DEBUG_WAKEUP) Slog.i(TAG, "Started waking up...");
+        if (DEBUG_WAKEUP) {
+            Slog.i(TAG, "Started waking up... (why="
+                    + WindowManagerPolicyConstants.onReasonToString(why) + ")");
+        }
 
         mDefaultDisplayPolicy.setAwake(true);
 
@@ -4432,8 +4445,11 @@
 
     // Called on the PowerManager's Notifier thread.
     @Override
-    public void finishedWakingUp() {
-        if (DEBUG_WAKEUP) Slog.i(TAG, "Finished waking up...");
+    public void finishedWakingUp(@OnReason int why) {
+        if (DEBUG_WAKEUP) {
+            Slog.i(TAG, "Finished waking up... (why="
+                    + WindowManagerPolicyConstants.onReasonToString(why) + ")");
+        }
 
         if (mKeyguardDelegate != null) {
             mKeyguardDelegate.onFinishedWakingUp();
@@ -4441,10 +4457,12 @@
     }
 
     private void wakeUpFromPowerKey(long eventTime) {
-        wakeUp(eventTime, mAllowTheaterModeWakeFromPowerKey, "android.policy:POWER");
+        wakeUp(eventTime, mAllowTheaterModeWakeFromPowerKey,
+                PowerManager.WAKE_REASON_POWER_BUTTON, "android.policy:POWER");
     }
 
-    private boolean wakeUp(long wakeTime, boolean wakeInTheaterMode, String reason) {
+    private boolean wakeUp(long wakeTime, boolean wakeInTheaterMode, @WakeReason int reason,
+            String details) {
         final boolean theaterModeEnabled = isTheaterModeEnabled();
         if (!wakeInTheaterMode && theaterModeEnabled) {
             return false;
@@ -4455,7 +4473,7 @@
                     Settings.Global.THEATER_MODE_ON, 0);
         }
 
-        mPowerManager.wakeUp(wakeTime, reason);
+        mPowerManager.wakeUp(wakeTime, reason, details);
         return true;
     }
 
@@ -4786,7 +4804,7 @@
                 mKeyguardDelegate.onBootCompleted();
             }
         }
-        startedWakingUp();
+        startedWakingUp(ON_BECAUSE_OF_UNKNOWN);
         screenTurningOn(null);
         screenTurnedOn();
     }
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index e18cd17..d1bd102 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -1070,12 +1070,12 @@
     /**
      * Called when the device has started waking up.
      */
-    public void startedWakingUp();
+    void startedWakingUp(@OnReason int reason);
 
     /**
      * Called when the device has finished waking up.
      */
-    public void finishedWakingUp();
+    void finishedWakingUp(@OnReason int reason);
 
     /**
      * Called when the device has started going to sleep.
diff --git a/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java b/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java
index e7de8dd..3534cf3 100644
--- a/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java
+++ b/services/core/java/com/android/server/policy/role/LegacyRoleResolutionPolicy.java
@@ -67,8 +67,8 @@
                         mContext.getContentResolver(),
                         Settings.Secure.SMS_DEFAULT_APPLICATION, userId);
 
-                // TODO: STOPSHIP: Remove the following code once we remove default_sms_application
-                // and use the new config_defaultRoleHolders.
+                // TODO: STOPSHIP: Remove the following code once we read the value of
+                //  config_defaultSms in RoleControllerService.
                 if (result == null) {
                     Collection<SmsApplication.SmsApplicationData> applications =
                             SmsApplication.getApplicationCollectionAsUser(mContext, userId);
diff --git a/services/core/java/com/android/server/power/Notifier.java b/services/core/java/com/android/server/power/Notifier.java
index c3f20aa..1a82858 100644
--- a/services/core/java/com/android/server/power/Notifier.java
+++ b/services/core/java/com/android/server/power/Notifier.java
@@ -36,6 +36,7 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.PowerManager;
+import android.os.PowerManager.WakeReason;
 import android.os.PowerManagerInternal;
 import android.os.Process;
 import android.os.RemoteException;
@@ -48,6 +49,7 @@
 import android.util.EventLog;
 import android.util.Slog;
 import android.util.StatsLog;
+import android.view.WindowManagerPolicyConstants.OnReason;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.IBatteryStats;
@@ -136,6 +138,7 @@
     // broadcasted state over the course of reporting the transition asynchronously.
     private boolean mInteractive = true;
     private int mInteractiveChangeReason;
+    private long mInteractiveChangeStartTime; // In SystemClock.uptimeMillis()
     private boolean mInteractiveChanging;
 
     // The pending interactive state that we will eventually want to broadcast.
@@ -371,7 +374,7 @@
      * which case it will assume that the state did not fully converge before the
      * next transition began and will recover accordingly.
      */
-    public void onWakefulnessChangeStarted(final int wakefulness, int reason) {
+    public void onWakefulnessChangeStarted(final int wakefulness, int reason, long eventTime) {
         final boolean interactive = PowerManagerInternal.isInteractive(wakefulness);
         if (DEBUG) {
             Slog.d(TAG, "onWakefulnessChangeStarted: wakefulness=" + wakefulness
@@ -410,6 +413,7 @@
             // Handle early behaviors.
             mInteractive = interactive;
             mInteractiveChangeReason = reason;
+            mInteractiveChangeStartTime = eventTime;
             mInteractiveChanging = true;
             handleEarlyInteractiveChange();
         }
@@ -440,8 +444,8 @@
                 mHandler.post(new Runnable() {
                     @Override
                     public void run() {
-                        // Note a SCREEN tron event is logged in PowerManagerService.
-                        mPolicy.startedWakingUp();
+                        final int why = translateOnReason(mInteractiveChangeReason);
+                        mPolicy.startedWakingUp(why);
                     }
                 });
 
@@ -470,12 +474,21 @@
      */
     private void handleLateInteractiveChange() {
         synchronized (mLock) {
+            final int interactiveChangeLatency =
+                    (int) (SystemClock.uptimeMillis() - mInteractiveChangeStartTime);
             if (mInteractive) {
                 // Finished waking up...
+                final int why = translateOnReason(mInteractiveChangeReason);
                 mHandler.post(new Runnable() {
                     @Override
                     public void run() {
-                        mPolicy.finishedWakingUp();
+                        LogMaker log = new LogMaker(MetricsEvent.SCREEN);
+                        log.setType(MetricsEvent.TYPE_OPEN);
+                        log.setSubtype(why);
+                        log.setLatency(interactiveChangeLatency);
+                        MetricsLogger.action(log);
+                        EventLogTags.writePowerScreenState(1, 0, 0, 0, interactiveChangeLatency);
+                        mPolicy.finishedWakingUp(why);
                     }
                 });
             } else {
@@ -499,8 +512,9 @@
                         LogMaker log = new LogMaker(MetricsEvent.SCREEN);
                         log.setType(MetricsEvent.TYPE_CLOSE);
                         log.setSubtype(why);
+                        log.setLatency(interactiveChangeLatency);
                         MetricsLogger.action(log);
-                        EventLogTags.writePowerScreenState(0, why, 0, 0, 0);
+                        EventLogTags.writePowerScreenState(0, why, 0, 0, interactiveChangeLatency);
                         mPolicy.finishedGoingToSleep(why);
                     }
                 });
@@ -524,6 +538,23 @@
         }
     }
 
+    private static @OnReason int translateOnReason(@WakeReason int reason) {
+        switch (reason) {
+            case PowerManager.WAKE_REASON_POWER_BUTTON:
+            case PowerManager.WAKE_REASON_PLUGGED_IN:
+            case PowerManager.WAKE_REASON_GESTURE:
+            case PowerManager.WAKE_REASON_CAMERA_LAUNCH:
+            case PowerManager.WAKE_REASON_WAKE_KEY:
+            case PowerManager.WAKE_REASON_WAKE_MOTION:
+            case PowerManager.WAKE_REASON_LID:
+                return WindowManagerPolicy.ON_BECAUSE_OF_USER;
+            case PowerManager.WAKE_REASON_APPLICATION:
+                return WindowManagerPolicy.ON_BECAUSE_OF_APPLICATION;
+            default:
+                return WindowManagerPolicy.ON_BECAUSE_OF_UNKNOWN;
+        }
+    }
+
     /**
      * Called when screen brightness boost begins or ends.
      */
@@ -565,14 +596,16 @@
     /**
      * Called when the screen has turned on.
      */
-    public void onWakeUp(String reason, int reasonUid, String opPackageName, int opUid) {
+    public void onWakeUp(int reason, String details, int reasonUid, String opPackageName,
+            int opUid) {
         if (DEBUG) {
-            Slog.d(TAG, "onWakeUp: event=" + reason + ", reasonUid=" + reasonUid
+            Slog.d(TAG, "onWakeUp: reason=" + PowerManager.wakeReasonToString(reason)
+                    + ", details=" + details + ", reasonUid=" + reasonUid
                     + " opPackageName=" + opPackageName + " opUid=" + opUid);
         }
 
         try {
-            mBatteryStats.noteWakeUp(reason, reasonUid);
+            mBatteryStats.noteWakeUp(details, reasonUid);
             if (opPackageName != null) {
                 mAppOps.noteOpNoThrow(AppOpsManager.OP_TURN_SCREEN_ON, opUid, opPackageName);
             }
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 3ccd234..1782b6a 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -39,7 +39,6 @@
 import android.hardware.display.DisplayManagerInternal;
 import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
 import android.hardware.power.V1_0.PowerHint;
-import android.metrics.LogMaker;
 import android.net.Uri;
 import android.os.BatteryManager;
 import android.os.BatteryManagerInternal;
@@ -52,6 +51,7 @@
 import android.os.Message;
 import android.os.PowerManager;
 import android.os.PowerManager.ServiceType;
+import android.os.PowerManager.WakeReason;
 import android.os.PowerManagerInternal;
 import android.os.PowerSaveState;
 import android.os.Process;
@@ -82,8 +82,6 @@
 import com.android.internal.app.IAppOpsService;
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.hardware.AmbientDisplayConfiguration;
-import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.os.BackgroundThread;
 import com.android.internal.util.DumpUtils;
 import com.android.server.EventLogTags;
@@ -199,7 +197,8 @@
     // System Property indicating that retail demo mode is currently enabled.
     private static final String SYSTEM_PROPERTY_RETAIL_DEMO_ENABLED = "sys.retaildemo.enabled";
 
-    // Possible reasons for shutting down for use in data/misc/reboot/last_shutdown_reason
+    // Possible reasons for shutting down or reboot for use in REBOOT_PROPERTY(sys.boot.reason)
+    // which is set by bootstat
     private static final String REASON_SHUTDOWN = "shutdown";
     private static final String REASON_REBOOT = "reboot";
     private static final String REASON_USERREQUESTED = "shutdown,userrequested";
@@ -295,6 +294,7 @@
     private long mLastSleepTime;
 
     // Last reason the device went to sleep.
+    private @WakeReason int mLastWakeReason;
     private int mLastSleepReason;
 
     // Timestamp of the last call to user activity.
@@ -1119,8 +1119,9 @@
                 opPackageName = wakeLock.mPackageName;
                 opUid = wakeLock.mOwnerUid;
             }
-            wakeUpNoUpdateLocked(SystemClock.uptimeMillis(), wakeLock.mTag, opUid,
-                    opPackageName, opUid);
+            wakeUpNoUpdateLocked(SystemClock.uptimeMillis(),
+                    PowerManager.WAKE_REASON_APPLICATION, wakeLock.mTag,
+                    opUid, opPackageName, opUid);
         }
     }
 
@@ -1410,17 +1411,17 @@
         }
     }
 
-    private void wakeUpInternal(long eventTime, String reason, int uid, String opPackageName,
-            int opUid) {
+    private void wakeUpInternal(long eventTime, @WakeReason int reason, String details, int uid,
+            String opPackageName, int opUid) {
         synchronized (mLock) {
-            if (wakeUpNoUpdateLocked(eventTime, reason, uid, opPackageName, opUid)) {
+            if (wakeUpNoUpdateLocked(eventTime, reason, details, uid, opPackageName, opUid)) {
                 updatePowerStateLocked();
             }
         }
     }
 
-    private boolean wakeUpNoUpdateLocked(long eventTime, String reason, int reasonUid,
-            String opPackageName, int opUid) {
+    private boolean wakeUpNoUpdateLocked(long eventTime, @WakeReason int reason, String details,
+            int reasonUid, String opPackageName, int opUid) {
         if (DEBUG_SPEW) {
             Slog.d(TAG, "wakeUpNoUpdateLocked: eventTime=" + eventTime + ", uid=" + reasonUid);
         }
@@ -1434,25 +1435,18 @@
 
         Trace.traceBegin(Trace.TRACE_TAG_POWER, "wakeUp");
         try {
-            switch (mWakefulness) {
-                case WAKEFULNESS_ASLEEP:
-                    Slog.i(TAG, "Waking up from sleep (uid=" + reasonUid + " reason=" + reason
-                            + ")...");
-                    break;
-                case WAKEFULNESS_DREAMING:
-                    Slog.i(TAG, "Waking up from dream (uid=" + reasonUid + " reason=" + reason
-                            + ")...");
-                    break;
-                case WAKEFULNESS_DOZING:
-                    Slog.i(TAG, "Waking up from dozing (uid=" + reasonUid + " reason=" + reason
-                            + ")...");
-                    break;
-            }
+            Slog.i(TAG, "Waking up from "
+                    + PowerManagerInternal.wakefulnessToString(mWakefulness)
+                    + " (uid=" + reasonUid
+                    + ", reason=" + PowerManager.wakeReasonToString(reason)
+                    + ", details=" + details
+                    + ")...");
 
             mLastWakeTime = eventTime;
-            setWakefulnessLocked(WAKEFULNESS_AWAKE, 0);
+            mLastWakeReason = reason;
+            setWakefulnessLocked(WAKEFULNESS_AWAKE, reason, eventTime);
 
-            mNotifier.onWakeUp(reason, reasonUid, opPackageName, opUid);
+            mNotifier.onWakeUp(reason, details, reasonUid, opPackageName, opUid);
             userActivityNoUpdateLocked(
                     eventTime, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, reasonUid);
         } finally {
@@ -1520,7 +1514,7 @@
             mLastSleepTime = eventTime;
             mLastSleepReason = reason;
             mSandmanSummoned = true;
-            setWakefulnessLocked(WAKEFULNESS_DOZING, reason);
+            setWakefulnessLocked(WAKEFULNESS_DOZING, reason, eventTime);
 
             // Report the number of wake locks that will be cleared by going to sleep.
             int numWakeLocksCleared = 0;
@@ -1570,7 +1564,7 @@
             Slog.i(TAG, "Nap time (uid " + uid +")...");
 
             mSandmanSummoned = true;
-            setWakefulnessLocked(WAKEFULNESS_DREAMING, 0);
+            setWakefulnessLocked(WAKEFULNESS_DREAMING, 0, eventTime);
         } finally {
             Trace.traceEnd(Trace.TRACE_TAG_POWER);
         }
@@ -1593,7 +1587,8 @@
         try {
             Slog.i(TAG, "Sleeping (uid " + uid +")...");
 
-            setWakefulnessLocked(WAKEFULNESS_ASLEEP, PowerManager.GO_TO_SLEEP_REASON_TIMEOUT);
+            setWakefulnessLocked(WAKEFULNESS_ASLEEP, PowerManager.GO_TO_SLEEP_REASON_TIMEOUT,
+                    eventTime);
         } finally {
             Trace.traceEnd(Trace.TRACE_TAG_POWER);
         }
@@ -1601,13 +1596,13 @@
     }
 
     @VisibleForTesting
-    void setWakefulnessLocked(int wakefulness, int reason) {
+    void setWakefulnessLocked(int wakefulness, int reason, long eventTime) {
         if (mWakefulness != wakefulness) {
             mWakefulness = wakefulness;
             mWakefulnessChanging = true;
             mDirty |= DIRTY_WAKEFULNESS;
             if (mNotifier != null) {
-                mNotifier.onWakefulnessChangeStarted(wakefulness, reason);
+                mNotifier.onWakefulnessChangeStarted(wakefulness, reason, eventTime);
             }
             mAttentionDetector.onWakefulnessChangeStarted(wakefulness);
         }
@@ -1631,23 +1626,6 @@
         }
     }
 
-    private void logScreenOn() {
-        Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, TRACE_SCREEN_ON, 0);
-
-        final int latencyMs = (int) (SystemClock.uptimeMillis() - mLastWakeTime);
-
-        LogMaker log = new LogMaker(MetricsEvent.SCREEN);
-        log.setType(MetricsEvent.TYPE_OPEN);
-        log.setSubtype(0); // not user initiated
-        log.setLatency(latencyMs); // How long it took.
-        MetricsLogger.action(log);
-        EventLogTags.writePowerScreenState(1, 0, 0, 0, latencyMs);
-
-        if (latencyMs >= SCREEN_ON_LATENCY_WARNING_MS) {
-            Slog.w(TAG, "Screen on took " + latencyMs+ " ms");
-        }
-    }
-
     private void finishWakefulnessChangeIfNeededLocked() {
         if (mWakefulnessChanging && mDisplayReady) {
             if (mWakefulness == WAKEFULNESS_DOZING
@@ -1658,7 +1636,11 @@
                 logSleepTimeoutRecapturedLocked();
             }
             if (mWakefulness == WAKEFULNESS_AWAKE) {
-                logScreenOn();
+                Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, TRACE_SCREEN_ON, 0);
+                final int latencyMs = (int) (SystemClock.uptimeMillis() - mLastWakeTime);
+                if (latencyMs >= SCREEN_ON_LATENCY_WARNING_MS) {
+                    Slog.w(TAG, "Screen on took " + latencyMs + " ms");
+                }
             }
             mWakefulnessChanging = false;
             mNotifier.onWakefulnessChangeFinished();
@@ -1786,7 +1768,8 @@
                 final long now = SystemClock.uptimeMillis();
                 if (shouldWakeUpWhenPluggedOrUnpluggedLocked(wasPowered, oldPlugType,
                         dockedOnWirelessCharger)) {
-                    wakeUpNoUpdateLocked(now, "android.server.power:POWER", Process.SYSTEM_UID,
+                    wakeUpNoUpdateLocked(now, PowerManager.WAKE_REASON_PLUGGED_IN,
+                            "android.server.power:PLUGGED:" + mIsPowered, Process.SYSTEM_UID,
                             mContext.getOpPackageName(), Process.SYSTEM_UID);
                 }
                 userActivityNoUpdateLocked(
@@ -2369,8 +2352,10 @@
                             PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, 0, Process.SYSTEM_UID);
                     updatePowerStateLocked();
                 } else {
-                    wakeUpNoUpdateLocked(SystemClock.uptimeMillis(), "android.server.power:DREAM",
-                            Process.SYSTEM_UID, mContext.getOpPackageName(), Process.SYSTEM_UID);
+                    wakeUpNoUpdateLocked(SystemClock.uptimeMillis(),
+                            PowerManager.WAKE_REASON_UNKNOWN,
+                            "android.server.power:DREAM_FINISHED", Process.SYSTEM_UID,
+                            mContext.getOpPackageName(), Process.SYSTEM_UID);
                     updatePowerStateLocked();
                 }
             } else if (wakefulness == WAKEFULNESS_DOZING) {
@@ -4375,7 +4360,8 @@
         }
 
         @Override // Binder call
-        public void wakeUp(long eventTime, String reason, String opPackageName) {
+        public void wakeUp(long eventTime, @WakeReason int reason, String details,
+                String opPackageName) {
             if (eventTime > SystemClock.uptimeMillis()) {
                 throw new IllegalArgumentException("event time must not be in the future");
             }
@@ -4386,7 +4372,7 @@
             final int uid = Binder.getCallingUid();
             final long ident = Binder.clearCallingIdentity();
             try {
-                wakeUpInternal(eventTime, reason, uid, opPackageName, uid);
+                wakeUpInternal(eventTime, reason, details, uid, opPackageName, uid);
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
diff --git a/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java b/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java
index bd46a50..fac95f9 100644
--- a/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java
+++ b/services/core/java/com/android/server/power/batterysaver/BatterySaverPolicy.java
@@ -665,8 +665,7 @@
                     config.getEnableAdjustBrightness(),
                     config.getEnableDataSaver(),
                     config.getEnableFirewall(),
-                    // TODO: add option to config
-                    config.getAdvertiseIsEnabled(),
+                    config.getEnableNightMode(),
                     config.getEnableQuickDoze(),
                     /* filesForInteractive */
                     (new CpuFrequencies()).parseString(cpuFreqInteractive).toSysFileMap(),
@@ -674,7 +673,7 @@
                     (new CpuFrequencies()).parseString(cpuFreqNoninteractive).toSysFileMap(),
                     config.getForceAllAppsStandby(),
                     config.getForceBackgroundCheck(),
-                    config.getGpsMode()
+                    config.getLocationMode()
             );
         }
 
diff --git a/services/core/java/com/android/server/role/RemoteRoleControllerService.java b/services/core/java/com/android/server/role/RemoteRoleControllerService.java
index 107cb2c..4fb40db 100644
--- a/services/core/java/com/android/server/role/RemoteRoleControllerService.java
+++ b/services/core/java/com/android/server/role/RemoteRoleControllerService.java
@@ -21,6 +21,7 @@
 import android.annotation.UserIdInt;
 import android.annotation.WorkerThread;
 import android.app.role.IRoleManagerCallback;
+import android.app.role.RoleManager;
 import android.app.role.RoleManagerCallback;
 import android.content.ComponentName;
 import android.content.Context;
@@ -61,34 +62,35 @@
      * Add a specific application to the holders of a role. If the role is exclusive, the previous
      * holder will be replaced.
      *
-     * @see RoleControllerService#onAddRoleHolder(String, String, RoleManagerCallback)
+     * @see RoleControllerService#onAddRoleHolder(String, String, int, RoleManagerCallback)
      */
     public void onAddRoleHolder(@NonNull String roleName, @NonNull String packageName,
-            @NonNull IRoleManagerCallback callback) {
+            @RoleManager.ManageHoldersFlags int flags, @NonNull IRoleManagerCallback callback) {
         mConnection.enqueueCall(new Connection.Call((service, callbackDelegate) ->
-                service.onAddRoleHolder(roleName, packageName, callbackDelegate), callback));
+                service.onAddRoleHolder(roleName, packageName, flags, callbackDelegate), callback));
     }
 
     /**
      * Remove a specific application from the holders of a role.
      *
-     * @see RoleControllerService#onRemoveRoleHolder(String, String, RoleManagerCallback)
+     * @see RoleControllerService#onRemoveRoleHolder(String, String, int, RoleManagerCallback)
      */
     public void onRemoveRoleHolder(@NonNull String roleName, @NonNull String packageName,
-            @NonNull IRoleManagerCallback callback) {
+            @RoleManager.ManageHoldersFlags int flags, @NonNull IRoleManagerCallback callback) {
         mConnection.enqueueCall(new Connection.Call((service, callbackDelegate) ->
-                service.onRemoveRoleHolder(roleName, packageName, callbackDelegate), callback));
+                service.onRemoveRoleHolder(roleName, packageName, flags, callbackDelegate),
+                callback));
     }
 
     /**
      * Remove all holders of a role.
      *
-     * @see RoleControllerService#onClearRoleHolders(String, RoleManagerCallback)
+     * @see RoleControllerService#onClearRoleHolders(String, int, RoleManagerCallback)
      */
     public void onClearRoleHolders(@NonNull String roleName,
-            @NonNull IRoleManagerCallback callback) {
+            @RoleManager.ManageHoldersFlags int flags, @NonNull IRoleManagerCallback callback) {
         mConnection.enqueueCall(new Connection.Call((service, callbackDelegate) ->
-                service.onClearRoleHolders(roleName, callbackDelegate), callback));
+                service.onClearRoleHolders(roleName, flags, callbackDelegate), callback));
     }
 
     /**
diff --git a/services/core/java/com/android/server/role/RoleManagerService.java b/services/core/java/com/android/server/role/RoleManagerService.java
index 84305be..21bf9de 100644
--- a/services/core/java/com/android/server/role/RoleManagerService.java
+++ b/services/core/java/com/android/server/role/RoleManagerService.java
@@ -201,10 +201,15 @@
                 new ContentObserver(getContext().getMainThreadHandler()) {
                     @Override
                     public void onChange(boolean selfChange, Uri uri, int userId) {
-                        getOrCreateControllerService(userId).onSmsKillSwitchToggled(
-                                Settings.Global.getInt(
-                                        getContext().getContentResolver(),
-                                        Settings.Global.SMS_ACCESS_RESTRICTION_ENABLED, 0) == 1);
+                        boolean killSwitchEnabled = Settings.Global.getInt(
+                                getContext().getContentResolver(),
+                                Settings.Global.SMS_ACCESS_RESTRICTION_ENABLED, 0) == 1;
+                        for (int user : mUserManagerInternal.getUserIds()) {
+                            if (mUserManagerInternal.isUserRunning(user)) {
+                                getOrCreateControllerService(user)
+                                        .onSmsKillSwitchToggled(killSwitchEnabled);
+                            }
+                        }
                     }
                 }, UserHandle.USER_ALL);
     }
@@ -450,7 +455,8 @@
 
         @Override
         public void addRoleHolderAsUser(@NonNull String roleName, @NonNull String packageName,
-                @UserIdInt int userId, @NonNull IRoleManagerCallback callback) {
+                @RoleManager.ManageHoldersFlags int flags, @UserIdInt int userId,
+                @NonNull IRoleManagerCallback callback) {
             Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
             Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
             Preconditions.checkNotNull(callback, "callback cannot be null");
@@ -462,12 +468,14 @@
             getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS,
                     "addRoleHolderAsUser");
 
-            getOrCreateControllerService(userId).onAddRoleHolder(roleName, packageName, callback);
+            getOrCreateControllerService(userId).onAddRoleHolder(roleName, packageName, flags,
+                    callback);
         }
 
         @Override
         public void removeRoleHolderAsUser(@NonNull String roleName, @NonNull String packageName,
-                @UserIdInt int userId, @NonNull IRoleManagerCallback callback) {
+                @RoleManager.ManageHoldersFlags int flags, @UserIdInt int userId,
+                @NonNull IRoleManagerCallback callback) {
             Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
             Preconditions.checkStringNotEmpty(packageName, "packageName cannot be null or empty");
             Preconditions.checkNotNull(callback, "callback cannot be null");
@@ -479,12 +487,13 @@
             getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS,
                     "removeRoleHolderAsUser");
 
-            getOrCreateControllerService(userId).onRemoveRoleHolder(roleName, packageName,
+            getOrCreateControllerService(userId).onRemoveRoleHolder(roleName, packageName, flags,
                     callback);
         }
 
         @Override
-        public void clearRoleHoldersAsUser(@NonNull String roleName, @UserIdInt int userId,
+        public void clearRoleHoldersAsUser(@NonNull String roleName,
+                @RoleManager.ManageHoldersFlags int flags, @UserIdInt int userId,
                 @NonNull IRoleManagerCallback callback) {
             Preconditions.checkStringNotEmpty(roleName, "roleName cannot be null or empty");
             Preconditions.checkNotNull(callback, "callback cannot be null");
@@ -496,7 +505,7 @@
             getContext().enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ROLE_HOLDERS,
                     "clearRoleHoldersAsUser");
 
-            getOrCreateControllerService(userId).onClearRoleHolders(roleName, callback);
+            getOrCreateControllerService(userId).onClearRoleHolders(roleName, flags, callback);
         }
 
         @Override
@@ -718,9 +727,9 @@
             };
             if (packageName != null) {
                 getOrCreateControllerService(userId).onAddRoleHolder(RoleManager.ROLE_BROWSER,
-                        packageName, callback);
+                        packageName, 0, callback);
             } else {
-                getOrCreateControllerService(userId).onClearRoleHolders(RoleManager.ROLE_BROWSER,
+                getOrCreateControllerService(userId).onClearRoleHolders(RoleManager.ROLE_BROWSER, 0,
                         callback);
             }
             try {
diff --git a/services/core/java/com/android/server/role/RoleManagerShellCommand.java b/services/core/java/com/android/server/role/RoleManagerShellCommand.java
index b245e98..00021d7 100644
--- a/services/core/java/com/android/server/role/RoleManagerShellCommand.java
+++ b/services/core/java/com/android/server/role/RoleManagerShellCommand.java
@@ -98,13 +98,22 @@
         return userId;
     }
 
+    private int getFlagsMaybe() {
+        String flags = getNextArg();
+        if (flags == null) {
+            return 0;
+        }
+        return Integer.parseInt(flags);
+    }
+
     private int runAddRoleHolder() throws RemoteException {
         int userId = getUserIdMaybe();
         String roleName = getNextArgRequired();
         String packageName = getNextArgRequired();
+        int flags = getFlagsMaybe();
 
         Callback callback = new Callback();
-        mRoleManager.addRoleHolderAsUser(roleName, packageName, userId, callback);
+        mRoleManager.addRoleHolderAsUser(roleName, packageName, flags, userId, callback);
         return callback.waitForResult();
     }
 
@@ -112,18 +121,20 @@
         int userId = getUserIdMaybe();
         String roleName = getNextArgRequired();
         String packageName = getNextArgRequired();
+        int flags = getFlagsMaybe();
 
         Callback callback = new Callback();
-        mRoleManager.removeRoleHolderAsUser(roleName, packageName, userId, callback);
+        mRoleManager.removeRoleHolderAsUser(roleName, packageName, flags, userId, callback);
         return callback.waitForResult();
     }
 
     private int runClearRoleHolders() throws RemoteException {
         int userId = getUserIdMaybe();
         String roleName = getNextArgRequired();
+        int flags = getFlagsMaybe();
 
         Callback callback = new Callback();
-        mRoleManager.clearRoleHoldersAsUser(roleName, userId, callback);
+        mRoleManager.clearRoleHoldersAsUser(roleName, flags, userId, callback);
         return callback.waitForResult();
     }
 
@@ -134,9 +145,9 @@
         pw.println("  help");
         pw.println("    Print this help text.");
         pw.println();
-        pw.println("  add-role-holder [--user USER_ID] ROLE PACKAGE");
-        pw.println("  remove-role-holder [--user USER_ID] ROLE PACKAGE");
-        pw.println("  clear-role-holders [--user USER_ID] ROLE");
+        pw.println("  add-role-holder [--user USER_ID] ROLE PACKAGE [FLAGS]");
+        pw.println("  remove-role-holder [--user USER_ID] ROLE PACKAGE [FLAGS]");
+        pw.println("  clear-role-holders [--user USER_ID] ROLE [FLAGS]");
         pw.println();
     }
 }
diff --git a/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java b/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java
index 8dd0760..f3b8385 100644
--- a/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java
+++ b/services/core/java/com/android/server/rollback/AppDataRollbackHelper.java
@@ -22,6 +22,7 @@
 import android.os.storage.StorageManager;
 import android.util.IntArray;
 import android.util.Log;
+import android.util.SparseLongArray;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.server.pm.Installer;
@@ -51,11 +52,13 @@
      * Creates an app data snapshot for a specified {@code packageName} for {@code installedUsers},
      * a specified set of users for whom the package is installed.
      *
-     * @return a list of users for which the snapshot is pending, usually because data for one or
-     *         more users is still credential locked.
+     * @return a {@link SnapshotAppDataResult}/
+     * @see SnapshotAppDataResult
      */
-    public IntArray snapshotAppData(String packageName, int[] installedUsers) {
+    public SnapshotAppDataResult snapshotAppData(String packageName, int[] installedUsers) {
         final IntArray pendingBackups = new IntArray();
+        final SparseLongArray ceSnapshotInodes = new SparseLongArray();
+
         for (int user : installedUsers) {
             final int storageFlags;
             if (isUserCredentialLocked(user)) {
@@ -69,14 +72,17 @@
             }
 
             try {
-                mInstaller.snapshotAppData(packageName, user, storageFlags);
+                long ceSnapshotInode = mInstaller.snapshotAppData(packageName, user, storageFlags);
+                if ((storageFlags & Installer.FLAG_STORAGE_CE) != 0) {
+                    ceSnapshotInodes.put(user, ceSnapshotInode);
+                }
             } catch (InstallerException ie) {
                 Log.e(TAG, "Unable to create app data snapshot for: " + packageName
                         + ", userId: " + user, ie);
             }
         }
 
-        return pendingBackups;
+        return new SnapshotAppDataResult(pendingBackups, ceSnapshotInodes);
     }
 
     /**
@@ -138,6 +144,22 @@
     }
 
     /**
+     * Deletes an app data data snapshot for a specified package {@code packageName} for a
+     * given {@code user}.
+     */
+    public void destroyAppDataSnapshot(String packageName, int user, long ceSnapshotInode) {
+        int storageFlags = Installer.FLAG_STORAGE_DE;
+        if (ceSnapshotInode > 0) {
+            storageFlags |= Installer.FLAG_STORAGE_CE;
+        }
+        try {
+            mInstaller.destroyAppDataSnapshot(packageName, user, ceSnapshotInode, storageFlags);
+        } catch (InstallerException ie) {
+            Log.e(TAG, "Unable to delete app data snapshot for " + packageName, ie);
+        }
+    }
+
+    /**
      * Computes the list of pending backups and restores for {@code userId} given lists of
      * available and recent rollbacks. Packages pending backup for the given user are added
      * to {@code pendingBackups} and packages pending restore are added to {@code pendingRestores}
@@ -191,16 +213,28 @@
     }
 
     /**
-     * Commits the list of pending backups and restores for a given {@code userId}.
+     * Commits the list of pending backups and restores for a given {@code userId}. For the pending
+     * backups updates corresponding {@code changedRollbackData} with a mapping from {@code userId}
+     * to a inode of theirs CE user data snapshot.
      */
     public void commitPendingBackupAndRestoreForUser(int userId,
-            ArrayList<String> pendingBackups, Map<String, RestoreInfo> pendingRestores) {
+            ArrayList<String> pendingBackups, Map<String, RestoreInfo> pendingRestores,
+            List<RollbackData> changedRollbackData) {
         if (!pendingBackups.isEmpty()) {
             for (String packageName : pendingBackups) {
                 try {
-                    mInstaller.snapshotAppData(packageName, userId, Installer.FLAG_STORAGE_CE);
+                    long ceSnapshotInode = mInstaller.snapshotAppData(packageName, userId,
+                            Installer.FLAG_STORAGE_CE);
+                    for (RollbackData data : changedRollbackData) {
+                        for (PackageRollbackInfo info : data.packages) {
+                            if (info.getPackageName().equals(packageName)) {
+                                info.putCeSnapshotInode(userId, ceSnapshotInode);
+                            }
+                        }
+                    }
                 } catch (InstallerException ie) {
-                    Log.e(TAG, "Unable to create app data snapshot for: " + packageName, ie);
+                    Log.e(TAG, "Unable to create app data snapshot for: " + packageName
+                            + ", userId: " + userId, ie);
                 }
             }
         }
@@ -233,4 +267,26 @@
         return StorageManager.isFileEncryptedNativeOrEmulated()
                 && !StorageManager.isUserKeyUnlocked(userId);
     }
+
+    /**
+     * Encapsulates a result of {@link #snapshotAppData} method.
+     */
+    public static final class SnapshotAppDataResult {
+
+        /**
+         * A list of users for which the snapshot is pending, usually because data for one or more
+         * users is still credential locked.
+         */
+        public final IntArray pendingBackups;
+
+        /**
+         * A mapping between user and an inode of theirs CE data snapshot.
+         */
+        public final SparseLongArray ceSnapshotInodes;
+
+        public SnapshotAppDataResult(IntArray pendingBackups, SparseLongArray ceSnapshotInodes) {
+            this.pendingBackups = pendingBackups;
+            this.ceSnapshotInodes = ceSnapshotInodes;
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index 27f7bcf..95c3f4c 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -43,6 +43,7 @@
 import android.util.IntArray;
 import android.util.Log;
 import android.util.SparseBooleanArray;
+import android.util.SparseLongArray;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.server.LocalServices;
@@ -110,7 +111,7 @@
     private final HandlerThread mHandlerThread;
     private final Installer mInstaller;
     private final RollbackPackageHealthObserver mPackageHealthObserver;
-    private final AppDataRollbackHelper mUserdataHelper;
+    private final AppDataRollbackHelper mAppDataRollbackHelper;
 
     RollbackManagerServiceImpl(Context context) {
         mContext = context;
@@ -124,7 +125,7 @@
         mRollbackStore = new RollbackStore(new File(Environment.getDataDirectory(), "rollback"));
 
         mPackageHealthObserver = new RollbackPackageHealthObserver(mContext);
-        mUserdataHelper = new AppDataRollbackHelper(mInstaller);
+        mAppDataRollbackHelper = new AppDataRollbackHelper(mInstaller);
 
         // Kick off loading of the rollback data from strorage in a background
         // thread.
@@ -339,12 +340,9 @@
                 // for apex?
                 if (!info.isApex()) {
                     String installerPackageName = pm.getInstallerPackageName(info.getPackageName());
-                    if (installerPackageName == null) {
-                        sendFailure(statusReceiver, RollbackManager.STATUS_FAILURE,
-                                "Cannot find installer package");
-                        return;
+                    if (installerPackageName != null) {
+                        params.setInstallerPackageName(installerPackageName);
                     }
-                    params.setInstallerPackageName(installerPackageName);
                 }
                 params.setAllowDowngrade(true);
                 if (data.isStaged()) {
@@ -449,7 +447,7 @@
                 for (PackageRollbackInfo info : data.packages) {
                     if (info.getPackageName().equals(packageName)) {
                         iter.remove();
-                        mRollbackStore.deleteAvailableRollback(data);
+                        deleteRollback(data);
                         break;
                     }
                 }
@@ -464,13 +462,13 @@
             final List<RollbackData> changed;
             synchronized (mLock) {
                 ensureRollbackDataLoadedLocked();
-                changed = mUserdataHelper.computePendingBackupsAndRestores(userId,
+                changed = mAppDataRollbackHelper.computePendingBackupsAndRestores(userId,
                         pendingBackupPackages, pendingRestorePackages, mAvailableRollbacks,
                         mRecentlyExecutedRollbacks);
             }
 
-            mUserdataHelper.commitPendingBackupAndRestoreForUser(userId,
-                    pendingBackupPackages, pendingRestorePackages);
+            mAppDataRollbackHelper.commitPendingBackupAndRestoreForUser(userId,
+                    pendingBackupPackages, pendingRestorePackages, changed);
 
             for (RollbackData rd : changed) {
                 try {
@@ -520,7 +518,7 @@
                         // mAvailableRollbacks, or is it okay to leave as
                         // unavailable until the next reboot when it will go
                         // away on its own?
-                        mRollbackStore.deleteAvailableRollback(data);
+                        deleteRollback(data);
                     }
                 }
             }
@@ -592,7 +590,7 @@
                                         info.getVersionRolledBackFrom(),
                                         installedVersion)) {
                         iter.remove();
-                        mRollbackStore.deleteAvailableRollback(data);
+                        deleteRollback(data);
                         break;
                     }
                 }
@@ -705,7 +703,7 @@
 
                 if (!now.isBefore(data.timestamp.plusMillis(ROLLBACK_LIFETIME_DURATION_MILLIS))) {
                     iter.remove();
-                    mRollbackStore.deleteAvailableRollback(data);
+                    deleteRollback(data);
                 } else if (oldest == null || oldest.isAfter(data.timestamp)) {
                     oldest = data.timestamp;
                 }
@@ -821,9 +819,13 @@
             String packageName = newPackage.packageName;
             for (PackageRollbackInfo info : rd.packages) {
                 if (info.getPackageName().equals(packageName)) {
-                    IntArray pendingBackups = mUserdataHelper.snapshotAppData(
-                            packageName, installedUsers);
-                    info.getPendingBackups().addAll(pendingBackups);
+                    AppDataRollbackHelper.SnapshotAppDataResult rs =
+                            mAppDataRollbackHelper.snapshotAppData(packageName, installedUsers);
+                    info.getPendingBackups().addAll(rs.pendingBackups);
+                    for (int i = 0; i < rs.ceSnapshotInodes.size(); i++) {
+                        info.putCeSnapshotInode(rs.ceSnapshotInodes.keyAt(i),
+                                rs.ceSnapshotInodes.valueAt(i));
+                    }
                     try {
                         mRollbackStore.saveAvailableRollback(rd);
                     } catch (IOException ioe) {
@@ -892,13 +894,18 @@
         VersionedPackage installedVersion = new VersionedPackage(packageName,
                 pkgInfo.getLongVersionCode());
 
-        IntArray pendingBackups = IntArray.wrap(new int[0]);
+        final AppDataRollbackHelper.SnapshotAppDataResult result;
         if (snapshotUserData && !isApex) {
-            pendingBackups = mUserdataHelper.snapshotAppData(packageName, installedUsers);
+            result = mAppDataRollbackHelper.snapshotAppData(packageName, installedUsers);
+        } else {
+            result = new AppDataRollbackHelper.SnapshotAppDataResult(IntArray.wrap(new int[0]),
+                new SparseLongArray());
         }
 
         PackageRollbackInfo info = new PackageRollbackInfo(newVersion, installedVersion,
-                pendingBackups, new ArrayList<>(), isApex);
+                result.pendingBackups, new ArrayList<>(), isApex, IntArray.wrap(installedUsers),
+                result.ceSnapshotInodes);
+
         RollbackData data;
         try {
             int childSessionId = session.getSessionId();
@@ -948,9 +955,8 @@
         getHandler().post(() -> {
             final RollbackData rollbackData = getRollbackForPackage(packageName);
             for (int userId : userIds) {
-                final boolean changedRollbackData = mUserdataHelper.restoreAppData(packageName,
-                        rollbackData, userId, appId, ceDataInode, seInfo);
-
+                final boolean changedRollbackData = mAppDataRollbackHelper.restoreAppData(
+                        packageName, rollbackData, userId, appId, ceDataInode, seInfo);
                 // We've updated metadata about this rollback, so save it to flash.
                 if (changedRollbackData) {
                     try {
@@ -1142,12 +1148,12 @@
                     scheduleExpiration(ROLLBACK_LIFETIME_DURATION_MILLIS);
                 } catch (IOException e) {
                     Log.e(TAG, "Unable to enable rollback", e);
-                    mRollbackStore.deleteAvailableRollback(data);
+                    deleteRollback(data);
                 }
             } else {
                 // The install session was aborted, clean up the pending
                 // install.
-                mRollbackStore.deleteAvailableRollback(data);
+                deleteRollback(data);
             }
         }
     }
@@ -1246,4 +1252,17 @@
 
         throw new IOException("Failed to allocate rollback ID");
     }
+
+    private void deleteRollback(RollbackData rollbackData) {
+        for (PackageRollbackInfo info : rollbackData.packages) {
+            IntArray installedUsers = info.getInstalledUsers();
+            SparseLongArray ceSnapshotInodes = info.getCeSnapshotInodes();
+            for (int i = 0; i < installedUsers.size(); i++) {
+                int userId = installedUsers.get(i);
+                mAppDataRollbackHelper.destroyAppDataSnapshot(info.getPackageName(), userId,
+                        ceSnapshotInodes.get(userId, 0));
+            }
+        }
+        mRollbackStore.deleteAvailableRollback(rollbackData);
+    }
 }
diff --git a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
index 3c6a54a..3a2b69f 100644
--- a/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
+++ b/services/core/java/com/android/server/rollback/RollbackPackageHealthObserver.java
@@ -16,8 +16,11 @@
 
 package com.android.server.rollback;
 
+import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageInstaller;
 import android.content.pm.PackageManager;
 import android.content.pm.VersionedPackage;
 import android.content.rollback.PackageRollbackInfo;
@@ -25,6 +28,7 @@
 import android.content.rollback.RollbackManager;
 import android.os.Handler;
 import android.os.HandlerThread;
+import android.os.PowerManager;
 import android.text.TextUtils;
 import android.util.Pair;
 import android.util.Slog;
@@ -91,6 +95,7 @@
                     + failedPackage.getVersionCode() + "]");
             return false;
         }
+
         RollbackInfo rollback = rollbackPair.first;
         // We only log mainline package rollbacks, so check if rollback contains the
         // module metadata provider, if it does, the rollback is a mainline rollback
@@ -111,6 +116,12 @@
                             StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_SUCCESS,
                             moduleMetadataPackage.getPackageName(),
                             moduleMetadataPackage.getVersionCode());
+                    if (rollback.isStaged()) {
+                        int rollbackId = rollback.getRollbackId();
+                        BroadcastReceiver listener =
+                                listenForStagedSessionReady(rollbackManager, rollbackId);
+                        handleStagedSessionChange(rollbackManager, rollbackId, listener);
+                    }
                 } else {
                     StatsLog.write(StatsLog.WATCHDOG_ROLLBACK_OCCURRED,
                             StatsLog.WATCHDOG_ROLLBACK_OCCURRED__ROLLBACK_TYPE__ROLLBACK_FAILURE,
@@ -178,4 +189,42 @@
             return null;
         }
     }
+
+    private BroadcastReceiver listenForStagedSessionReady(RollbackManager rollbackManager,
+            int rollbackId) {
+        BroadcastReceiver sessionUpdatedReceiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                handleStagedSessionChange(rollbackManager,
+                        rollbackId, this /* BroadcastReceiver */);
+            }
+        };
+        IntentFilter sessionUpdatedFilter =
+                new IntentFilter(PackageInstaller.ACTION_SESSION_UPDATED);
+        mContext.registerReceiver(sessionUpdatedReceiver, sessionUpdatedFilter);
+        return sessionUpdatedReceiver;
+    }
+
+    private void handleStagedSessionChange(RollbackManager rollbackManager, int rollbackId,
+            BroadcastReceiver listener) {
+        PackageInstaller packageInstaller =
+                mContext.getPackageManager().getPackageInstaller();
+        List<RollbackInfo> recentRollbacks =
+                rollbackManager.getRecentlyCommittedRollbacks();
+        for (int i = 0; i < recentRollbacks.size(); i++) {
+            RollbackInfo recentRollback = recentRollbacks.get(i);
+            int sessionId = recentRollback.getCommittedSessionId();
+            if ((rollbackId == recentRollback.getRollbackId())
+                    && (sessionId != PackageInstaller.SessionInfo.INVALID_ID)) {
+                PackageInstaller.SessionInfo sessionInfo =
+                        packageInstaller.getSessionInfo(sessionId);
+                if (sessionInfo.isSessionReady()) {
+                    mContext.unregisterReceiver(listener);
+                    mContext.getSystemService(PowerManager.class).reboot("Rollback staged install");
+                } else if (sessionInfo.isSessionFailed()) {
+                    mContext.unregisterReceiver(listener);
+                }
+            }
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/rollback/RollbackStore.java b/services/core/java/com/android/server/rollback/RollbackStore.java
index d17ebae..be904ea 100644
--- a/services/core/java/com/android/server/rollback/RollbackStore.java
+++ b/services/core/java/com/android/server/rollback/RollbackStore.java
@@ -23,6 +23,7 @@
 import android.content.rollback.RollbackInfo;
 import android.util.IntArray;
 import android.util.Log;
+import android.util.SparseLongArray;
 
 import libcore.io.IoUtils;
 
@@ -160,6 +161,28 @@
         return restoreInfos;
     }
 
+    private static @NonNull JSONArray ceSnapshotInodesToJson(
+            @NonNull SparseLongArray ceSnapshotInodes) throws JSONException {
+        JSONArray array = new JSONArray();
+        for (int i = 0; i < ceSnapshotInodes.size(); i++) {
+            JSONObject entryJson = new JSONObject();
+            entryJson.put("userId", ceSnapshotInodes.keyAt(i));
+            entryJson.put("ceSnapshotInode", ceSnapshotInodes.valueAt(i));
+            array.put(entryJson);
+        }
+        return array;
+    }
+
+    private static @NonNull SparseLongArray ceSnapshotInodesFromJson(JSONArray json)
+            throws JSONException {
+        SparseLongArray ceSnapshotInodes = new SparseLongArray(json.length());
+        for (int i = 0; i < json.length(); i++) {
+            JSONObject entry = json.getJSONObject(i);
+            ceSnapshotInodes.append(entry.getInt("userId"), entry.getLong("ceSnapshotInode"));
+        }
+        return ceSnapshotInodes;
+    }
+
     /**
      * Reads the list of recently executed rollbacks from persistent storage.
      */
@@ -263,8 +286,6 @@
      * rollback.
      */
     void deleteAvailableRollback(RollbackData data) {
-        // TODO(narayan): Make sure we delete the userdata snapshot along with the backup of the
-        // actual app.
         removeFile(data.backupDir);
     }
 
@@ -341,11 +362,15 @@
 
         IntArray pendingBackups = info.getPendingBackups();
         List<RestoreInfo> pendingRestores = info.getPendingRestores();
+        IntArray installedUsers = info.getInstalledUsers();
         json.put("pendingBackups", convertToJsonArray(pendingBackups));
         json.put("pendingRestores", convertToJsonArray(pendingRestores));
 
         json.put("isApex", info.isApex());
 
+        json.put("installedUsers", convertToJsonArray(installedUsers));
+        json.put("ceSnapshotInodes", ceSnapshotInodesToJson(info.getCeSnapshotInodes()));
+
         return json;
     }
 
@@ -362,8 +387,12 @@
 
         final boolean isApex = json.getBoolean("isApex");
 
+        final IntArray installedUsers = convertToIntArray(json.getJSONArray("installedUsers"));
+        final SparseLongArray ceSnapshotInodes = ceSnapshotInodesFromJson(
+                json.getJSONArray("ceSnapshotInodes"));
+
         return new PackageRollbackInfo(versionRolledBackFrom, versionRolledBackTo,
-                pendingBackups, pendingRestores, isApex);
+                pendingBackups, pendingRestores, isApex, installedUsers, ceSnapshotInodes);
     }
 
     private JSONArray versionedPackagesToJson(List<VersionedPackage> packages)
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index 3586772..dd2cda2 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -45,6 +45,8 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PermissionInfo;
 import android.content.pm.UserInfo;
+import android.hardware.biometrics.BiometricsProtoEnums;
+import android.hardware.face.FaceManager;
 import android.hardware.fingerprint.FingerprintManager;
 import android.net.ConnectivityManager;
 import android.net.INetworkStatsService;
@@ -1419,23 +1421,35 @@
         }
     }
 
-    private void pullNumFingerprints(int tagId, long elapsedNanos, long wallClockNanos,
-            List<StatsLogEventWrapper> pulledData) {
+    private void pullNumBiometricsEnrolled(int modality, int tagId, long elapsedNanos,
+            long wallClockNanos, List<StatsLogEventWrapper> pulledData) {
         FingerprintManager fingerprintManager = mContext.getSystemService(FingerprintManager.class);
-        if (fingerprintManager == null) {
+        FaceManager faceManager = mContext.getSystemService(FaceManager.class);
+        if (modality == BiometricsProtoEnums.MODALITY_FINGERPRINT && fingerprintManager == null) {
+            return;
+        }
+        if (modality == BiometricsProtoEnums.MODALITY_FACE && faceManager == null) {
             return;
         }
         UserManager userManager = mContext.getSystemService(UserManager.class);
         if (userManager == null) {
             return;
         }
+
         final long token = Binder.clearCallingIdentity();
         for (UserInfo user : userManager.getUsers()) {
             final int userId = user.getUserHandle().getIdentifier();
-            final int numFingerprints = fingerprintManager.getEnrolledFingerprints(userId).size();
+            int numEnrolled = 0;
+            if (modality == BiometricsProtoEnums.MODALITY_FINGERPRINT) {
+                numEnrolled = fingerprintManager.getEnrolledFingerprints(userId).size();
+            } else if (modality == BiometricsProtoEnums.MODALITY_FACE) {
+                numEnrolled = faceManager.getEnrolledFaces(userId).size();
+            } else {
+                return;
+            }
             StatsLogEventWrapper e = new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
             e.writeInt(userId);
-            e.writeInt(numFingerprints);
+            e.writeInt(numEnrolled);
             pulledData.add(e);
         }
         Binder.restoreCallingIdentity(token);
@@ -2027,7 +2041,13 @@
                 break;
             }
             case StatsLog.NUM_FINGERPRINTS_ENROLLED: {
-                pullNumFingerprints(tagId, elapsedNanos, wallClockNanos, ret);
+                pullNumBiometricsEnrolled(BiometricsProtoEnums.MODALITY_FINGERPRINT, tagId,
+                        elapsedNanos, wallClockNanos, ret);
+                break;
+            }
+            case StatsLog.NUM_FACES_ENROLLED: {
+                pullNumBiometricsEnrolled(BiometricsProtoEnums.MODALITY_FACE, tagId, elapsedNanos,
+                        wallClockNanos, ret);
                 break;
             }
             case StatsLog.PROC_STATS: {
diff --git a/services/core/java/com/android/server/testharness/TestHarnessModeService.java b/services/core/java/com/android/server/testharness/TestHarnessModeService.java
index 4adce58..ec62ec7 100644
--- a/services/core/java/com/android/server/testharness/TestHarnessModeService.java
+++ b/services/core/java/com/android/server/testharness/TestHarnessModeService.java
@@ -22,6 +22,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.UserInfo;
+import android.debug.AdbManagerInternal;
 import android.os.BatteryManager;
 import android.os.Binder;
 import android.os.IBinder;
@@ -42,6 +43,7 @@
 import java.io.ByteArrayOutputStream;
 import java.io.DataInputStream;
 import java.io.DataOutputStream;
+import java.io.File;
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.InputStream;
@@ -49,7 +51,6 @@
 import java.io.PrintWriter;
 import java.nio.file.Files;
 import java.nio.file.Path;
-import java.nio.file.Paths;
 import java.nio.file.attribute.PosixFilePermission;
 import java.util.Set;
 
@@ -85,6 +86,7 @@
                 break;
             case PHASE_BOOT_COMPLETED:
                 disableAutoSync();
+                configureSettings();
                 break;
         }
         super.onBootPhase(phase);
@@ -98,31 +100,19 @@
             return;
         }
         mShouldSetUpTestHarnessMode = true;
+        setUpAdb(testHarnessModeData);
+        setDeviceProvisioned();
+    }
+
+    private void setUpAdb(byte[] testHarnessModeData) {
+        ContentResolver cr = getContext().getContentResolver();
+        // Disable the TTL for ADB keys before enabling ADB
+        Settings.Global.putLong(cr, Settings.Global.ADB_ALLOWED_CONNECTION_TIME, 0);
+
         PersistentData persistentData = PersistentData.fromBytes(testHarnessModeData);
 
         SystemProperties.set(TEST_HARNESS_MODE_PROPERTY, persistentData.mEnabled ? "1" : "0");
         writeAdbKeysFile(persistentData);
-        // Clear out the data block so that we don't revert the ADB keys on every boot.
-        getPersistentDataBlock().clearTestHarnessModeData();
-
-        ContentResolver cr = getContext().getContentResolver();
-        if (Settings.Global.getInt(cr, Settings.Global.ADB_ENABLED, 0) == 0) {
-            // Enable ADB
-            Settings.Global.putInt(cr, Settings.Global.ADB_ENABLED, 1);
-        } else {
-            // ADB is already enabled, we should restart the service so it picks up the new keys
-            android.os.SystemService.restart("adbd");
-        }
-
-        Settings.Global.putInt(cr, Settings.Global.PACKAGE_VERIFIER_ENABLE, 0);
-        Settings.Global.putInt(
-                cr,
-                Settings.Global.STAY_ON_WHILE_PLUGGED_IN,
-                BatteryManager.BATTERY_PLUGGED_ANY);
-        Settings.Global.putInt(cr, Settings.Global.OTA_DISABLE_AUTOMATIC_UPDATE, 1);
-        Settings.Global.putInt(cr, Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 1);
-
-        setDeviceProvisioned();
     }
 
     private void disableAutoSync() {
@@ -134,11 +124,36 @@
             .setMasterSyncAutomaticallyAsUser(false, primaryUser.getUserHandle().getIdentifier());
     }
 
+    private void configureSettings() {
+        if (!mShouldSetUpTestHarnessMode) {
+            return;
+        }
+        ContentResolver cr = getContext().getContentResolver();
+
+        Settings.Global.putInt(cr, Settings.Global.ADB_ENABLED, 1);
+        Settings.Global.putInt(cr, Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 1);
+        Settings.Global.putInt(cr, Settings.Global.PACKAGE_VERIFIER_ENABLE, 0);
+        Settings.Global.putInt(
+                cr,
+                Settings.Global.STAY_ON_WHILE_PLUGGED_IN,
+                BatteryManager.BATTERY_PLUGGED_ANY);
+        Settings.Global.putInt(cr, Settings.Global.OTA_DISABLE_AUTOMATIC_UPDATE, 1);
+    }
+
     private void writeAdbKeysFile(PersistentData persistentData) {
-        Path adbKeys = Paths.get("/data/misc/adb/adb_keys");
+        AdbManagerInternal adbManager = LocalServices.getService(AdbManagerInternal.class);
+
+        writeBytesToFile(persistentData.mAdbKeys, adbManager.getAdbKeysFile().toPath());
+        writeBytesToFile(persistentData.mAdbTempKeys, adbManager.getAdbTempKeysFile().toPath());
+
+        // Clear out the data block so that we don't revert the ADB keys on every boot.
+        getPersistentDataBlock().clearTestHarnessModeData();
+    }
+
+    private void writeBytesToFile(byte[] keys, Path adbKeys) {
         try {
             OutputStream fileOutputStream = Files.newOutputStream(adbKeys);
-            fileOutputStream.write(persistentData.mAdbKeys);
+            fileOutputStream.write(keys);
             fileOutputStream.close();
 
             Set<PosixFilePermission> permissions = Files.getPosixFilePermissions(adbKeys);
@@ -219,23 +234,22 @@
         }
 
         private int handleEnable() {
-            Path adbKeys = Paths.get("/data/misc/adb/adb_keys");
-            if (!Files.exists(adbKeys)) {
+            AdbManagerInternal adbManager = LocalServices.getService(AdbManagerInternal.class);
+            File adbKeys = adbManager.getAdbKeysFile();
+            File adbTempKeys = adbManager.getAdbTempKeysFile();
+            if (adbKeys == null && adbTempKeys == null) {
                 // This should only be accessible on eng builds that haven't yet set up ADB keys
                 getErrPrintWriter()
                     .println("No ADB keys stored; not enabling test harness mode");
                 return 1;
             }
 
-            try (InputStream inputStream = Files.newInputStream(adbKeys)) {
-                long size = Files.size(adbKeys);
-                byte[] adbKeysBytes = new byte[(int) size];
-                int numBytes = inputStream.read(adbKeysBytes);
-                if (numBytes != size) {
-                    getErrPrintWriter().println("Failed to read all bytes of adb_keys");
-                    return 1;
-                }
-                PersistentData persistentData = new PersistentData(true, adbKeysBytes);
+            try {
+                byte[] adbKeysBytes = getBytesFromFile(adbKeys);
+                byte[] adbTempKeysBytes = getBytesFromFile(adbTempKeys);
+
+                PersistentData persistentData =
+                        new PersistentData(true, adbKeysBytes, adbTempKeysBytes);
                 getPersistentDataBlock().setTestHarnessModeData(persistentData.toBytes());
             } catch (IOException e) {
                 Slog.e(TAG, "Failed to store ADB keys.", e);
@@ -252,6 +266,22 @@
             return 0;
         }
 
+        private byte[] getBytesFromFile(File file) throws IOException {
+            if (file == null || !file.exists()) {
+                return new byte[0];
+            }
+            Path path = file.toPath();
+            try (InputStream inputStream = Files.newInputStream(path)) {
+                int size = (int) Files.size(path);
+                byte[] bytes = new byte[size];
+                int numBytes = inputStream.read(bytes);
+                if (numBytes != size) {
+                    throw new IOException("Failed to read the whole file");
+                }
+                return bytes;
+            }
+        }
+
         @Override
         public void onHelp() {
             PrintWriter pw = getOutPrintWriter();
@@ -290,15 +320,17 @@
         final int mVersion;
         final boolean mEnabled;
         final byte[] mAdbKeys;
+        final byte[] mAdbTempKeys;
 
-        PersistentData(boolean enabled, byte[] adbKeys) {
-            this(VERSION_1, enabled, adbKeys);
+        PersistentData(boolean enabled, byte[] adbKeys, byte[] adbTempKeys) {
+            this(VERSION_1, enabled, adbKeys, adbTempKeys);
         }
 
-        PersistentData(int version, boolean enabled, byte[] adbKeys) {
+        PersistentData(int version, boolean enabled, byte[] adbKeys, byte[] adbTempKeys) {
             this.mVersion = version;
             this.mEnabled = enabled;
             this.mAdbKeys = adbKeys;
+            this.mAdbTempKeys = adbTempKeys;
         }
 
         static PersistentData fromBytes(byte[] bytes) {
@@ -309,7 +341,10 @@
                 int adbKeysLength = is.readInt();
                 byte[] adbKeys = new byte[adbKeysLength];
                 is.readFully(adbKeys);
-                return new PersistentData(version, enabled, adbKeys);
+                int adbTempKeysLength = is.readInt();
+                byte[] adbTempKeys = new byte[adbTempKeysLength];
+                is.readFully(adbTempKeys);
+                return new PersistentData(version, enabled, adbKeys, adbTempKeys);
             } catch (IOException e) {
                 throw new RuntimeException(e);
             }
@@ -323,6 +358,8 @@
                 dos.writeBoolean(mEnabled);
                 dos.writeInt(mAdbKeys.length);
                 dos.write(mAdbKeys);
+                dos.writeInt(mAdbTempKeys.length);
+                dos.write(mAdbTempKeys);
                 dos.close();
                 return os.toByteArray();
             } catch (IOException e) {
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 1163d39..057b53e 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -128,6 +128,8 @@
 
     private final WatchLogHandler mWatchLogHandler;
 
+    private IBinder.DeathRecipient mDeathRecipient;
+
     public TvInputManagerService(Context context) {
         super(context);
 
@@ -674,6 +676,7 @@
                 if (sessionToken == userState.mainSessionToken) {
                     setMainLocked(sessionToken, false, callingUid, userId);
                 }
+                sessionState.session.asBinder().unlinkToDeath(sessionState, 0);
                 sessionState.session.release();
             }
         } catch (RemoteException | SessionNotFoundException e) {
@@ -709,6 +712,7 @@
             clientState.sessionTokens.remove(sessionToken);
             if (clientState.isEmpty()) {
                 userState.clientStateMap.remove(sessionState.client.asBinder());
+                sessionState.client.asBinder().unlinkToDeath(clientState, 0);
             }
         }
 
@@ -1002,17 +1006,19 @@
                 synchronized (mLock) {
                     final UserState userState = getOrCreateUserStateLocked(resolvedUserId);
                     userState.callbackSet.add(callback);
-                    try {
-                        callback.asBinder().linkToDeath(new IBinder.DeathRecipient() {
-                            @Override
-                            public void binderDied() {
-                                synchronized (mLock) {
-                                    if (userState.callbackSet != null) {
-                                        userState.callbackSet.remove(callback);
-                                    }
+                    mDeathRecipient = new IBinder.DeathRecipient() {
+                        @Override
+                        public void binderDied() {
+                            synchronized (mLock) {
+                                if (userState.callbackSet != null) {
+                                    userState.callbackSet.remove(callback);
                                 }
                             }
-                        }, 0);
+                        }
+                    };
+
+                    try {
+                        callback.asBinder().linkToDeath(mDeathRecipient, 0);
                     } catch (RemoteException e) {
                         Slog.e(TAG, "client process has already died", e);
                     }
@@ -1031,6 +1037,7 @@
                 synchronized (mLock) {
                     UserState userState = getOrCreateUserStateLocked(resolvedUserId);
                     userState.callbackSet.remove(callback);
+                    callback.asBinder().unlinkToDeath(mDeathRecipient, 0);
                 }
             } finally {
                 Binder.restoreCallingIdentity(identity);
diff --git a/services/core/java/com/android/server/uri/UriGrantsManagerService.java b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
index 744efab..332df95 100644
--- a/services/core/java/com/android/server/uri/UriGrantsManagerService.java
+++ b/services/core/java/com/android/server/uri/UriGrantsManagerService.java
@@ -1067,8 +1067,9 @@
 
         // Figure out the value returned when access is allowed
         final int allowedResult;
-        if ((modeFlags & Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0) {
-            // If we're extending a persistable grant, then we need to return
+        if ((modeFlags & Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION) != 0
+                || pi.forceUriPermissions) {
+            // If we're extending a persistable grant or need to force, then we need to return
             // "targetUid" so that we always create a grant data structure to
             // support take/release APIs
             allowedResult = targetUid;
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 071dde7..b0ef8a0 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -2243,9 +2243,12 @@
         synchronized (mLock) {
             mInAmbientMode = inAmbientMode;
             final WallpaperData data = mWallpaperMap.get(mCurrentUserId);
+            final boolean hasConnection = data != null && data.connection != null;
+            final WallpaperInfo info = hasConnection ? data.connection.mInfo : null;
+
             // The wallpaper info is null for image wallpaper, also use the engine in this case.
-            if (data != null && data.connection != null && (data.connection.mInfo == null
-                    || data.connection.mInfo.supportsAmbientMode())) {
+            if (hasConnection && (info == null && isAodImageWallpaperEnabled()
+                    || info != null && info.supportsAmbientMode())) {
                 // TODO(multi-display) Extends this method with specific display.
                 engine = data.connection.getDisplayConnectorOrCreate(DEFAULT_DISPLAY).mEngine;
             } else {
diff --git a/services/core/java/com/android/server/wm/ActivityDisplay.java b/services/core/java/com/android/server/wm/ActivityDisplay.java
index 62421ac..f882fde 100644
--- a/services/core/java/com/android/server/wm/ActivityDisplay.java
+++ b/services/core/java/com/android/server/wm/ActivityDisplay.java
@@ -40,6 +40,7 @@
 import static com.android.server.am.ActivityDisplayProto.SINGLE_TASK_INSTANCE;
 import static com.android.server.am.ActivityDisplayProto.STACKS;
 import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
+import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE;
 import static com.android.server.wm.ActivityStackSupervisor.TAG_TASKS;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STACK;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STATES;
@@ -575,7 +576,8 @@
             final ActivityStack stack = mStacks.get(stackNdx);
             final ActivityRecord resumedActivity = stack.getResumedActivity();
             if (resumedActivity != null
-                    && (!stack.shouldBeVisible(resuming) || !stack.isFocusable())) {
+                    && (stack.getVisibility(resuming) != STACK_VISIBILITY_VISIBLE
+                        || !stack.isFocusable())) {
                 if (DEBUG_STATES) Slog.d(TAG_STATES, "pauseBackStacks: stack=" + stack +
                         " mResumedActivity=" + resumedActivity);
                 someActivityPaused |= stack.startPausingLocked(userLeaving, false, resuming,
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index ef40648..4faf910 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -109,6 +109,7 @@
 import static com.android.server.wm.ActivityStack.LAUNCH_TICK;
 import static com.android.server.wm.ActivityStack.LAUNCH_TICK_MSG;
 import static com.android.server.wm.ActivityStack.PAUSE_TIMEOUT_MSG;
+import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE;
 import static com.android.server.wm.ActivityStack.STOP_TIMEOUT_MSG;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_CONFIGURATION;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_FOCUS;
@@ -2054,8 +2055,10 @@
      * @param activeActivity the activity that is active or just completed pause action. We won't
      *                       resume if this activity is active.
      */
-    private boolean shouldResumeActivity(ActivityRecord activeActivity) {
-        return shouldMakeActive(activeActivity) && isFocusable() && !isState(RESUMED);
+    @VisibleForTesting
+    boolean shouldResumeActivity(ActivityRecord activeActivity) {
+        return shouldMakeActive(activeActivity) && isFocusable() && !isState(RESUMED)
+                && getActivityStack().getVisibility(activeActivity) == STACK_VISIBILITY_VISIBLE;
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 6f07be8..cc78588 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -108,6 +108,7 @@
 
 import static java.lang.Integer.MAX_VALUE;
 
+import android.annotation.IntDef;
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
@@ -223,6 +224,22 @@
     // How many activities have to be scheduled to stop to force a stop pass.
     private static final int MAX_STOPPING_TO_FORCE = 3;
 
+    @IntDef(prefix = {"STACK_VISIBILITY"}, value = {
+            STACK_VISIBILITY_VISIBLE,
+            STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
+            STACK_VISIBILITY_INVISIBLE,
+    })
+    @interface StackVisibility {}
+
+    /** Stack is visible. No other stacks on top that fully or partially occlude it. */
+    static final int STACK_VISIBILITY_VISIBLE = 0;
+
+    /** Stack is partially occluded by other translucent stack(s) on top of it. */
+    static final int STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT = 1;
+
+    /** Stack is completely invisible. */
+    static final int STACK_VISIBILITY_INVISIBLE = 2;
+
     @Override
     protected int getChildCount() {
         return mTaskHistory.size();
@@ -1959,14 +1976,28 @@
      * @param starting The currently starting activity or null if there is none.
      */
     boolean shouldBeVisible(ActivityRecord starting) {
+        return getVisibility(starting) != STACK_VISIBILITY_INVISIBLE;
+    }
+
+    /**
+     * Returns true if the stack should be visible.
+     *
+     * @param starting The currently starting activity or null if there is none.
+     */
+    @StackVisibility
+    int getVisibility(ActivityRecord starting) {
         if (!isAttached() || mForceHidden) {
-            return false;
+            return STACK_VISIBILITY_INVISIBLE;
         }
 
         final ActivityDisplay display = getDisplay();
         boolean gotSplitScreenStack = false;
         boolean gotOpaqueSplitScreenPrimary = false;
         boolean gotOpaqueSplitScreenSecondary = false;
+        boolean gotTranslucentFullscreen = false;
+        boolean gotTranslucentSplitScreenPrimary = false;
+        boolean gotTranslucentSplitScreenSecondary = false;
+        boolean shouldBeVisible = true;
         final int windowingMode = getWindowingMode();
         final boolean isAssistantType = isActivityTypeAssistant();
         for (int i = display.getChildCount() - 1; i >= 0; --i) {
@@ -1975,8 +2006,9 @@
             if (other == this) {
                 // Should be visible if there is no other stack occluding it, unless it doesn't
                 // have any running activities, not starting one and not home stack.
-                return hasRunningActivities || isInStackLocked(starting) != null
+                shouldBeVisible = hasRunningActivities || isInStackLocked(starting) != null
                         || isActivityTypeHome();
+                break;
             }
 
             if (!hasRunningActivities) {
@@ -1996,51 +2028,79 @@
                 if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
                     if (activityType == ACTIVITY_TYPE_HOME
                             || (activityType == ACTIVITY_TYPE_ASSISTANT
-                                    && mWindowManager.getRecentsAnimationController() != null)) {
-                       return true;
+                                && mWindowManager.getRecentsAnimationController() != null)) {
+                        break;
                     }
                 }
                 if (other.isStackTranslucent(starting)) {
                     // Can be visible behind a translucent fullscreen stack.
+                    gotTranslucentFullscreen = true;
                     continue;
                 }
-                return false;
+                return STACK_VISIBILITY_INVISIBLE;
             } else if (otherWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
                     && !gotOpaqueSplitScreenPrimary) {
                 gotSplitScreenStack = true;
-                gotOpaqueSplitScreenPrimary =
-                        !other.isStackTranslucent(starting);
+                gotTranslucentSplitScreenPrimary = other.isStackTranslucent(starting);
+                gotOpaqueSplitScreenPrimary = !gotTranslucentSplitScreenPrimary;
                 if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
                         && gotOpaqueSplitScreenPrimary) {
                     // Can not be visible behind another opaque stack in split-screen-primary mode.
-                    return false;
+                    return STACK_VISIBILITY_INVISIBLE;
                 }
             } else if (otherWindowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
                     && !gotOpaqueSplitScreenSecondary) {
                 gotSplitScreenStack = true;
-                gotOpaqueSplitScreenSecondary =
-                        !other.isStackTranslucent(starting);
+                gotTranslucentSplitScreenSecondary = other.isStackTranslucent(starting);
+                gotOpaqueSplitScreenSecondary = !gotTranslucentSplitScreenSecondary;
                 if (windowingMode == WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
                         && gotOpaqueSplitScreenSecondary) {
                     // Can not be visible behind another opaque stack in split-screen-secondary mode.
-                    return false;
+                    return STACK_VISIBILITY_INVISIBLE;
                 }
             }
             if (gotOpaqueSplitScreenPrimary && gotOpaqueSplitScreenSecondary) {
                 // Can not be visible if we are in split-screen windowing mode and both halves of
                 // the screen are opaque.
-                return false;
+                return STACK_VISIBILITY_INVISIBLE;
             }
             if (isAssistantType && gotSplitScreenStack) {
                 // Assistant stack can't be visible behind split-screen. In addition to this not
                 // making sense, it also works around an issue here we boost the z-order of the
                 // assistant window surfaces in window manager whenever it is visible.
-                return false;
+                return STACK_VISIBILITY_INVISIBLE;
             }
         }
 
-        // Well, nothing is stopping you from being visible...
-        return true;
+        if (!shouldBeVisible) {
+            return STACK_VISIBILITY_INVISIBLE;
+        }
+
+        // Handle cases when there can be a translucent split-screen stack on top.
+        switch (windowingMode) {
+            case WINDOWING_MODE_FULLSCREEN:
+                if (gotTranslucentSplitScreenPrimary || gotTranslucentSplitScreenSecondary) {
+                    // At least one of the split-screen stacks that covers this one is translucent.
+                    return STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
+                }
+                break;
+            case WINDOWING_MODE_SPLIT_SCREEN_PRIMARY:
+                if (gotTranslucentSplitScreenPrimary) {
+                    // Covered by translucent primary split-screen on top.
+                    return STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
+                }
+                break;
+            case WINDOWING_MODE_SPLIT_SCREEN_SECONDARY:
+                if (gotTranslucentSplitScreenSecondary) {
+                    // Covered by translucent secondary split-screen on top.
+                    return STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
+                }
+                break;
+        }
+
+        // Lastly - check if there is a translucent fullscreen stack on top.
+        return gotTranslucentFullscreen ? STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT
+                : STACK_VISIBILITY_VISIBLE;
     }
 
     final int rankTaskLayers(int baseLayer) {
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index c0fe6e9..0a3c2fb 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -97,7 +97,6 @@
 import android.app.servertransaction.PauseActivityItem;
 import android.app.servertransaction.ResumeActivityItem;
 import android.content.ComponentName;
-import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
@@ -467,7 +466,7 @@
      * initialized.  So we initialize our wakelocks afterwards.
      */
     void initPowerManagement() {
-        mPowerManager = (PowerManager)mService.mContext.getSystemService(Context.POWER_SERVICE);
+        mPowerManager = mService.mContext.getSystemService(PowerManager.class);
         mGoingToSleep = mPowerManager
                 .newWakeLock(PARTIAL_WAKE_LOCK, "ActivityManager-Sleep");
         mLaunchingActivity = mPowerManager.newWakeLock(PARTIAL_WAKE_LOCK, "*launch*");
@@ -2456,7 +2455,8 @@
     }
 
     void wakeUp(String reason) {
-        mPowerManager.wakeUp(SystemClock.uptimeMillis(), "android.server.am:TURN_ON:" + reason);
+        mPowerManager.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_APPLICATION,
+                "android.server.am:TURN_ON:" + reason);
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 1d71d876..678a896 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -753,8 +753,8 @@
                 Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                         "shouldAbortBackgroundActivityStart");
                 abortBackgroundStart = shouldAbortBackgroundActivityStart(callingUid, callingPid,
-                        callingPackage, realCallingUid, callerApp, originatingPendingIntent,
-                        allowBackgroundActivityStart, intent);
+                        callingPackage, realCallingUid, realCallingPid, callerApp,
+                        originatingPendingIntent, allowBackgroundActivityStart, intent);
             } finally {
                 Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
             }
@@ -914,22 +914,14 @@
     }
 
     private boolean shouldAbortBackgroundActivityStart(int callingUid, int callingPid,
-            final String callingPackage, int realCallingUid, WindowProcessController callerApp,
-            PendingIntentRecord originatingPendingIntent, boolean allowBackgroundActivityStart,
-            Intent intent) {
+            final String callingPackage, int realCallingUid, int realCallingPid,
+            WindowProcessController callerApp, PendingIntentRecord originatingPendingIntent,
+            boolean allowBackgroundActivityStart, Intent intent) {
         // don't abort for the most important UIDs
         if (callingUid == Process.ROOT_UID || callingUid == Process.SYSTEM_UID
                 || callingUid == Process.NFC_UID) {
             return false;
         }
-        // don't abort if the callerApp has any visible activity
-        if (callerApp != null && callerApp.hasForegroundActivities()) {
-            return false;
-        }
-        // don't abort if the callerApp is instrumenting with background activity starts privileges
-        if (callerApp != null && callerApp.isInstrumentingWithBackgroundActivityStartPrivileges()) {
-            return false;
-        }
         // don't abort if the callingUid is in the foreground or is a persistent system process
         final int callingUidProcState = mService.getUidStateLocked(callingUid);
         final boolean callingUidHasAnyVisibleWindow =
@@ -967,9 +959,26 @@
                 return false;
             }
         }
-        // don't abort if the caller is currently temporarily whitelisted
-        if (callerApp != null && callerApp.areBackgroundActivityStartsAllowed()) {
-            return false;
+        // If we don't have callerApp at this point, no caller was provided to startActivity().
+        // That's the case for PendingIntent-based starts, since the creator's process might not be
+        // up and alive. If that's the case, we retrieve the WindowProcessController for the send()
+        // caller, so that we can make the decision based on its foreground/whitelisted state.
+        if (callerApp == null) {
+            callerApp = mService.getProcessController(realCallingPid, realCallingUid);
+        }
+        if (callerApp != null) {
+            // don't abort if the callerApp has any visible activity
+            if (callerApp.hasForegroundActivities()) {
+                return false;
+            }
+            // don't abort if the callerApp is instrumenting with background activity starts privs
+            if (callerApp.isInstrumentingWithBackgroundActivityStartPrivileges()) {
+                return false;
+            }
+            // don't abort if the caller is currently temporarily whitelisted
+            if (callerApp.areBackgroundActivityStartsAllowed()) {
+                return false;
+            }
         }
         // don't abort if the callingUid has START_ACTIVITIES_FROM_BACKGROUND permission
         if (mService.checkPermission(START_ACTIVITIES_FROM_BACKGROUND, callingPid, callingUid)
@@ -996,6 +1005,7 @@
                 + "; originatingPendingIntent: " + originatingPendingIntent
                 + "; isBgStartWhitelisted: " + allowBackgroundActivityStart
                 + "; intent: " + intent
+                + "; callerApp: " + callerApp
                 + "]");
         // log aborted activity start to TRON
         if (mService.isActivityStartsLoggingEnabled()) {
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index b6bac613..875fc4e 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -1383,6 +1383,7 @@
                 .setProfilerInfo(profilerInfo)
                 .setActivityOptions(bOptions)
                 .setMayWait(userId)
+                .setAllowBackgroundActivityStart(true)
                 .execute();
     }
 
@@ -1398,6 +1399,7 @@
                 .setResolvedType(resolvedType)
                 .setActivityOptions(bOptions)
                 .setMayWait(userId)
+                .setAllowBackgroundActivityStart(true)
                 .execute();
     }
 
@@ -5666,6 +5668,20 @@
         return null;
     }
 
+    WindowProcessController getProcessController(int pid, int uid) {
+        final ArrayMap<String, SparseArray<WindowProcessController>> pmap = mProcessNames.getMap();
+        for (int i = pmap.size()-1; i >= 0; i--) {
+            final SparseArray<WindowProcessController> procs = pmap.valueAt(i);
+            for (int j = procs.size() - 1; j >= 0; j--) {
+                final WindowProcessController proc = procs.valueAt(j);
+                if (UserHandle.isApp(uid) && proc.getPid() == pid && proc.mUid == uid) {
+                    return proc;
+                }
+            }
+        }
+        return null;
+    }
+
     int getUidStateLocked(int uid) {
         return mActiveUids.get(uid, PROCESS_STATE_NONEXISTENT);
     }
diff --git a/services/core/java/com/android/server/wm/AppWindowThumbnail.java b/services/core/java/com/android/server/wm/AppWindowThumbnail.java
index 6fcc331..5519729 100644
--- a/services/core/java/com/android/server/wm/AppWindowThumbnail.java
+++ b/services/core/java/com/android/server/wm/AppWindowThumbnail.java
@@ -143,7 +143,7 @@
 
     void destroy() {
         mSurfaceAnimator.cancelAnimation();
-        mSurfaceControl.destroy();
+        getPendingTransaction().remove(mSurfaceControl);
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 3246a87..bcf6aba 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -1275,7 +1275,19 @@
     void onDisplayChanged(DisplayContent dc) {
         DisplayContent prevDc = mDisplayContent;
         super.onDisplayChanged(dc);
-        if (prevDc != null && prevDc.mFocusedApp == this) {
+        if (prevDc == null) {
+            return;
+        }
+        if (prevDc.mChangingApps.contains(this)) {
+            // This gets called *after* the AppWindowToken has been reparented to the new display.
+            // That reparenting resulted in this window changing modes (eg. FREEFORM -> FULLSCREEN),
+            // so this token is now "frozen" while waiting for the animation to start on prevDc
+            // (which will be cancelled since the window is no-longer a child). However, since this
+            // is no longer a child of prevDc, this won't be notified of the cancelled animation,
+            // so we need to cancel the change transition here.
+            clearChangeLeash(getPendingTransaction(), true /* cancel */);
+        }
+        if (prevDc.mFocusedApp == this) {
             prevDc.setFocusedApp(null);
             final TaskStack stack = dc.getTopStack();
             if (stack != null) {
@@ -1584,7 +1596,10 @@
     }
 
     private boolean shouldStartChangeTransition(int prevWinMode, int newWinMode) {
-        if (!isVisible() || getDisplayContent().mAppTransition.isTransitionSet()) {
+        if (mWmService.mDisableTransitionAnimation
+                || !isVisible()
+                || getDisplayContent().mAppTransition.isTransitionSet()
+                || getSurfaceControl() == null) {
             return false;
         }
         // Only do an animation into and out-of freeform mode for now. Other mode
@@ -2504,7 +2519,7 @@
     public void onAnimationLeashDestroyed(Transaction t) {
         super.onAnimationLeashDestroyed(t);
         if (mAnimationBoundsLayer != null) {
-            t.reparent(mAnimationBoundsLayer, null);
+            t.remove(mAnimationBoundsLayer);
             mAnimationBoundsLayer = null;
         }
 
@@ -2561,9 +2576,7 @@
             return;
         } else if (mTransitChangeLeash != null) {
             // unparent mTransitChangeLeash for clean-up
-            t.hide(mTransitChangeLeash);
-            t.reparent(mTransitChangeLeash, null);
-            mTransitChangeLeash = null;
+            clearChangeLeash(t, false /* cancel */);
         }
 
         if (mAnimatingAppWindowTokenRegistry != null) {
@@ -2659,15 +2672,36 @@
         return super.isSelfAnimating();
     }
 
+    /**
+     * @param cancel {@code true} if clearing the leash due to cancelling instead of transferring
+     *                            to another leash.
+     */
+    private void clearChangeLeash(Transaction t, boolean cancel) {
+        if (mTransitChangeLeash == null) {
+            return;
+        }
+        if (cancel) {
+            clearThumbnail();
+            SurfaceControl sc = getSurfaceControl();
+            SurfaceControl parentSc = getParentSurfaceControl();
+            // Don't reparent if surface is getting destroyed
+            if (parentSc != null && sc != null) {
+                t.reparent(sc, getParentSurfaceControl());
+            }
+        }
+        t.hide(mTransitChangeLeash);
+        t.reparent(mTransitChangeLeash, null);
+        mTransitChangeLeash = null;
+        if (cancel) {
+            onAnimationLeashDestroyed(t);
+        }
+    }
+
     @Override
     void cancelAnimation() {
         cancelAnimationOnly();
         clearThumbnail();
-        if (mTransitChangeLeash != null) {
-            getPendingTransaction().hide(mTransitChangeLeash);
-            getPendingTransaction().reparent(mTransitChangeLeash, null);
-            mTransitChangeLeash = null;
-        }
+        clearChangeLeash(getPendingTransaction(), true /* cancel */);
     }
 
     /**
@@ -3003,7 +3037,9 @@
     void removeFromPendingTransition() {
         if (isWaitingForTransitionStart() && mDisplayContent != null) {
             mDisplayContent.mOpeningApps.remove(this);
-            mDisplayContent.mChangingApps.remove(this);
+            if (mDisplayContent.mChangingApps.remove(this)) {
+                clearChangeLeash(getPendingTransaction(), true /* cancel */);
+            }
             mDisplayContent.mClosingApps.remove(this);
         }
     }
diff --git a/services/core/java/com/android/server/wm/BlackFrame.java b/services/core/java/com/android/server/wm/BlackFrame.java
index c90f5bf..497e412 100644
--- a/services/core/java/com/android/server/wm/BlackFrame.java
+++ b/services/core/java/com/android/server/wm/BlackFrame.java
@@ -153,7 +153,7 @@
                 if (mBlackSurfaces[i] != null) {
                     if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) Slog.i(TAG_WM,
                             "  BLACK " + mBlackSurfaces[i].surface + ": DESTROY");
-                    mBlackSurfaces[i].surface.destroy();
+                    mBlackSurfaces[i].surface.remove();
                     mBlackSurfaces[i] = null;
                 }
             }
diff --git a/services/core/java/com/android/server/wm/Dimmer.java b/services/core/java/com/android/server/wm/Dimmer.java
index c39060e..1373e18 100644
--- a/services/core/java/com/android/server/wm/Dimmer.java
+++ b/services/core/java/com/android/server/wm/Dimmer.java
@@ -129,7 +129,7 @@
             final DimAnimatable dimAnimatable = new DimAnimatable(dimLayer);
             mSurfaceAnimator = new SurfaceAnimator(dimAnimatable, () -> {
                 if (!mDimming) {
-                    dimAnimatable.getPendingTransaction().reparent(mDimLayer, null);
+                    dimAnimatable.getPendingTransaction().remove(mDimLayer);
                 }
             }, mHost.mWmService);
         }
@@ -300,7 +300,7 @@
 
         if (!mDimState.mDimming) {
             if (!mDimState.mAnimateExit) {
-                t.reparent(mDimState.mDimLayer, null);
+                t.remove(mDimState.mDimLayer);
             } else {
                 startDimExit(mLastRequestedDimContainer, mDimState.mSurfaceAnimator, t);
             }
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 18df88b..5cfc20b 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -23,7 +23,6 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
-import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
@@ -33,14 +32,12 @@
 import static android.view.Display.FLAG_PRIVATE;
 import static android.view.Display.INVALID_DISPLAY;
 import static android.view.InsetsState.TYPE_IME;
-import static android.view.InsetsState.TYPE_NAVIGATION_BAR;
-import static android.view.InsetsState.TYPE_TOP_BAR;
 import static android.view.Surface.ROTATION_0;
 import static android.view.Surface.ROTATION_180;
 import static android.view.Surface.ROTATION_270;
 import static android.view.Surface.ROTATION_90;
 import static android.view.View.GONE;
-import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
+import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE;
 import static android.view.WindowManager.DOCKED_BOTTOM;
 import static android.view.WindowManager.DOCKED_INVALID;
 import static android.view.WindowManager.DOCKED_TOP;
@@ -141,6 +138,7 @@
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
+import android.graphics.Insets;
 import android.graphics.Matrix;
 import android.graphics.Rect;
 import android.graphics.RectF;
@@ -1162,14 +1160,12 @@
     @Override
     boolean onDescendantOrientationChanged(IBinder freezeDisplayToken,
             ConfigurationContainer requestingContainer) {
-        final int previousRotation = mRotation;
         final Configuration config = updateOrientationFromAppTokens(
                 getRequestedOverrideConfiguration(), freezeDisplayToken, false);
-        // This event is considered handled iff a configuration propagation is triggered, because
-        // that's the only place lower level containers check if they need to do something to this
-        // request. The only guaranteed signal is that the display is rotated to a different
-        // orientation (i.e. rotating 180 degrees doesn't count).
-        final boolean handled = (mRotation - previousRotation) % 2 != 0;
+        // If display rotation class tells us that it doesn't consider app requested orientation,
+        // this display won't rotate just because of an app changes its requested orientation. Thus
+        // it indicates that this display chooses not to handle this request.
+        final boolean handled = getDisplayRotation().respectAppRequestedOrientation();
         if (config == null) {
             return handled;
         }
@@ -1191,6 +1187,11 @@
         return handled;
     }
 
+    @Override
+    boolean handlesOrientationChangeFromDescendant() {
+        return getDisplayRotation().respectAppRequestedOrientation();
+    }
+
     /**
      * Determine the new desired orientation of this display.
      *
@@ -1371,8 +1372,7 @@
 
         if (DEBUG_ORIENTATION) Slog.v(TAG_WM, "Display id=" + mDisplayId
                 + " selected orientation " + lastOrientation
-                + ", got rotation " + rotation + " which has "
-                + " metrics");
+                + ", got rotation " + rotation);
 
         if (oldRotation == rotation) {
             // No change.
@@ -3253,6 +3253,36 @@
         mInputMethodTargetWaitingAnim = targetWaitingAnim;
         assignWindowLayers(false /* setLayoutNeeded */);
         mInsetsStateController.onImeTargetChanged(target);
+        updateImeParent();
+    }
+
+    private void updateImeParent() {
+        if (ViewRootImpl.sNewInsetsMode == NEW_INSETS_MODE_NONE) {
+            return;
+        }
+        final SurfaceControl newParent = computeImeParent();
+        if (newParent != null) {
+            mPendingTransaction.reparent(mImeWindowsContainers.mSurfaceControl, newParent);
+            scheduleAnimation();
+        }
+    }
+
+    /**
+     * Computes the window the IME should be attached to.
+     */
+    @VisibleForTesting
+    SurfaceControl computeImeParent() {
+
+        // Attach it to app if the target is part of an app and such app is covering the entire
+        // screen. If it's not covering the entire screen the IME might extend beyond the apps
+        // bounds.
+        if (mInputMethodTarget != null && mInputMethodTarget.mAppToken != null &&
+                mInputMethodTarget.getWindowingMode() == WINDOWING_MODE_FULLSCREEN) {
+            return mInputMethodTarget.mAppToken.getSurfaceControl();
+        }
+
+        // Otherwise, we just attach it to the display.
+        return mWindowingLayer;
     }
 
     boolean getNeedsMenu(WindowState top, WindowManagerPolicy.WindowState bottom) {
@@ -4420,13 +4450,13 @@
                         .show(mSplitScreenDividerAnchor);
                 scheduleAnimation();
             } else {
-                mAppAnimationLayer.destroy();
+                mAppAnimationLayer.remove();
                 mAppAnimationLayer = null;
-                mBoostedAppAnimationLayer.destroy();
+                mBoostedAppAnimationLayer.remove();
                 mBoostedAppAnimationLayer = null;
-                mHomeAppAnimationLayer.destroy();
+                mHomeAppAnimationLayer.remove();
                 mHomeAppAnimationLayer = null;
-                mSplitScreenDividerAnchor.destroy();
+                mSplitScreenDividerAnchor.remove();
                 mSplitScreenDividerAnchor = null;
             }
         }
@@ -4887,6 +4917,11 @@
                 .reparent(mWindowingLayer, sc).reparent(mOverlayLayer, sc);
     }
 
+    @VisibleForTesting
+    SurfaceControl getWindowingLayer() {
+        return mWindowingLayer;
+    }
+
     /**
      * Create a portal window handle for input. This window transports any touch to the display
      * indicated by {@link InputWindowHandle#portalToDisplayId} if the touch hits this window.
@@ -4911,4 +4946,19 @@
         portalWindowHandle.portalToDisplayId = mDisplayId;
         return portalWindowHandle;
     }
+
+    /**
+     * @see IWindowManager#setForwardedInsets
+     */
+    public void setForwardedInsets(Insets insets) {
+        if (insets == null) {
+            insets = Insets.NONE;
+        }
+        if (mDisplayPolicy.getForwardedInsets().equals(insets)) {
+            return;
+        }
+        mDisplayPolicy.setForwardedInsets(insets);
+        setLayoutNeeded();
+        mWmService.mWindowPlacerLocked.requestTraversal();
+    }
 }
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index bbf115f..2ee30ac 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -27,6 +27,7 @@
 import static android.content.res.Configuration.UI_MODE_TYPE_MASK;
 import static android.view.InsetsState.TYPE_TOP_BAR;
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE;
 import static android.view.WindowManager.INPUT_CONSUMER_NAVIGATION;
 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
 import static android.view.WindowManager.LayoutParams.FIRST_SYSTEM_WINDOW;
@@ -103,6 +104,7 @@
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowManagerService.localLOGV;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.ActivityThread;
@@ -110,6 +112,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Resources;
+import android.graphics.Insets;
 import android.graphics.Rect;
 import android.hardware.input.InputManager;
 import android.hardware.power.V1_0.PowerHint;
@@ -134,6 +137,7 @@
 import android.view.PointerIcon;
 import android.view.Surface;
 import android.view.View;
+import android.view.ViewRootImpl;
 import android.view.WindowManager;
 import android.view.WindowManager.LayoutParams;
 import android.view.WindowManagerGlobal;
@@ -339,6 +343,16 @@
 
     private InputConsumer mInputConsumer = null;
 
+    /**
+     * The area covered by system windows which belong to another display. Forwarded insets is set
+     * in case this is a virtual display, this is displayed on another display that has insets, and
+     * the bounds of this display is overlapping with the insets of the host display (e.g. IME is
+     * displayed on the host display, and it covers a part of this virtual display.)
+     * The forwarded insets is used to compute display frames of this virtual display, which will
+     * be then used to layout windows in the virtual display.
+     */
+    @NonNull private Insets mForwardedInsets = Insets.NONE;
+
     // -------- PolicyHandler --------
     private static final int MSG_UPDATE_DREAMING_SLEEP_TOKEN = 1;
     private static final int MSG_REQUEST_TRANSIENT_BARS = 2;
@@ -1362,6 +1376,15 @@
             displayFrames.mDisplayCutoutSafe.top = Math.max(displayFrames.mDisplayCutoutSafe.top,
                     displayFrames.mStable.top);
         }
+
+        // In case this is a virtual display, and the host display has insets that overlap this
+        // virtual display, apply the insets of the overlapped area onto the current and content
+        // frame of this virtual display. This let us layout windows in the virtual display as
+        // expected when the window needs to avoid overlap with the system windows.
+        // TODO: Generalize the forwarded insets, so that we can handle system windows other than
+        // IME.
+        displayFrames.mCurrent.inset(mForwardedInsets);
+        displayFrames.mContent.inset(mForwardedInsets);
     }
 
     private void layoutScreenDecorWindows(DisplayFrames displayFrames) {
@@ -1900,7 +1923,10 @@
                         if (win.isVoiceInteraction()) {
                             cf.set(displayFrames.mVoiceContent);
                         } else {
-                            if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
+                            // IME Insets are handled on the client for ADJUST_RESIZE in the new
+                            // insets world
+                            if (ViewRootImpl.sNewInsetsMode != NEW_INSETS_MODE_NONE
+                                    || adjust != SOFT_INPUT_ADJUST_RESIZE) {
                                 cf.set(displayFrames.mDock);
                             } else {
                                 cf.set(displayFrames.mContent);
@@ -1991,7 +2017,11 @@
                     of.set(displayFrames.mRestricted);
                     df.set(displayFrames.mRestricted);
                     pf.set(displayFrames.mRestricted);
-                    if (adjust != SOFT_INPUT_ADJUST_RESIZE) {
+
+                    // IME Insets are handled on the client for ADJUST_RESIZE in the new insets
+                    // world
+                    if (ViewRootImpl.sNewInsetsMode != NEW_INSETS_MODE_NONE
+                            || adjust != SOFT_INPUT_ADJUST_RESIZE) {
                         cf.set(displayFrames.mDock);
                     } else {
                         cf.set(displayFrames.mContent);
@@ -2718,6 +2748,18 @@
         }
     }
 
+    /**
+     * @see IWindowManager#setForwardedInsets
+     */
+    public void setForwardedInsets(@NonNull Insets forwardedInsets) {
+        mForwardedInsets = forwardedInsets;
+    }
+
+    @NonNull
+    public Insets getForwardedInsets() {
+        return mForwardedInsets;
+    }
+
     @NavigationBarPosition
     int navigationBarPosition(int displayWidth, int displayHeight, int displayRotation) {
         if (navigationBarCanMove() && displayWidth > displayHeight) {
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index bc165dc..5f341ee 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -329,6 +329,15 @@
         return mFixedToUserRotation;
     }
 
+    /**
+     * Returns {@code true} if this display rotation takes app requested orientation into
+     * consideration; {@code false} otherwise. For the time being the only case where this is {@code
+     * false} is when {@link #isFixedToUserRotation()} is {@code true}.
+     */
+    boolean respectAppRequestedOrientation() {
+        return !mFixedToUserRotation;
+    }
+
     public int getLandscapeRotation() {
         return mLandscapeRotation;
     }
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index afae9c4..a1b52f4 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -112,6 +112,7 @@
      * Called when a layout pass has occurred.
      */
     void onPostLayout() {
+        mState.setDisplayFrame(mDisplayContent.getBounds());
         for (int i = mControllers.size() - 1; i>= 0; i--) {
             mControllers.valueAt(i).onPostLayout();
         }
diff --git a/services/core/java/com/android/server/wm/Letterbox.java b/services/core/java/com/android/server/wm/Letterbox.java
index 434084c..9874920 100644
--- a/services/core/java/com/android/server/wm/Letterbox.java
+++ b/services/core/java/com/android/server/wm/Letterbox.java
@@ -107,10 +107,10 @@
         mOuter.setEmpty();
         mInner.setEmpty();
 
-        mTop.destroy();
-        mLeft.destroy();
-        mBottom.destroy();
-        mRight.destroy();
+        mTop.remove();
+        mLeft.remove();
+        mBottom.remove();
+        mRight.remove();
     }
 
     /** Returns whether a call to {@link #applySurfaceChanges} would change the surface. */
@@ -154,9 +154,9 @@
             mSurface.setColor(new float[]{0, 0, 0});
         }
 
-        public void destroy() {
+        public void remove() {
             if (mSurface != null) {
-                mSurface.destroy();
+                mSurface.remove();
                 mSurface = null;
             }
         }
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index 3947bd4..84cd8d1 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -626,7 +626,7 @@
             if (SHOW_TRANSACTIONS ||
                     SHOW_SURFACE_ALLOC) Slog.i(TAG_WM,
                             "  FREEZE " + mSurfaceControl + ": DESTROY");
-            mSurfaceControl.destroy();
+            mSurfaceControl.remove();
             mSurfaceControl = null;
         }
         if (mCustomBlackFrame != null) {
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java
index c600e0f..5ea2451 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimator.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java
@@ -280,7 +280,7 @@
         }
         mService.mAnimationTransferMap.remove(mAnimation);
         if (mLeash != null && destroyLeash) {
-            t.reparent(mLeash, null);
+            t.remove(mLeash);
             scheduleAnim = true;
         }
         mLeash = null;
diff --git a/services/core/java/com/android/server/wm/TEST_MAPPING b/services/core/java/com/android/server/wm/TEST_MAPPING
index bbe5424..b2e8bbe 100644
--- a/services/core/java/com/android/server/wm/TEST_MAPPING
+++ b/services/core/java/com/android/server/wm/TEST_MAPPING
@@ -1,34 +1,4 @@
 {
-  "presubmit": [
-    {
-      "name": "FrameworksServicesTests",
-      "options": [
-        {
-          "include-filter": "com.android.server.wm."
-        },
-        {
-          "include-annotation": "android.platform.test.annotations.Presubmit"
-        },
-        {
-          "exclude-annotation": "androidx.test.filters.FlakyTest"
-        }
-      ]
-    },
-    {
-      "name": "WmTests",
-      "options": [
-        {
-          "include-filter": "com.android.server.wm."
-        },
-        {
-          "include-annotation": "android.platform.test.annotations.Presubmit"
-        },
-        {
-          "exclude-annotation": "androidx.test.filters.FlakyTest"
-        }
-      ]
-    }
-  ],
   "postsubmit": [
     {
       "name": "CtsWindowManagerDeviceTestCases"
diff --git a/services/core/java/com/android/server/wm/TaskRecord.java b/services/core/java/com/android/server/wm/TaskRecord.java
index af38c06..69f0012 100644
--- a/services/core/java/com/android/server/wm/TaskRecord.java
+++ b/services/core/java/com/android/server/wm/TaskRecord.java
@@ -2197,11 +2197,15 @@
             // In FULLSCREEN mode, always start with empty bounds to indicate "fill parent"
             outOverrideBounds.setEmpty();
 
+            final boolean parentHandlesOrientationChange = mTask != null
+                    && mTask.getParent() != null
+                    && mTask.getParent().handlesOrientationChangeFromDescendant();
             // If the task or its top activity requires a different orientation, make it fit the
             // available bounds by scaling down its bounds.
             int forcedOrientation = getTopActivityRequestedOrientation();
             if (forcedOrientation != ORIENTATION_UNDEFINED
-                    && forcedOrientation != newParentConfig.orientation) {
+                    && forcedOrientation != newParentConfig.orientation
+                    && !parentHandlesOrientationChange) {
                 final Rect parentBounds = newParentConfig.windowConfiguration.getBounds();
                 final int parentWidth = parentBounds.width();
                 final int parentHeight = parentBounds.height();
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 53cd5ea..7b742fd 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -1006,7 +1006,7 @@
         EventLog.writeEvent(EventLogTags.WM_STACK_REMOVED, mStackId);
 
         if (mAnimationBackgroundSurface != null) {
-            mAnimationBackgroundSurface.destroy();
+            mAnimationBackgroundSurface.remove();
             mAnimationBackgroundSurface = null;
         }
 
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index b246da4..76f080b 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -320,7 +320,7 @@
         }
 
         if (mSurfaceControl != null) {
-            mPendingTransaction.reparent(mSurfaceControl, null);
+            mPendingTransaction.remove(mSurfaceControl);
 
             // Merge to parent transaction to ensure the transactions on this WindowContainer are
             // applied in native even if WindowContainer is removed.
@@ -715,6 +715,21 @@
     }
 
     /**
+     * Check if this container or its parent will handle orientation changes from descendants. It's
+     * different from the return value of {@link #onDescendantOrientationChanged(IBinder,
+     * ConfigurationContainer)} in the sense that the return value of this method tells if this
+     * container or its parent will handle the request eventually, while the return value of the
+     * other method is if it handled the request synchronously.
+     *
+     * @return {@code true} if it handles or will handle orientation change in the future; {@code
+     *         false} if it won't handle the change at anytime.
+     */
+    boolean handlesOrientationChangeFromDescendant() {
+        final WindowContainer parent = getParent();
+        return parent != null && parent.handlesOrientationChangeFromDescendant();
+    }
+
+    /**
      * Calls {@link #setOrientation(int, IBinder, ActivityRecord)} with {@code null} to the last 2
      * parameters.
      *
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 3bb6608..6c3e1f4 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -134,6 +134,7 @@
 import android.content.res.Configuration;
 import android.database.ContentObserver;
 import android.graphics.Bitmap;
+import android.graphics.Insets;
 import android.graphics.Matrix;
 import android.graphics.Point;
 import android.graphics.Rect;
@@ -6438,6 +6439,23 @@
         }
     }
 
+    @Override
+    public void setForwardedInsets(int displayId, Insets insets) throws RemoteException {
+        synchronized (mGlobalLock) {
+            final DisplayContent dc = mRoot.getDisplayContent(displayId);
+            if (dc == null) {
+                return;
+            }
+            final int callingUid = Binder.getCallingUid();
+            final int displayOwnerUid = dc.getDisplay().getOwnerUid();
+            if (callingUid != displayOwnerUid) {
+                throw new SecurityException(
+                        "Only owner of the display can set ForwardedInsets to it.");
+            }
+            dc.setForwardedInsets(insets);
+        }
+    }
+
     void intersectDisplayInsetBounds(Rect display, Rect insets, Rect inOutBounds) {
         mTmpRect3.set(display);
         mTmpRect3.inset(insets);
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 0fb900a..465f413 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -986,7 +986,7 @@
 
     @Override
     public String toString() {
-        return mOwner.toString();
+        return mOwner != null ? mOwner.toString() : null;
     }
 
     public void dump(PrintWriter pw, String prefix) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 4bc1400..85b251a 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -156,6 +156,7 @@
 import android.os.Debug;
 import android.os.IBinder;
 import android.os.PowerManager;
+import android.os.PowerManager.WakeReason;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.SystemClock;
@@ -611,7 +612,7 @@
     }
 
     interface PowerManagerWrapper {
-        void wakeUp(long time, String reason);
+        void wakeUp(long time, @WakeReason int reason, String details);
 
         boolean isInteractive();
 
@@ -623,8 +624,8 @@
         this(service, s, c, token, parentWindow, appOp, seq, a, viewVisibility, ownerId,
                 ownerCanAddInternalSystemWindow, new PowerManagerWrapper() {
                     @Override
-                    public void wakeUp(long time, String reason) {
-                        service.mPowerManager.wakeUp(time, reason);
+                    public void wakeUp(long time, @WakeReason int reason, String details) {
+                        service.mPowerManager.wakeUp(time, reason, details);
                     }
 
                     @Override
@@ -2253,7 +2254,7 @@
                     Slog.v(TAG, "Relayout window turning screen on: " + this);
                 }
                 mPowerManagerWrapper.wakeUp(SystemClock.uptimeMillis(),
-                        "android.server.wm:TURN_ON");
+                        PowerManager.WAKE_REASON_APPLICATION, "android.server.wm:SCREEN_ON_FLAG");
             }
 
             if (mAppToken != null) {
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index dea3597..e796b99 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -161,7 +161,7 @@
         }
         try {
             if (mSurfaceControl != null) {
-                mSurfaceControl.destroy();
+                mSurfaceControl.remove();
             }
         } catch (RuntimeException e) {
             Slog.w(TAG, "Error destroying surface in: " + this, e);
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index 33317b5..c18e98b 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -373,6 +373,9 @@
     mInputManager->getReader()->dump(dump);
     dump += "\n";
 
+    mInputManager->getClassifier()->dump(dump);
+    dump += "\n";
+
     mInputManager->getDispatcher()->dump(dump);
     dump += "\n";
 }
diff --git a/services/core/jni/com_android_server_security_VerityUtils.cpp b/services/core/jni/com_android_server_security_VerityUtils.cpp
index bf96f9a..6cd9f2c 100644
--- a/services/core/jni/com_android_server_security_VerityUtils.cpp
+++ b/services/core/jni/com_android_server_security_VerityUtils.cpp
@@ -122,7 +122,7 @@
     }
 
     ~JavaByteArrayHolder() {
-        LOG_ALWAYS_FATAL_IF(mElements == nullptr, "Elements are not released");
+        LOG_ALWAYS_FATAL_IF(mElements != nullptr, "Elements are not released");
     }
 
   private:
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 1155f49..e30acf7 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -12790,10 +12790,6 @@
         }
     }
 
-    // TODO(b/22388012): When backup is available for secondary users and profiles, consider
-    // whether there are any privacy/security implications of enabling the backup service here
-    // if there are other users or profiles unmanaged or managed by a different entity (i.e. not
-    // affiliated).
     @Override
     public void setBackupServiceEnabled(ComponentName admin, boolean enabled) {
         if (!mHasFeature) {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index ab30cda..a6017f2 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -64,6 +64,7 @@
 import android.util.Slog;
 import android.util.TimingsTraceLog;
 import android.view.WindowManager;
+import android.view.contentcapture.ContentCaptureManager;
 import android.view.inputmethod.InputMethodSystemProperty;
 
 import com.android.internal.R;
@@ -2214,33 +2215,30 @@
     }
 
     private void startContentCaptureService(@NonNull Context context) {
-        // Check if it was explicitly enabled by DeviceConfig
-        final String settings = DeviceConfig.getProperty(DeviceConfig.ContentCapture.NAMESPACE,
-                DeviceConfig.ContentCapture.PROPERTY_CONTENTCAPTURE_ENABLED);
-        if (settings == null) {
-            // Better be safe than sorry...
-            Slog.d(TAG, "ContentCaptureService disabled because its not set by OEM");
-            return;
-        }
-        switch (settings) {
-            case "always":
-                // Should be used only during development
+        // First check if it was explicitly enabled by DeviceConfig
+        boolean explicitlySupported = false;
+        String settings = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
+                ContentCaptureManager.DEVICE_CONFIG_PROPERTY_SERVICE_EXPLICITLY_ENABLED);
+        if (settings != null && !settings.equalsIgnoreCase("default")) {
+            explicitlySupported = Boolean.parseBoolean(settings);
+            if (explicitlySupported) {
                 Slog.d(TAG, "ContentCaptureService explicitly enabled by DeviceConfig");
-                break;
-            case "default":
-                // Default case: check if OEM overlaid the resource that defines the service.
-                final String serviceName = context.getString(
-                        com.android.internal.R.string.config_defaultContentCaptureService);
-                if (TextUtils.isEmpty(serviceName)) {
-                    Slog.d(TAG, "ContentCaptureService disabled because resource is not overlaid");
-                    return;
-                }
-                break;
-            default:
-                // Kill switch for OEMs
-                Slog.d(TAG, "ContentCaptureService disabled because its set to: " + settings);
+            } else {
+                Slog.d(TAG, "ContentCaptureService explicitly disabled by DeviceConfig");
                 return;
+            }
         }
+
+        // Then check if OEM overlaid the resource that defines the service.
+        if (!explicitlySupported) {
+            final String serviceName = context
+                    .getString(com.android.internal.R.string.config_defaultContentCaptureService);
+            if (TextUtils.isEmpty(serviceName)) {
+                Slog.d(TAG, "ContentCaptureService disabled because resource is not overlaid");
+                return;
+            }
+        }
+
         traceBeginAndSlog("StartContentCaptureService");
         mSystemServiceManager.startService(CONTENT_CAPTURE_MANAGER_SERVICE_CLASS);
         traceEnd();
diff --git a/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java
index b8db3f3..37909c3 100644
--- a/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/BackupManagerServiceTest.java
@@ -62,6 +62,7 @@
 
 import java.io.File;
 import java.io.FileDescriptor;
+import java.io.IOException;
 import java.io.PrintWriter;
 
 /** Tests for the user-aware backup/restore system service {@link BackupManagerService}. */
@@ -1516,8 +1517,7 @@
     public void testDump_onRegisteredUser_callsMethodForUser() throws Exception {
         BackupManagerService backupManagerService =
                 createServiceAndRegisterUser(UserHandle.USER_SYSTEM, mUserOneService);
-        File testFile = new File(mContext.getFilesDir(), "test");
-        testFile.createNewFile();
+        File testFile = createTestFile();
         FileDescriptor fileDescriptor = new FileDescriptor();
         PrintWriter printWriter = new PrintWriter(testFile);
         String[] args = {"1", "2"};
@@ -1531,8 +1531,7 @@
     @Test
     public void testDump_onUnknownUser_doesNotPropagateCall() throws Exception {
         BackupManagerService backupManagerService = createService();
-        File testFile = new File(mContext.getFilesDir(), "test");
-        testFile.createNewFile();
+        File testFile = createTestFile();
         FileDescriptor fileDescriptor = new FileDescriptor();
         PrintWriter printWriter = new PrintWriter(testFile);
         String[] args = {"1", "2"};
@@ -1542,6 +1541,12 @@
         verify(mUserOneService, never()).dump(fileDescriptor, printWriter, args);
     }
 
+    private File createTestFile() throws IOException {
+        File testFile = new File(mContext.getFilesDir(), "test");
+        testFile.createNewFile();
+        return testFile;
+    }
+
     private BackupManagerService createService() {
         mShadowContext.grantPermissions(BACKUP);
         return new BackupManagerService(
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 427aed7..c8d1eb4 100644
--- a/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java
+++ b/services/robotests/backup/src/com/android/server/backup/UserBackupManagerServiceTest.java
@@ -76,6 +76,7 @@
 import org.robolectric.shadows.ShadowPackageManager;
 
 import java.io.File;
+import java.io.IOException;
 import java.util.List;
 
 /**
@@ -1158,6 +1159,58 @@
     }
 
     /**
+     * Test that {@link UserBackupManagerService#getAncestralSerialNumber()} returns {@code -1}
+     * when value not set.
+     */
+    @Test
+    public void testGetAncestralSerialNumber_notSet_returnsMinusOne() {
+        UserBackupManagerService service = createUserBackupManagerServiceAndRunTasks();
+
+        assertThat(service.getAncestralSerialNumber()).isEqualTo(-1L);
+    }
+
+    /**
+     * Test that {@link UserBackupManagerService#getAncestralSerialNumber()} returns correct value
+     * when value set.
+     */
+    @Test
+    public void testGetAncestralSerialNumber_set_returnsCorrectValue() throws Exception {
+        mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
+        UserBackupManagerService service = createUserBackupManagerServiceAndRunTasks();
+        service.setAncestralSerialNumberFile(createTestFile());
+
+        long testSerialNumber = 20L;
+        service.setAncestralSerialNumber(testSerialNumber);
+
+        assertThat(service.getAncestralSerialNumber()).isEqualTo(testSerialNumber);
+    }
+
+    /**
+     * Test that {@link UserBackupManagerService#getAncestralSerialNumber()} returns correct value
+     * when value set.
+     */
+    @Test
+    public void testGetAncestralSerialNumber_setTwice_returnsCorrectValue() throws Exception {
+        mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
+        UserBackupManagerService service = createUserBackupManagerServiceAndRunTasks();
+        service.setAncestralSerialNumberFile(createTestFile());
+
+        long testSerialNumber = 20L;
+        long testSerialNumber2 = 21L;
+        service.setAncestralSerialNumber(testSerialNumber);
+        service.setAncestralSerialNumber(testSerialNumber2);
+
+        assertThat(service.getAncestralSerialNumber()).isEqualTo(testSerialNumber2);
+    }
+
+    private File createTestFile() throws IOException {
+        File testFile = new File(mContext.getFilesDir(), "test");
+        testFile.createNewFile();
+        return testFile;
+    }
+
+
+    /**
      * We can't mock the void method {@link #schedule(Context, long, BackupManagerConstants)} so we
      * extend {@link ShadowKeyValueBackupJob} and throw an exception at the end of the method.
      */
diff --git a/services/robotests/src/com/android/server/backup/encryption/chunking/ByteRangeTest.java b/services/robotests/src/com/android/server/backup/encryption/chunking/ByteRangeTest.java
new file mode 100644
index 0000000..8df0826
--- /dev/null
+++ b/services/robotests/src/com/android/server/backup/encryption/chunking/ByteRangeTest.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2018 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.encryption.chunking;
+
+import static org.junit.Assert.assertEquals;
+import static org.testng.Assert.assertThrows;
+
+import android.platform.test.annotations.Presubmit;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+
+/** Tests for {@link ByteRange}. */
+@RunWith(RobolectricTestRunner.class)
+@Presubmit
+public class ByteRangeTest {
+    @Test
+    public void getLength_includesEnd() throws Exception {
+        ByteRange byteRange = new ByteRange(5, 10);
+
+        int length = byteRange.getLength();
+
+        assertEquals(6, length);
+    }
+
+    @Test
+    public void constructor_rejectsNegativeStart() {
+        assertThrows(IllegalArgumentException.class, () -> new ByteRange(-1, 10));
+    }
+
+    @Test
+    public void constructor_rejectsEndBeforeStart() {
+        assertThrows(IllegalArgumentException.class, () -> new ByteRange(10, 9));
+    }
+
+    @Test
+    public void extend_withZeroLength_throwsException() {
+        ByteRange byteRange = new ByteRange(5, 10);
+
+        assertThrows(IllegalArgumentException.class, () -> byteRange.extend(0));
+    }
+}
diff --git a/services/robotests/src/com/android/server/backup/encryption/chunking/DiffScriptBackupWriterTest.java b/services/robotests/src/com/android/server/backup/encryption/chunking/DiffScriptBackupWriterTest.java
new file mode 100644
index 0000000..2af6f2b
--- /dev/null
+++ b/services/robotests/src/com/android/server/backup/encryption/chunking/DiffScriptBackupWriterTest.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2018 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.encryption.chunking;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import android.platform.test.annotations.Presubmit;
+
+import com.google.common.primitives.Bytes;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.Mock;
+import org.robolectric.RobolectricTestRunner;
+
+import java.io.IOException;
+
+/** Tests for {@link DiffScriptBackupWriter}. */
+@RunWith(RobolectricTestRunner.class)
+@Presubmit
+public class DiffScriptBackupWriterTest {
+    private static final byte[] TEST_BYTES = {1, 2, 3, 4, 5, 6, 7, 8, 9};
+
+    @Captor private ArgumentCaptor<Byte> mBytesCaptor;
+    @Mock private SingleStreamDiffScriptWriter mDiffScriptWriter;
+    private BackupWriter mBackupWriter;
+
+    @Before
+    public void setUp() {
+        mDiffScriptWriter = mock(SingleStreamDiffScriptWriter.class);
+        mBackupWriter = new DiffScriptBackupWriter(mDiffScriptWriter);
+        mBytesCaptor = ArgumentCaptor.forClass(Byte.class);
+    }
+
+    @Test
+    public void writeBytes_writesBytesToWriter() throws Exception {
+        mBackupWriter.writeBytes(TEST_BYTES);
+
+        verify(mDiffScriptWriter, atLeastOnce()).writeByte(mBytesCaptor.capture());
+        assertThat(mBytesCaptor.getAllValues())
+                .containsExactlyElementsIn(Bytes.asList(TEST_BYTES))
+                .inOrder();
+    }
+
+    @Test
+    public void writeChunk_writesChunkToWriter() throws Exception {
+        mBackupWriter.writeChunk(0, 10);
+
+        verify(mDiffScriptWriter).writeChunk(0, 10);
+    }
+
+    @Test
+    public void getBytesWritten_returnsTotalSum() throws Exception {
+        mBackupWriter.writeBytes(TEST_BYTES);
+        mBackupWriter.writeBytes(TEST_BYTES);
+        mBackupWriter.writeChunk(/*start=*/ 0, /*length=*/ 10);
+
+        long bytesWritten = mBackupWriter.getBytesWritten();
+
+        assertThat(bytesWritten).isEqualTo(2 * TEST_BYTES.length + 10);
+    }
+
+    @Test
+    public void flush_flushesWriter() throws IOException {
+        mBackupWriter.flush();
+
+        verify(mDiffScriptWriter).flush();
+    }
+}
diff --git a/services/robotests/src/com/android/server/backup/encryption/chunking/SingleStreamDiffScriptWriterTest.java b/services/robotests/src/com/android/server/backup/encryption/chunking/SingleStreamDiffScriptWriterTest.java
new file mode 100644
index 0000000..73baf80
--- /dev/null
+++ b/services/robotests/src/com/android/server/backup/encryption/chunking/SingleStreamDiffScriptWriterTest.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2018 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.encryption.chunking;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+import static org.testng.Assert.assertThrows;
+
+import android.platform.test.annotations.Presubmit;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.robolectric.RobolectricTestRunner;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.Locale;
+
+/** Tests for {@link SingleStreamDiffScriptWriter}. */
+@RunWith(RobolectricTestRunner.class)
+@Presubmit
+public class SingleStreamDiffScriptWriterTest {
+    private static final int MAX_CHUNK_SIZE_IN_BYTES = 256;
+    /** By default this Locale does not use Arabic numbers for %d formatting. */
+    private static final Locale HINDI = new Locale("hi", "IN");
+
+    private Locale mDefaultLocale;
+    private ByteArrayOutputStream mOutputStream;
+    private SingleStreamDiffScriptWriter mDiffScriptWriter;
+
+    @Before
+    public void setUp() {
+        mDefaultLocale = Locale.getDefault();
+        mOutputStream = new ByteArrayOutputStream();
+        mDiffScriptWriter =
+                new SingleStreamDiffScriptWriter(mOutputStream, MAX_CHUNK_SIZE_IN_BYTES);
+    }
+
+    @After
+    public void tearDown() {
+        Locale.setDefault(mDefaultLocale);
+    }
+
+    @Test
+    public void writeChunk_withNegativeStart_throwsException() {
+        assertThrows(
+                IllegalArgumentException.class,
+                () -> mDiffScriptWriter.writeChunk(-1, 50));
+    }
+
+    @Test
+    public void writeChunk_withZeroLength_throwsException() {
+        assertThrows(
+                IllegalArgumentException.class,
+                () -> mDiffScriptWriter.writeChunk(0, 0));
+    }
+
+    @Test
+    public void writeChunk_withExistingBytesInBuffer_writesBufferFirst()
+            throws IOException {
+        String testString = "abcd";
+        writeStringAsBytesToWriter(testString, mDiffScriptWriter);
+
+        mDiffScriptWriter.writeChunk(0, 20);
+        mDiffScriptWriter.flush();
+
+        // Expected format: length of abcd, newline, abcd, newline, chunk start - chunk end
+        assertThat(mOutputStream.toString("UTF-8")).isEqualTo(
+                String.format("%d\n%s\n%d-%d\n", testString.length(), testString, 0, 19));
+    }
+
+    @Test
+    public void writeChunk_overlappingPreviousChunk_combinesChunks() throws IOException {
+        mDiffScriptWriter.writeChunk(3, 4);
+
+        mDiffScriptWriter.writeChunk(7, 5);
+        mDiffScriptWriter.flush();
+
+        assertThat(mOutputStream.toString("UTF-8")).isEqualTo(String.format("3-11\n"));
+    }
+
+    @Test
+    public void writeChunk_formatsByteIndexesUsingArabicNumbers() throws Exception {
+        Locale.setDefault(HINDI);
+
+        mDiffScriptWriter.writeChunk(0, 12345);
+        mDiffScriptWriter.flush();
+
+        assertThat(mOutputStream.toString("UTF-8")).isEqualTo("0-12344\n");
+    }
+
+    @Test
+    public void flush_flushesOutputStream() throws IOException {
+        ByteArrayOutputStream mockOutputStream = mock(ByteArrayOutputStream.class);
+        SingleStreamDiffScriptWriter diffScriptWriter =
+                new SingleStreamDiffScriptWriter(mockOutputStream, MAX_CHUNK_SIZE_IN_BYTES);
+
+        diffScriptWriter.flush();
+
+        verify(mockOutputStream).flush();
+    }
+
+    private void writeStringAsBytesToWriter(String string, SingleStreamDiffScriptWriter writer)
+            throws IOException {
+        byte[] bytes = string.getBytes("UTF-8");
+        for (int i = 0; i < bytes.length; i++) {
+            writer.writeByte(bytes[i]);
+        }
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/am/AppCompactorTest.java b/services/tests/servicestests/src/com/android/server/am/AppCompactorTest.java
index 2f8e545..63015be 100644
--- a/services/tests/servicestests/src/com/android/server/am/AppCompactorTest.java
+++ b/services/tests/servicestests/src/com/android/server/am/AppCompactorTest.java
@@ -147,10 +147,10 @@
                 KEY_USE_COMPACTION, "true", false);
         DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
                 KEY_COMPACT_ACTION_1,
-                Integer.toString((AppCompactor.DEFAULT_COMPACT_ACTION_1 + 1 % 3) + 1), false);
+                Integer.toString((AppCompactor.DEFAULT_COMPACT_ACTION_1 + 1 % 4) + 1), false);
         DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
                 KEY_COMPACT_ACTION_2,
-                Integer.toString((AppCompactor.DEFAULT_COMPACT_ACTION_2 + 1 % 3) + 1), false);
+                Integer.toString((AppCompactor.DEFAULT_COMPACT_ACTION_2 + 1 % 4) + 1), false);
         DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
                 KEY_COMPACT_THROTTLE_1,
                 Long.toString(AppCompactor.DEFAULT_COMPACT_THROTTLE_1 + 1), false);
@@ -173,9 +173,9 @@
         assertThat(mCompactorUnderTest.mCompactionThread.isAlive(), is(true));
 
         assertThat(mCompactorUnderTest.mCompactActionSome,
-                is(compactActionIntToString((AppCompactor.DEFAULT_COMPACT_ACTION_1 + 1 % 3) + 1)));
+                is(compactActionIntToString((AppCompactor.DEFAULT_COMPACT_ACTION_1 + 1 % 4) + 1)));
         assertThat(mCompactorUnderTest.mCompactActionFull,
-                is(compactActionIntToString((AppCompactor.DEFAULT_COMPACT_ACTION_2 + 1 % 3) + 1)));
+                is(compactActionIntToString((AppCompactor.DEFAULT_COMPACT_ACTION_2 + 1 % 4) + 1)));
         assertThat(mCompactorUnderTest.mCompactThrottleSomeSome,
                 is(AppCompactor.DEFAULT_COMPACT_THROTTLE_1 + 1));
         assertThat(mCompactorUnderTest.mCompactThrottleSomeFull,
@@ -233,13 +233,13 @@
 
         // When we override new values for the compaction action with reasonable values...
 
-        // There are three possible values for compactAction[Some|Full].
-        for (int i = 1; i < 4; i++) {
+        // There are four possible values for compactAction[Some|Full].
+        for (int i = 1; i < 5; i++) {
             mCountDown = new CountDownLatch(2);
-            int expectedSome = (mCompactorUnderTest.DEFAULT_COMPACT_ACTION_1 + i) % 3 + 1;
+            int expectedSome = (mCompactorUnderTest.DEFAULT_COMPACT_ACTION_1 + i) % 4 + 1;
             DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
                     KEY_COMPACT_ACTION_1, Integer.toString(expectedSome), false);
-            int expectedFull = (mCompactorUnderTest.DEFAULT_COMPACT_ACTION_2 + i) % 3 + 1;
+            int expectedFull = (mCompactorUnderTest.DEFAULT_COMPACT_ACTION_2 + i) % 4 + 1;
             DeviceConfig.setProperty(DeviceConfig.ActivityManager.NAMESPACE,
                     KEY_COMPACT_ACTION_2, Integer.toString(expectedFull), false);
             assertThat(mCountDown.await(5, TimeUnit.SECONDS), is(true));
diff --git a/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java b/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java
index e3b1245..7081d2e 100644
--- a/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/BrightnessTrackerTest.java
@@ -962,13 +962,13 @@
         }
 
         @Override
-        public int getColorTemperature(Context context, int userId) {
+        public int getNightDisplayColorTemperature(Context context) {
           return mSecureIntSettings.getOrDefault(Settings.Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE,
                   mDefaultNightModeColorTemperature);
         }
 
         @Override
-        public boolean isNightModeActive(Context context, int userId) {
+        public boolean isNightDisplayActivated(Context context) {
             return mSecureIntSettings.getOrDefault(Settings.Secure.NIGHT_DISPLAY_ACTIVATED,
                     0) == 1;
         }
diff --git a/services/tests/servicestests/src/com/android/server/display/ColorDisplayServiceTest.java b/services/tests/servicestests/src/com/android/server/display/ColorDisplayServiceTest.java
index 0b01657..5900fc5 100644
--- a/services/tests/servicestests/src/com/android/server/display/ColorDisplayServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/ColorDisplayServiceTest.java
@@ -26,6 +26,7 @@
 import android.content.Context;
 import android.content.ContextWrapper;
 import android.hardware.display.ColorDisplayManager;
+import android.hardware.display.Time;
 import android.os.Handler;
 import android.os.UserHandle;
 import android.provider.Settings;
@@ -37,7 +38,6 @@
 import androidx.test.runner.AndroidJUnit4;
 
 import com.android.internal.R;
-import com.android.internal.app.ColorDisplayController;
 import com.android.internal.util.test.FakeSettingsProvider;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
@@ -71,7 +71,6 @@
     private MockTwilightManager mTwilightManager;
 
     private ColorDisplayService mColorDisplayService;
-    private ColorDisplayController mColorDisplayController;
     private ColorDisplayService.BinderService mBinderService;
 
     @BeforeClass
@@ -97,7 +96,6 @@
         mTwilightManager = new MockTwilightManager();
         LocalServices.addService(TwilightManager.class, mTwilightManager);
 
-        mColorDisplayController = new ColorDisplayController(mContext, mUserId);
         mColorDisplayService = new ColorDisplayService(mContext);
         mBinderService = mColorDisplayService.new BinderService();
     }
@@ -988,9 +986,11 @@
      * @param endTimeOffset the offset relative to now to deactivate Night display (in minutes)
      */
     private void setAutoModeCustom(int startTimeOffset, int endTimeOffset) {
-        mColorDisplayController.setAutoMode(ColorDisplayManager.AUTO_MODE_CUSTOM_TIME);
-        mColorDisplayController.setCustomStartTime(getLocalTimeRelativeToNow(startTimeOffset));
-        mColorDisplayController.setCustomEndTime(getLocalTimeRelativeToNow(endTimeOffset));
+        mBinderService.setNightDisplayAutoMode(ColorDisplayManager.AUTO_MODE_CUSTOM_TIME);
+        mBinderService.setNightDisplayCustomStartTime(
+                new Time(getLocalTimeRelativeToNow(startTimeOffset)));
+        mBinderService
+                .setNightDisplayCustomEndTime(new Time(getLocalTimeRelativeToNow(endTimeOffset)));
     }
 
     /**
@@ -1000,7 +1000,7 @@
      * @param sunriseOffset the offset relative to now for sunrise (in minutes)
      */
     private void setAutoModeTwilight(int sunsetOffset, int sunriseOffset) {
-        mColorDisplayController.setAutoMode(ColorDisplayManager.AUTO_MODE_TWILIGHT);
+        mBinderService.setNightDisplayAutoMode(ColorDisplayManager.AUTO_MODE_TWILIGHT);
         mTwilightManager.setTwilightState(
                 getTwilightStateRelativeToNow(sunsetOffset, sunriseOffset));
     }
@@ -1041,22 +1041,18 @@
     }
 
     /**
-     * Configures color mode via ColorDisplayController.
-     *
-     * @param colorMode the color mode to set
+     * Configures color mode.
      */
     private void setColorMode(int colorMode) {
-        mColorDisplayController.setColorMode(colorMode);
+        mBinderService.setColorMode(colorMode);
     }
 
     /**
      * Returns whether the color mode is valid on the device the tests are running on.
-     *
-     * @param mode the mode to check
      */
     private boolean isColorModeValid(int mode) {
         final int[] availableColorModes = mContext.getResources().getIntArray(
-            R.array.config_availableColorModes);
+                R.array.config_availableColorModes);
         if (availableColorModes != null) {
             for (int availableMode : availableColorModes) {
                 if (mode == availableMode) {
@@ -1073,12 +1069,9 @@
     private void startService() {
         Secure.putIntForUser(mContext.getContentResolver(), Secure.USER_SETUP_COMPLETE, 1, mUserId);
 
-        InstrumentationRegistry.getInstrumentation().runOnMainSync(new Runnable() {
-            @Override
-            public void run() {
-                mColorDisplayService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
-                mColorDisplayService.onStartUser(mUserId);
-            }
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+            mColorDisplayService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);
+            mColorDisplayService.onStartUser(mUserId);
         });
     }
 
@@ -1100,7 +1093,7 @@
      */
     private void assertActiveColorMode(int mode) {
         assertWithMessage("Unexpected color mode setting")
-                .that(mColorDisplayController.getColorMode())
+                .that(mBinderService.getColorMode())
                 .isEqualTo(mode);
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
index 85909d5..72357ce 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
@@ -31,7 +31,6 @@
 import android.content.pm.ServiceInfo;
 import android.content.pm.SharedLibraryInfo;
 import android.content.pm.Signature;
-import android.content.pm.UsesPermissionInfo;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.platform.test.annotations.Presubmit;
@@ -466,7 +465,6 @@
         pkg.services.add(new PackageParser.Service(dummy, new ServiceInfo()));
         pkg.instrumentation.add(new PackageParser.Instrumentation(dummy, new InstrumentationInfo()));
         pkg.requestedPermissions.add("foo7");
-        pkg.usesPermissionInfos.add(new UsesPermissionInfo("foo7"));
         pkg.implicitPermissions.add("foo25");
 
         pkg.protectedBroadcasts = new ArrayList<>();
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
index 2ddc71f..48ab8d6 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexManagerTests.java
@@ -141,7 +141,8 @@
         assertIsUsedByOtherApps(mBarUser0, pui, true);
         assertTrue(pui.getDexUseInfoMap().isEmpty());
 
-        assertHasDclInfo(mBarUser0, mFooUser0, mBarUser0.getBaseAndSplitDexPaths());
+        // A package loading another package's APK is not DCL (it's not app data).
+        assertNoDclInfo(mBarUser0);
     }
 
     @Test
@@ -334,7 +335,9 @@
         notifyDexLoad(mFooUser0, newSplits, mUser0);
         PackageUseInfo pui = getPackageUseInfo(mBarUser0);
         assertIsUsedByOtherApps(newSplits, pui, true);
-        assertHasDclInfo(mBarUser0, mFooUser0, newSplits);
+
+        // Primary and split APKs are not recorded as DCL.
+        assertNoDclInfo(mBarUser0);
     }
 
     @Test
diff --git a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
index bfa0b74..63341b6 100644
--- a/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/power/PowerManagerServiceTest.java
@@ -150,7 +150,7 @@
     @SmallTest
     public void testGetDesiredScreenPolicy_WithVR() throws Exception {
         // Brighten up the screen
-        mService.setWakefulnessLocked(WAKEFULNESS_AWAKE, 0);
+        mService.setWakefulnessLocked(WAKEFULNESS_AWAKE, PowerManager.WAKE_REASON_UNKNOWN, 0);
         assertThat(mService.getDesiredScreenPolicyLocked()).isEqualTo(
                 DisplayPowerRequest.POLICY_BRIGHT);
 
@@ -160,12 +160,13 @@
                 DisplayPowerRequest.POLICY_VR);
 
         // Then take a nap
-        mService.setWakefulnessLocked(WAKEFULNESS_ASLEEP, 0);
+        mService.setWakefulnessLocked(WAKEFULNESS_ASLEEP, PowerManager.GO_TO_SLEEP_REASON_TIMEOUT,
+                0);
         assertThat(mService.getDesiredScreenPolicyLocked()).isEqualTo(
                 DisplayPowerRequest.POLICY_OFF);
 
         // Wake up to VR
-        mService.setWakefulnessLocked(WAKEFULNESS_AWAKE, 0);
+        mService.setWakefulnessLocked(WAKEFULNESS_AWAKE, PowerManager.WAKE_REASON_UNKNOWN, 0);
         assertThat(mService.getDesiredScreenPolicyLocked()).isEqualTo(
                 DisplayPowerRequest.POLICY_VR);
 
diff --git a/services/tests/servicestests/src/com/android/server/rollback/AppDataRollbackHelperTest.java b/services/tests/servicestests/src/com/android/server/rollback/AppDataRollbackHelperTest.java
index 43e3eb0..50dbaf5 100644
--- a/services/tests/servicestests/src/com/android/server/rollback/AppDataRollbackHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/rollback/AppDataRollbackHelperTest.java
@@ -18,15 +18,19 @@
 
 import static org.junit.Assert.*;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Matchers.anyInt;
+import static org.mockito.Matchers.anyString;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
 
 import android.content.pm.VersionedPackage;
 import android.content.rollback.PackageRollbackInfo;
 import android.content.rollback.PackageRollbackInfo.RestoreInfo;
 import android.util.IntArray;
+import android.util.SparseLongArray;
 
 import com.android.server.pm.Installer;
 
@@ -38,6 +42,7 @@
 
 import java.io.File;
 import java.util.ArrayList;
+import java.util.HashMap;
 
 @RunWith(JUnit4.class)
 public class AppDataRollbackHelperTest {
@@ -50,10 +55,14 @@
         // All users are unlocked so we should snapshot data for them.
         doReturn(true).when(helper).isUserCredentialLocked(eq(10));
         doReturn(true).when(helper).isUserCredentialLocked(eq(11));
-        IntArray pending = helper.snapshotAppData("com.foo.bar", new int[]{10, 11});
-        assertEquals(2, pending.size());
-        assertEquals(10, pending.get(0));
-        assertEquals(11, pending.get(1));
+        AppDataRollbackHelper.SnapshotAppDataResult result = helper.snapshotAppData("com.foo.bar",
+                new int[]{10, 11});
+
+        assertEquals(2, result.pendingBackups.size());
+        assertEquals(10, result.pendingBackups.get(0));
+        assertEquals(11, result.pendingBackups.get(1));
+
+        assertEquals(0, result.ceSnapshotInodes.size());
 
         InOrder inOrder = Mockito.inOrder(installer);
         inOrder.verify(installer).snapshotAppData(
@@ -65,10 +74,14 @@
         // One of the users is unlocked but the other isn't
         doReturn(false).when(helper).isUserCredentialLocked(eq(10));
         doReturn(true).when(helper).isUserCredentialLocked(eq(11));
+        when(installer.snapshotAppData(anyString(), anyInt(), anyInt())).thenReturn(239L);
 
-        pending = helper.snapshotAppData("com.foo.bar", new int[]{10, 11});
-        assertEquals(1, pending.size());
-        assertEquals(11, pending.get(0));
+        result = helper.snapshotAppData("com.foo.bar", new int[]{10, 11});
+        assertEquals(1, result.pendingBackups.size());
+        assertEquals(11, result.pendingBackups.get(0));
+
+        assertEquals(1, result.ceSnapshotInodes.size());
+        assertEquals(239L, result.ceSnapshotInodes.get(10));
 
         inOrder = Mockito.inOrder(installer);
         inOrder.verify(installer).snapshotAppData(
@@ -83,7 +96,7 @@
         RollbackData data = new RollbackData(1, new File("/does/not/exist"), -1, true);
         data.packages.add(new PackageRollbackInfo(
                 new VersionedPackage(packageName, 1), new VersionedPackage(packageName, 1),
-                new IntArray(), new ArrayList<>(), false));
+                new IntArray(), new ArrayList<>(), false, new IntArray(), new SparseLongArray()));
         data.inProgress = true;
 
         return data;
@@ -173,4 +186,53 @@
         ArrayList<RestoreInfo> pendingRestores = rd.packages.get(0).getPendingRestores();
         assertEquals(0, pendingRestores.size());
     }
+
+    @Test
+    public void destroyAppData() throws Exception {
+        Installer installer = mock(Installer.class);
+        AppDataRollbackHelper helper = new AppDataRollbackHelper(installer);
+        SparseLongArray ceSnapshotInodes = new SparseLongArray();
+        ceSnapshotInodes.put(11, 239L);
+
+        helper.destroyAppDataSnapshot("com.foo.bar", 10, 0L);
+        helper.destroyAppDataSnapshot("com.foo.bar", 11, 239L);
+
+        InOrder inOrder = Mockito.inOrder(installer);
+        inOrder.verify(installer).destroyAppDataSnapshot(
+                eq("com.foo.bar"), eq(10), eq(0L),
+                eq(Installer.FLAG_STORAGE_DE));
+        inOrder.verify(installer).destroyAppDataSnapshot(
+                eq("com.foo.bar"), eq(11), eq(239L),
+                eq(Installer.FLAG_STORAGE_DE | Installer.FLAG_STORAGE_CE));
+        inOrder.verifyNoMoreInteractions();
+    }
+
+    @Test
+    public void commitPendingBackupAndRestoreForUser_updatesRollbackData() throws Exception {
+        Installer installer = mock(Installer.class);
+        AppDataRollbackHelper helper = new AppDataRollbackHelper(installer);
+
+        ArrayList<RollbackData> changedRollbackData = new ArrayList<>();
+        changedRollbackData.add(createInProgressRollbackData("com.foo.bar"));
+
+        when(installer.snapshotAppData(anyString(), anyInt(), anyInt())).thenReturn(239L);
+
+        ArrayList<String> pendingBackups = new ArrayList<>();
+        pendingBackups.add("com.foo.bar");
+
+        helper.commitPendingBackupAndRestoreForUser(11, pendingBackups,
+                new HashMap<>() /* pendingRestores */, changedRollbackData);
+
+        assertEquals(1, changedRollbackData.size());
+        assertEquals(1, changedRollbackData.get(0).packages.size());
+        PackageRollbackInfo info = changedRollbackData.get(0).packages.get(0);
+
+        assertEquals(1, info.getCeSnapshotInodes().size());
+        assertEquals(239L, info.getCeSnapshotInodes().get(11));
+
+        InOrder inOrder = Mockito.inOrder(installer);
+        inOrder.verify(installer).snapshotAppData("com.foo.bar", 11 /* userId */,
+                Installer.FLAG_STORAGE_CE);
+        inOrder.verifyNoMoreInteractions();
+    }
 }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BubbleExtractorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BubbleExtractorTest.java
new file mode 100644
index 0000000..3e01fb5
--- /dev/null
+++ b/services/tests/uiservicestests/src/com/android/server/notification/BubbleExtractorTest.java
@@ -0,0 +1,154 @@
+/*
+ * 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.notification;
+
+import static android.app.NotificationManager.IMPORTANCE_HIGH;
+import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
+
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import static org.mockito.Mockito.when;
+
+import android.app.ActivityManager;
+import android.app.Notification;
+import android.app.Notification.Builder;
+import android.app.NotificationChannel;
+import android.os.UserHandle;
+import android.service.notification.StatusBarNotification;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.server.UiServiceTestCase;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class BubbleExtractorTest extends UiServiceTestCase {
+
+    @Mock RankingConfig mConfig;
+
+    private String mPkg = "com.android.server.notification";
+    private int mId = 1001;
+    private String mTag = null;
+    private int mUid = 1000;
+    private int mPid = 2000;
+    private UserHandle mUser = UserHandle.of(ActivityManager.getCurrentUser());
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+    }
+
+    private NotificationRecord getNotificationRecord(boolean allow, int importanceHigh) {
+        NotificationChannel channel = new NotificationChannel("a", "a", importanceHigh);
+        channel.setAllowBubbles(allow);
+        when(mConfig.getNotificationChannel(mPkg, mUid, "a", false)).thenReturn(channel);
+
+        final Builder builder = new Builder(getContext())
+                .setContentTitle("foo")
+                .setSmallIcon(android.R.drawable.sym_def_app_icon)
+                .setPriority(Notification.PRIORITY_HIGH)
+                .setDefaults(Notification.DEFAULT_SOUND);
+
+        Notification n = builder.build();
+        StatusBarNotification sbn = new StatusBarNotification(mPkg, mPkg, mId, mTag, mUid,
+                mPid, n, mUser, null, System.currentTimeMillis());
+        NotificationRecord r = new NotificationRecord(getContext(), sbn, channel);
+        return r;
+    }
+
+    //
+    // Tests
+    //
+
+    @Test
+    public void testAppYesChannelNo() {
+        BubbleExtractor extractor = new BubbleExtractor();
+        extractor.setConfig(mConfig);
+
+        when(mConfig.bubblesEnabled(mUser)).thenReturn(true);
+        when(mConfig.areBubblesAllowed(mPkg, mUid)).thenReturn(true);
+        NotificationRecord r = getNotificationRecord(false, IMPORTANCE_UNSPECIFIED);
+
+        extractor.process(r);
+
+        assertFalse(r.canBubble());
+    }
+
+    @Test
+    public void testAppNoChannelYes() throws Exception {
+        BubbleExtractor extractor = new BubbleExtractor();
+        extractor.setConfig(mConfig);
+
+        when(mConfig.bubblesEnabled(mUser)).thenReturn(true);
+        when(mConfig.areBubblesAllowed(mPkg, mUid)).thenReturn(false);
+        NotificationRecord r = getNotificationRecord(true, IMPORTANCE_HIGH);
+
+        extractor.process(r);
+
+        assertFalse(r.canBubble());
+    }
+
+    @Test
+    public void testAppYesChannelYes() {
+        BubbleExtractor extractor = new BubbleExtractor();
+        extractor.setConfig(mConfig);
+
+        when(mConfig.bubblesEnabled(mUser)).thenReturn(true);
+        when(mConfig.areBubblesAllowed(mPkg, mUid)).thenReturn(true);
+        NotificationRecord r = getNotificationRecord(true, IMPORTANCE_UNSPECIFIED);
+
+        extractor.process(r);
+
+        assertTrue(r.canBubble());
+    }
+
+    @Test
+    public void testAppNoChannelNo() {
+        BubbleExtractor extractor = new BubbleExtractor();
+        extractor.setConfig(mConfig);
+
+        when(mConfig.bubblesEnabled(mUser)).thenReturn(true);
+        when(mConfig.areBubblesAllowed(mPkg, mUid)).thenReturn(false);
+        NotificationRecord r = getNotificationRecord(false, IMPORTANCE_UNSPECIFIED);
+
+        extractor.process(r);
+
+        assertFalse(r.canBubble());
+    }
+
+    @Test
+    public void testAppYesChannelYesUserNo() {
+        BubbleExtractor extractor = new BubbleExtractor();
+        extractor.setConfig(mConfig);
+
+        when(mConfig.bubblesEnabled(mUser)).thenReturn(false);
+        when(mConfig.areBubblesAllowed(mPkg, mUid)).thenReturn(true);
+        NotificationRecord r = getNotificationRecord(true, IMPORTANCE_HIGH);
+
+        extractor.process(r);
+
+        assertFalse(r.canBubble());
+    }
+}
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java
index daca9cb..2162f28 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationListenerServiceTest.java
@@ -54,7 +54,7 @@
 @RunWith(AndroidJUnit4.class)
 public class NotificationListenerServiceTest extends UiServiceTestCase {
 
-    private String[] mKeys = new String[] { "key", "key1", "key2", "key3"};
+    private String[] mKeys = new String[] { "key", "key1", "key2", "key3", "key4"};
 
     @Test
     public void testGetActiveNotifications_notNull() throws Exception {
@@ -70,7 +70,7 @@
     }
 
     @Test
-    public void testRanking() throws Exception {
+    public void testRanking() {
         TestListenerService service = new TestListenerService();
         service.applyUpdateLocked(generateUpdate());
         for (int i = 0; i < mKeys.length; i++) {
@@ -92,6 +92,7 @@
             assertEquals(lastAudiblyAlerted(i), ranking.getLastAudiblyAlertedMillis());
             assertActionsEqual(getSmartActions(key, i), ranking.getSmartActions());
             assertEquals(getSmartReplies(key, i), ranking.getSmartReplies());
+            assertEquals(canBubble(i), ranking.canBubble());
         }
     }
 
@@ -112,6 +113,7 @@
         Bundle smartReplies = new Bundle();
         Bundle lastAudiblyAlerted = new Bundle();
         Bundle noisy = new Bundle();
+        boolean[] canBubble = new boolean[mKeys.length];
 
         for (int i = 0; i < mKeys.length; i++) {
             String key = mKeys[i];
@@ -133,12 +135,13 @@
             smartReplies.putCharSequenceArrayList(key, getSmartReplies(key, i));
             lastAudiblyAlerted.putLong(key, lastAudiblyAlerted(i));
             noisy.putBoolean(key, getNoisy(i));
+            canBubble[i] = canBubble(i);
         }
         NotificationRankingUpdate update = new NotificationRankingUpdate(mKeys,
                 interceptedKeys.toArray(new String[0]), visibilityOverrides,
                 suppressedVisualEffects, importance, explanation, overrideGroupKeys,
                 channels, overridePeople, snoozeCriteria, showBadge, userSentiment, mHidden,
-                smartActions, smartReplies, lastAudiblyAlerted, noisy);
+                smartActions, smartReplies, lastAudiblyAlerted, noisy, canBubble);
         return update;
     }
 
@@ -235,6 +238,10 @@
         return choices;
     }
 
+    private boolean canBubble(int index) {
+        return index % 4 == 0;
+    }
+
     private void assertActionsEqual(
             List<Notification.Action> expecteds, List<Notification.Action> actuals) {
         assertEquals(expecteds.size(), actuals.size());
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 ed46617..cc62138 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -275,11 +275,6 @@
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
 
-        // most tests assume badging is enabled
-        Secure.putIntForUser(getContext().getContentResolver(),
-                Secure.NOTIFICATION_BADGING, 1,
-                UserHandle.getUserHandleForUid(mUid).getIdentifier());
-
         LocalServices.removeServiceForTest(UriGrantsManagerInternal.class);
         LocalServices.addService(UriGrantsManagerInternal.class, mUgmInternal);
         LocalServices.removeServiceForTest(WindowManagerInternal.class);
@@ -434,6 +429,11 @@
             r.setShowBadge(!r.canShowBadge());
             return null;
         });
+        answers.put("bubbles", invocationOnMock -> {
+            NotificationRecord r = (NotificationRecord) invocationOnMock.getArguments()[0];
+            r.setAllowBubble(!r.canBubble());
+            return null;
+        });
         answers.put("package visibility", invocationOnMock -> {
             ((NotificationRecord) invocationOnMock.getArguments()[0]).setPackageVisibilityOverride(
                     Notification.VISIBILITY_SECRET);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index d46b41a..05bb307 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -149,6 +149,8 @@
         contentResolver.setFallbackToExisting(false);
         Secure.putIntForUser(contentResolver,
                 Secure.NOTIFICATION_BADGING, 1, UserHandle.getUserId(UID_N_MR1));
+        Secure.putIntForUser(contentResolver,
+                Secure.NOTIFICATION_BUBBLES, 1, UserHandle.getUserId(UID_N_MR1));
 
         ContentProvider testContentProvider = mock(ContentProvider.class);
         when(testContentProvider.getIContentProvider()).thenReturn(mTestIContentProvider);
@@ -1901,6 +1903,46 @@
     }
 
     @Test
+    public void testBubblesOverrideTrue() {
+        Secure.putIntForUser(getContext().getContentResolver(),
+                Secure.NOTIFICATION_BUBBLES, 1,
+                USER.getIdentifier());
+        mHelper.updateBubblesEnabled(); // would be called by settings observer
+        assertTrue(mHelper.bubblesEnabled(USER));
+    }
+
+    @Test
+    public void testBubblesOverrideFalse() {
+        Secure.putIntForUser(getContext().getContentResolver(),
+                Secure.NOTIFICATION_BUBBLES, 0,
+                USER.getIdentifier());
+        mHelper.updateBubblesEnabled(); // would be called by settings observer
+        assertFalse(mHelper.bubblesEnabled(USER));
+    }
+
+    @Test
+    public void testBubblesForUserAll() {
+        try {
+            mHelper.bubblesEnabled(UserHandle.ALL);
+        } catch (Exception e) {
+            fail("just don't throw");
+        }
+    }
+
+    @Test
+    public void testBubblesOverrideUserIsolation() {
+        Secure.putIntForUser(getContext().getContentResolver(),
+                Secure.NOTIFICATION_BUBBLES, 0,
+                USER.getIdentifier());
+        Secure.putIntForUser(getContext().getContentResolver(),
+                Secure.NOTIFICATION_BUBBLES, 1,
+                USER2.getIdentifier());
+        mHelper.updateBubblesEnabled(); // would be called by settings observer
+        assertFalse(mHelper.bubblesEnabled(USER));
+        assertTrue(mHelper.bubblesEnabled(USER2));
+    }
+
+    @Test
     public void testOnLocaleChanged_updatesDefaultChannels() throws Exception {
         String newLabel = "bananas!";
         final NotificationChannel defaultChannel = mHelper.getNotificationChannel(PKG_N_MR1,
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java
index c79e1db0..b322887 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/RankingHelperTest.java
@@ -125,11 +125,8 @@
                 InstrumentationRegistry.getContext().getContentResolver());
         when(mContext.getPackageManager()).thenReturn(mPm);
         when(mContext.getApplicationInfo()).thenReturn(legacy);
-        // most tests assume badging is enabled
         TestableContentResolver contentResolver = getContext().getContentResolver();
         contentResolver.setFallbackToExisting(false);
-        Secure.putIntForUser(contentResolver,
-                Secure.NOTIFICATION_BADGING, 1, UserHandle.getUserId(UID));
 
         ContentProvider testContentProvider = mock(ContentProvider.class);
         when(testContentProvider.getIContentProvider()).thenReturn(mTestIContentProvider);
diff --git a/services/tests/wmtests/AndroidManifest.xml b/services/tests/wmtests/AndroidManifest.xml
index 3f3b996..bfda2ea 100644
--- a/services/tests/wmtests/AndroidManifest.xml
+++ b/services/tests/wmtests/AndroidManifest.xml
@@ -37,8 +37,10 @@
     <uses-permission android:name="android.permission.WAKE_LOCK" />
     <uses-permission android:name="android.permission.REORDER_TASKS" />
 
+    <!-- TODO: Remove largeHeap hack when memory leak is fixed (b/123984854) -->
     <application android:debuggable="true"
-                 android:testOnly="true">
+                 android:testOnly="true"
+                 android:largeHeap="true">
         <uses-library android:name="android.test.mock" android:required="true" />
 
         <activity android:name="com.android.server.wm.TaskStackChangedListenerTest$ActivityA" />
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
index ee22861..2de4ae0 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityMetricsLaunchObserverTests.java
@@ -57,7 +57,6 @@
  */
 @SmallTest
 @Presubmit
-@FlakyTest(detail="promote once confirmed non-flaky")
 public class ActivityMetricsLaunchObserverTests extends ActivityTestsBase {
     private ActivityMetricsLogger mActivityMetricsLogger;
     private ActivityMetricsLaunchObserver mLaunchObserver;
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 192915f..4073ff1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -24,6 +24,7 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
 import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_BOTTOM;
@@ -34,6 +35,9 @@
 import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
 import static com.android.server.wm.ActivityStack.ActivityState.STOPPED;
 import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_MOVING;
+import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_INVISIBLE;
+import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE;
+import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
@@ -381,6 +385,21 @@
     }
 
     @Test
+    public void testShouldResume_stackVisibility() {
+        mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing");
+        spyOn(mStack);
+
+        doReturn(STACK_VISIBILITY_VISIBLE).when(mStack).getVisibility(null);
+        assertEquals(true, mActivity.shouldResumeActivity(null /* activeActivity */));
+
+        doReturn(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT).when(mStack).getVisibility(null);
+        assertEquals(false, mActivity.shouldResumeActivity(null /* activeActivity */));
+
+        doReturn(STACK_VISIBILITY_INVISIBLE).when(mStack).getVisibility(null);
+        assertEquals(false, mActivity.shouldResumeActivity(null /* activeActivity */));
+    }
+
+    @Test
     public void testPushConfigurationWhenLaunchTaskBehind() throws Exception {
         mActivity.setState(ActivityStack.ActivityState.STOPPED, "Testing");
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
index 986943a..822700f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
@@ -37,6 +37,9 @@
 import static com.android.server.wm.ActivityStack.ActivityState.STOPPED;
 import static com.android.server.wm.ActivityStack.ActivityState.STOPPING;
 import static com.android.server.wm.ActivityStack.REMOVE_TASK_MODE_DESTROYING;
+import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_INVISIBLE;
+import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE;
+import static com.android.server.wm.ActivityStack.STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
 import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_FREE_RESIZE;
 import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_WINDOWING_MODE_RESIZE;
 
@@ -321,12 +324,23 @@
         assertFalse(homeStack.shouldBeVisible(null /* starting */));
         assertTrue(splitScreenPrimary.shouldBeVisible(null /* starting */));
         assertTrue(splitScreenSecondary.shouldBeVisible(null /* starting */));
+        assertEquals(STACK_VISIBILITY_INVISIBLE, homeStack.getVisibility(null /* starting */));
+        assertEquals(STACK_VISIBILITY_VISIBLE,
+                splitScreenPrimary.getVisibility(null /* starting */));
+        assertEquals(STACK_VISIBILITY_VISIBLE,
+                splitScreenSecondary.getVisibility(null /* starting */));
 
         // Home stack should be visible if one of the halves of split-screen is translucent.
         splitScreenPrimary.setIsTranslucent(true);
         assertTrue(homeStack.shouldBeVisible(null /* starting */));
         assertTrue(splitScreenPrimary.shouldBeVisible(null /* starting */));
         assertTrue(splitScreenSecondary.shouldBeVisible(null /* starting */));
+        assertEquals(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
+                homeStack.getVisibility(null /* starting */));
+        assertEquals(STACK_VISIBILITY_VISIBLE,
+                splitScreenPrimary.getVisibility(null /* starting */));
+        assertEquals(STACK_VISIBILITY_VISIBLE,
+                splitScreenSecondary.getVisibility(null /* starting */));
 
         final TestActivityStack splitScreenSecondary2 =
                 createStackForShouldBeVisibleTest(mDefaultDisplay,
@@ -336,12 +350,20 @@
         splitScreenSecondary2.setIsTranslucent(false);
         assertFalse(splitScreenSecondary.shouldBeVisible(null /* starting */));
         assertTrue(splitScreenSecondary2.shouldBeVisible(null /* starting */));
+        assertEquals(STACK_VISIBILITY_INVISIBLE,
+                splitScreenSecondary.getVisibility(null /* starting */));
+        assertEquals(STACK_VISIBILITY_VISIBLE,
+                splitScreenSecondary2.getVisibility(null /* starting */));
 
         // First split-screen secondary should be visible behind another translucent split-screen
         // secondary.
         splitScreenSecondary2.setIsTranslucent(true);
         assertTrue(splitScreenSecondary.shouldBeVisible(null /* starting */));
         assertTrue(splitScreenSecondary2.shouldBeVisible(null /* starting */));
+        assertEquals(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
+                splitScreenSecondary.getVisibility(null /* starting */));
+        assertEquals(STACK_VISIBILITY_VISIBLE,
+                splitScreenSecondary2.getVisibility(null /* starting */));
 
         final TestActivityStack assistantStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
                 WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_ASSISTANT, true /* onTop */);
@@ -352,6 +374,14 @@
         assertFalse(splitScreenPrimary.shouldBeVisible(null /* starting */));
         assertFalse(splitScreenSecondary.shouldBeVisible(null /* starting */));
         assertFalse(splitScreenSecondary2.shouldBeVisible(null /* starting */));
+        assertEquals(STACK_VISIBILITY_VISIBLE,
+                assistantStack.getVisibility(null /* starting */));
+        assertEquals(STACK_VISIBILITY_INVISIBLE,
+                splitScreenPrimary.getVisibility(null /* starting */));
+        assertEquals(STACK_VISIBILITY_INVISIBLE,
+                splitScreenSecondary.getVisibility(null /* starting */));
+        assertEquals(STACK_VISIBILITY_INVISIBLE,
+                splitScreenSecondary2.getVisibility(null /* starting */));
 
         // Split-screen stacks should be visible behind a translucent fullscreen stack.
         assistantStack.setIsTranslucent(true);
@@ -359,6 +389,14 @@
         assertTrue(splitScreenPrimary.shouldBeVisible(null /* starting */));
         assertTrue(splitScreenSecondary.shouldBeVisible(null /* starting */));
         assertTrue(splitScreenSecondary2.shouldBeVisible(null /* starting */));
+        assertEquals(STACK_VISIBILITY_VISIBLE,
+                assistantStack.getVisibility(null /* starting */));
+        assertEquals(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
+                splitScreenPrimary.getVisibility(null /* starting */));
+        assertEquals(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
+                splitScreenSecondary.getVisibility(null /* starting */));
+        assertEquals(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
+                splitScreenSecondary2.getVisibility(null /* starting */));
 
         // Assistant stack shouldn't be visible behind translucent split-screen stack
         assistantStack.setIsTranslucent(false);
@@ -369,6 +407,113 @@
         assertFalse(assistantStack.shouldBeVisible(null /* starting */));
         assertTrue(splitScreenPrimary.shouldBeVisible(null /* starting */));
         assertTrue(splitScreenSecondary2.shouldBeVisible(null /* starting */));
+        assertEquals(STACK_VISIBILITY_INVISIBLE,
+                assistantStack.getVisibility(null /* starting */));
+        assertEquals(STACK_VISIBILITY_VISIBLE,
+                splitScreenPrimary.getVisibility(null /* starting */));
+        assertEquals(STACK_VISIBILITY_INVISIBLE,
+                splitScreenSecondary.getVisibility(null /* starting */));
+        assertEquals(STACK_VISIBILITY_VISIBLE,
+                splitScreenSecondary2.getVisibility(null /* starting */));
+    }
+
+    @Test
+    public void testGetVisibility_FullscreenBehindTranslucent() {
+        final TestActivityStack bottomStack =
+                createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
+                        false /* translucent */);
+        final TestActivityStack translucentStack =
+                createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
+                        true /* translucent */);
+
+        assertEquals(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
+                bottomStack.getVisibility(null /* starting */));
+        assertEquals(STACK_VISIBILITY_VISIBLE,
+                translucentStack.getVisibility(null /* starting */));
+    }
+
+    @Test
+    public void testGetVisibility_FullscreenBehindTranslucentAndOpaque() {
+        final TestActivityStack bottomStack =
+                createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
+                        false /* translucent */);
+        final TestActivityStack translucentStack =
+                createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
+                        true /* translucent */);
+        final TestActivityStack opaqueStack =
+                createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
+                        false /* translucent */);
+
+        assertEquals(STACK_VISIBILITY_INVISIBLE, bottomStack.getVisibility(null /* starting */));
+        assertEquals(STACK_VISIBILITY_INVISIBLE,
+                translucentStack.getVisibility(null /* starting */));
+        assertEquals(STACK_VISIBILITY_VISIBLE, opaqueStack.getVisibility(null /* starting */));
+    }
+
+    @Test
+    public void testGetVisibility_FullscreenBehindOpaqueAndTranslucent() {
+        final TestActivityStack bottomStack =
+                createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
+                        false /* translucent */);
+        final TestActivityStack opaqueStack =
+                createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
+                        false /* translucent */);
+        final TestActivityStack translucentStack =
+                createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
+                        true /* translucent */);
+
+        assertEquals(STACK_VISIBILITY_INVISIBLE, bottomStack.getVisibility(null /* starting */));
+        assertEquals(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
+                opaqueStack.getVisibility(null /* starting */));
+        assertEquals(STACK_VISIBILITY_VISIBLE,
+                translucentStack.getVisibility(null /* starting */));
+    }
+
+    @Test
+    public void testGetVisibility_FullscreenTranslucentBehindTranslucent() {
+        final TestActivityStack bottomTranslucentStack =
+                createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
+                        true /* translucent */);
+        final TestActivityStack translucentStack =
+                createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
+                        true /* translucent */);
+
+        assertEquals(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
+                bottomTranslucentStack.getVisibility(null /* starting */));
+        assertEquals(STACK_VISIBILITY_VISIBLE,
+                translucentStack.getVisibility(null /* starting */));
+    }
+
+    @Test
+    public void testGetVisibility_FullscreenTranslucentBehindOpaque() {
+        final TestActivityStack bottomTranslucentStack =
+                createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
+                        true /* translucent */);
+        final TestActivityStack opaqueStack =
+                createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
+                        false /* translucent */);
+
+        assertEquals(STACK_VISIBILITY_INVISIBLE,
+                bottomTranslucentStack.getVisibility(null /* starting */));
+        assertEquals(STACK_VISIBILITY_VISIBLE, opaqueStack.getVisibility(null /* starting */));
+    }
+
+    @Test
+    public void testGetVisibility_FullscreenBehindTranslucentAndPip() {
+        final TestActivityStack bottomStack =
+                createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
+                        false /* translucent */);
+        final TestActivityStack translucentStack =
+                createStandardStackForVisibilityTest(WINDOWING_MODE_FULLSCREEN,
+                        true /* translucent */);
+        final ActivityStack pinnedStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+                WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+
+        assertEquals(STACK_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT,
+                bottomStack.getVisibility(null /* starting */));
+        assertEquals(STACK_VISIBILITY_VISIBLE,
+                translucentStack.getVisibility(null /* starting */));
+        assertEquals(STACK_VISIBILITY_VISIBLE, pinnedStack.getVisibility(null /* starting */));
     }
 
     @Test
@@ -628,6 +773,14 @@
         assertFalse(assistantStack.shouldBeVisible(null /* starting */));
     }
 
+    private TestActivityStack createStandardStackForVisibilityTest(int windowingMode,
+            boolean translucent) {
+        final TestActivityStack stack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+                windowingMode, ACTIVITY_TYPE_STANDARD, true /* onTop */);
+        stack.setIsTranslucent(translucent);
+        return stack;
+    }
+
     @SuppressWarnings("TypeParameterUnusedInFormals")
     private <T extends ActivityStack> T createStackForShouldBeVisibleTest(
             ActivityDisplay display, int windowingMode, int activityType, boolean onTop) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
index 3bf884f..a7520dc 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
@@ -16,24 +16,29 @@
 
 package com.android.server.wm;
 
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 import static android.view.WindowManager.TRANSIT_TASK_CHANGE_WINDOWING_MODE;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
 
+import android.graphics.Rect;
 import android.os.IBinder;
+import android.view.Display;
 import android.view.IRemoteAnimationFinishedCallback;
 import android.view.IRemoteAnimationRunner;
 import android.view.RemoteAnimationAdapter;
 import android.view.RemoteAnimationDefinition;
 import android.view.RemoteAnimationTarget;
 
-import androidx.test.filters.FlakyTest;
 import androidx.test.filters.SmallTest;
 
-import org.junit.Before;
 import org.junit.Test;
 
 /**
@@ -42,7 +47,6 @@
  * Build/Install/Run:
  *  atest WmTests:AppChangeTransitionTests
  */
-@FlakyTest(detail = "Promote when shown to be stable.")
 @SmallTest
 public class AppChangeTransitionTests extends WindowTestsBase {
 
@@ -50,14 +54,20 @@
     private Task mTask;
     private WindowTestUtils.TestAppWindowToken mToken;
 
-    @Before
-    public void setUp() throws Exception {
-        mStack = createTaskStackOnDisplay(mDisplayContent);
+    public void setUpOnDisplay(DisplayContent dc) {
+        mStack = createTaskStackOnDisplay(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, dc);
         mTask = createTaskInStack(mStack, 0 /* userId */);
-        mToken = WindowTestUtils.createTestAppWindowToken(mDisplayContent);
+        mToken = WindowTestUtils.createTestAppWindowToken(dc);
         mToken.mSkipOnParentChanged = false;
 
         mTask.addChild(mToken, 0);
+
+        // Set a remote animator with snapshot disabled. Snapshots don't work in wmtests.
+        RemoteAnimationDefinition definition = new RemoteAnimationDefinition();
+        RemoteAnimationAdapter adapter =
+                new RemoteAnimationAdapter(new TestRemoteAnimationRunner(), 10, 1, false);
+        definition.addRemoteAnimation(TRANSIT_TASK_CHANGE_WINDOWING_MODE, adapter);
+        dc.registerRemoteAnimations(definition);
     }
 
     class TestRemoteAnimationRunner implements IRemoteAnimationRunner {
@@ -86,14 +96,58 @@
 
     @Test
     public void testModeChangeRemoteAnimatorNoSnapshot() {
-        RemoteAnimationDefinition definition = new RemoteAnimationDefinition();
-        RemoteAnimationAdapter adapter =
-                new RemoteAnimationAdapter(new TestRemoteAnimationRunner(), 10, 1, false);
-        definition.addRemoteAnimation(TRANSIT_TASK_CHANGE_WINDOWING_MODE, adapter);
-        mDisplayContent.registerRemoteAnimations(definition);
+        // setup currently defaults to no snapshot.
+        setUpOnDisplay(mDisplayContent);
 
         mTask.setWindowingMode(WINDOWING_MODE_FREEFORM);
         assertEquals(1, mDisplayContent.mChangingApps.size());
+
+        // Verify we are in a change transition, but without a snapshot.
+        // Though, the test will actually have crashed by now if a snapshot is attempted.
+        assertNull(mToken.getThumbnail());
+        assertTrue(mToken.isInChangeTransition());
+
+        waitUntilHandlersIdle();
+        mToken.removeImmediately();
+    }
+
+    @Test
+    public void testCancelPendingChangeOnRemove() {
+        // setup currently defaults to no snapshot.
+        setUpOnDisplay(mDisplayContent);
+
+        mTask.setWindowingMode(WINDOWING_MODE_FREEFORM);
+        assertEquals(1, mDisplayContent.mChangingApps.size());
+        assertTrue(mToken.isInChangeTransition());
+
+        // Removing the app-token from the display should clean-up the
+        // the change leash.
+        mDisplayContent.removeAppToken(mToken.token);
+        assertEquals(0, mDisplayContent.mChangingApps.size());
+        assertFalse(mToken.isInChangeTransition());
+
+        waitUntilHandlersIdle();
+        mToken.removeImmediately();
+    }
+
+    @Test
+    public void testNoChangeWhenMoveDisplay() {
+        mDisplayContent.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
+        final DisplayContent dc1 = createNewDisplay(Display.STATE_ON);
+        dc1.setWindowingMode(WINDOWING_MODE_FREEFORM);
+        setUpOnDisplay(dc1);
+
+        assertEquals(WINDOWING_MODE_FREEFORM, mTask.getWindowingMode());
+
+        // Reparenting to a display with different windowing mode may trigger
+        // a change transition internally, but it should be cleaned-up once
+        // the display change is complete.
+        mStack.reparent(mDisplayContent.getDisplayId(), new Rect(), true);
+
+        assertEquals(WINDOWING_MODE_FULLSCREEN, mTask.getWindowingMode());
+
+        // Make sure we're not waiting for a change animation (no leash)
+        assertFalse(mToken.isInChangeTransition());
         assertNull(mToken.getThumbnail());
 
         waitUntilHandlersIdle();
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java
index ea5ab7b..dd5f32d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java
@@ -87,8 +87,8 @@
         verify(mSpec).startAnimation(any(), any(), callbackCaptor.capture());
 
         callbackCaptor.getValue().onAnimationFinished(mSpec);
-        verify(mTransaction).reparent(eq(leash), eq(null));
-        verify(mTransaction).reparent(eq(animationBoundsLayer), eq(null));
+        verify(mTransaction).remove(eq(leash));
+        verify(mTransaction).remove(eq(animationBoundsLayer));
         assertThat(mToken.mNeedsAnimationBoundsLayer).isFalse();
     }
 
@@ -100,8 +100,8 @@
         final SurfaceControl animationBoundsLayer = mToken.mAnimationBoundsLayer;
 
         mToken.mSurfaceAnimator.cancelAnimation();
-        verify(mTransaction).reparent(eq(leash), eq(null));
-        verify(mTransaction).reparent(eq(animationBoundsLayer), eq(null));
+        verify(mTransaction).remove(eq(leash));
+        verify(mTransaction).remove(eq(animationBoundsLayer));
         assertThat(mToken.mNeedsAnimationBoundsLayer).isFalse();
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java b/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
index f99cd4b..5b32fe6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
@@ -166,7 +166,7 @@
 
         mDimmer.updateDims(mTransaction, new Rect());
         verify(mTransaction).show(getDimLayer());
-        verify(dimLayer, never()).destroy();
+        verify(dimLayer, never()).remove();
     }
 
     @Test
@@ -212,7 +212,7 @@
         mDimmer.updateDims(mTransaction, new Rect());
         verify(mSurfaceAnimatorStarter).startAnimation(any(SurfaceAnimator.class), any(
                 SurfaceControl.Transaction.class), any(AnimationAdapter.class), anyBoolean());
-        verify(mHost.getPendingTransaction()).reparent(dimLayer, null);
+        verify(mHost.getPendingTransaction()).remove(dimLayer);
     }
 
     @Test
@@ -228,7 +228,7 @@
 
         mDimmer.updateDims(mTransaction, new Rect());
         verify(mTransaction).show(dimLayer);
-        verify(dimLayer, never()).destroy();
+        verify(dimLayer, never()).remove();
     }
 
     @Test
@@ -269,7 +269,7 @@
         mDimmer.updateDims(mTransaction, new Rect());
         verify(mSurfaceAnimatorStarter, never()).startAnimation(any(SurfaceAnimator.class), any(
                 SurfaceControl.Transaction.class), any(AnimationAdapter.class), anyBoolean());
-        verify(mTransaction).reparent(dimLayer, null);
+        verify(mTransaction).remove(dimLayer);
     }
 
     private SurfaceControl getDimLayer() {
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index f399463..a62bc71 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -51,8 +51,10 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.eq;
 
 import android.annotation.SuppressLint;
+import android.app.WindowConfiguration;
 import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.os.SystemClock;
@@ -63,6 +65,8 @@
 import android.view.Gravity;
 import android.view.MotionEvent;
 import android.view.Surface;
+import android.view.ViewRootImpl;
+import android.view.test.InsetsModeSession;
 
 import androidx.test.filters.FlakyTest;
 import androidx.test.filters.SmallTest;
@@ -585,17 +589,15 @@
 
     @Test
     public void testOnDescendantOrientationRequestChanged() {
-        final DisplayInfo info = new DisplayInfo();
-        info.logicalWidth = 1080;
-        info.logicalHeight = 1920;
-        info.logicalDensityDpi = 240;
-        final DisplayContent dc = createNewDisplay(info);
-        dc.configureDisplayPolicy();
+        final DisplayContent dc = createNewDisplay();
         mWm.mAtmService.mRootActivityContainer = mock(RootActivityContainer.class);
+        final int newOrientation = dc.getLastOrientation() == SCREEN_ORIENTATION_LANDSCAPE
+                ? SCREEN_ORIENTATION_PORTRAIT
+                : SCREEN_ORIENTATION_LANDSCAPE;
 
         final WindowState window = createWindow(null /* parent */, TYPE_BASE_APPLICATION, dc, "w");
         window.getTask().mTaskRecord = mock(TaskRecord.class, ExtendedMockito.RETURNS_DEEP_STUBS);
-        window.mAppToken.mOrientation = SCREEN_ORIENTATION_LANDSCAPE;
+        window.mAppToken.setOrientation(newOrientation);
 
         ActivityRecord activityRecord = mock(ActivityRecord.class);
 
@@ -606,22 +608,21 @@
         verify(mWm.mAtmService).updateDisplayOverrideConfigurationLocked(captor.capture(),
                 same(activityRecord), anyBoolean(), eq(dc.getDisplayId()));
         final Configuration newDisplayConfig = captor.getValue();
-        assertEquals(Configuration.ORIENTATION_LANDSCAPE, newDisplayConfig.orientation);
+        assertEquals(Configuration.ORIENTATION_PORTRAIT, newDisplayConfig.orientation);
     }
 
     @Test
     public void testOnDescendantOrientationRequestChanged_FrozenToUserRotation() {
-        final DisplayInfo info = new DisplayInfo();
-        info.logicalWidth = 1080;
-        info.logicalHeight = 1920;
-        info.logicalDensityDpi = 240;
-        final DisplayContent dc = createNewDisplay(info);
+        final DisplayContent dc = createNewDisplay();
         dc.getDisplayRotation().setFixedToUserRotation(true);
         mWm.mAtmService.mRootActivityContainer = mock(RootActivityContainer.class);
+        final int newOrientation = dc.getLastOrientation() == SCREEN_ORIENTATION_LANDSCAPE
+                ? SCREEN_ORIENTATION_PORTRAIT
+                : SCREEN_ORIENTATION_LANDSCAPE;
 
         final WindowState window = createWindow(null /* parent */, TYPE_BASE_APPLICATION, dc, "w");
         window.getTask().mTaskRecord = mock(TaskRecord.class, ExtendedMockito.RETURNS_DEEP_STUBS);
-        window.mAppToken.mOrientation = SCREEN_ORIENTATION_LANDSCAPE;
+        window.mAppToken.setOrientation(newOrientation);
 
         ActivityRecord activityRecord = mock(ActivityRecord.class);
 
@@ -632,6 +633,39 @@
                 eq(activityRecord), anyBoolean(), eq(dc.getDisplayId()));
     }
 
+    @Test
+    public void testComputeImeParent_app() throws Exception {
+        try (final InsetsModeSession session =
+                     new InsetsModeSession(ViewRootImpl.NEW_INSETS_MODE_IME)) {
+            final DisplayContent dc = createNewDisplay();
+            dc.mInputMethodTarget = createWindow(null, TYPE_BASE_APPLICATION, "app");
+            assertEquals(dc.mInputMethodTarget.mAppToken.getSurfaceControl(),
+                    dc.computeImeParent());
+        }
+    }
+
+    @Test
+    public void testComputeImeParent_app_notFullscreen() throws Exception {
+        try (final InsetsModeSession session =
+                     new InsetsModeSession(ViewRootImpl.NEW_INSETS_MODE_IME)) {
+            final DisplayContent dc = createNewDisplay();
+            dc.mInputMethodTarget = createWindow(null, TYPE_STATUS_BAR, "app");
+            dc.mInputMethodTarget.setWindowingMode(
+                    WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
+            assertEquals(dc.getWindowingLayer(), dc.computeImeParent());
+        }
+    }
+
+    @Test
+    public void testComputeImeParent_noApp() throws Exception {
+        try (final InsetsModeSession session =
+                     new InsetsModeSession(ViewRootImpl.NEW_INSETS_MODE_IME)) {
+            final DisplayContent dc = createNewDisplay();
+            dc.mInputMethodTarget = createWindow(null, TYPE_STATUS_BAR, "statusBar");
+            assertEquals(dc.getWindowingLayer(), dc.computeImeParent());
+        }
+    }
+
     private boolean isOptionsPanelAtRight(int displayId) {
         return (mWm.getPreferredOptionsPanelGravity(displayId) & Gravity.RIGHT) == Gravity.RIGHT;
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
index 845a09f..4279c41 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
@@ -28,6 +28,8 @@
 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_NEVER;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
+import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
 
@@ -37,6 +39,7 @@
 import static org.mockito.Mockito.doNothing;
 import static org.mockito.Mockito.spy;
 
+import android.graphics.Insets;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.platform.test.annotations.Presubmit;
@@ -350,6 +353,48 @@
     }
 
     @Test
+    public void layoutWindowLw_withForwardInset_SoftInputAdjustResize() {
+        synchronized (mWm.mGlobalLock) {
+            mWindow.mAttrs.softInputMode = SOFT_INPUT_ADJUST_RESIZE;
+            addWindow(mWindow);
+
+            final int forwardedInsetBottom = 50;
+            mDisplayPolicy.setForwardedInsets(Insets.of(0, 0, 0, forwardedInsetBottom));
+            mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+            mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
+
+            assertInsetBy(mWindow.getParentFrame(), 0, 0, 0, 0);
+            assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+            assertInsetByTopBottom(mWindow.getContentFrameLw(),
+                    STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT + forwardedInsetBottom);
+            assertInsetByTopBottom(mWindow.getVisibleFrameLw(),
+                    STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT + forwardedInsetBottom);
+            assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
+            assertInsetBy(mWindow.getDisplayFrameLw(), 0, 0, 0, 0);
+        }
+    }
+
+    @Test
+    public void layoutWindowLw_withForwardInset_SoftInputAdjustNothing() {
+        synchronized (mWm.mGlobalLock) {
+            mWindow.mAttrs.softInputMode = SOFT_INPUT_ADJUST_NOTHING;
+            addWindow(mWindow);
+
+            final int forwardedInsetBottom = 50;
+            mDisplayPolicy.setForwardedInsets(Insets.of(0, 0, 0, forwardedInsetBottom));
+            mDisplayPolicy.beginLayoutLw(mFrames, 0 /* UI mode */);
+            mDisplayPolicy.layoutWindowLw(mWindow, null, mFrames);
+
+            assertInsetBy(mWindow.getParentFrame(), 0, 0, 0, 0);
+            assertInsetByTopBottom(mWindow.getStableFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+            assertInsetByTopBottom(mWindow.getContentFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+            assertInsetByTopBottom(mWindow.getVisibleFrameLw(), STATUS_BAR_HEIGHT, NAV_BAR_HEIGHT);
+            assertInsetBy(mWindow.getDecorFrame(), 0, 0, 0, 0);
+            assertInsetBy(mWindow.getDisplayFrameLw(), 0, 0, 0, 0);
+        }
+    }
+
+    @Test
     public void layoutHint_appWindow() {
         synchronized (mWm.mGlobalLock) {
             // Initialize DisplayFrames
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
index d05711e..198e7ce 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayRotationTests.java
@@ -33,6 +33,7 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
 import android.content.ContentResolver;
@@ -611,6 +612,23 @@
     // ========================
     // Non-rotation API Tests
     // ========================
+    @Test
+    public void testRespectsAppRequestedOrientationByDefault() throws Exception {
+        mBuilder.build();
+
+        assertTrue("Display rotation should respect app requested orientation by"
+                + " default.", mTarget.respectAppRequestedOrientation());
+    }
+
+    @Test
+    public void testNotRespectAppRequestedOrientation_FixedToUserRotation() throws Exception {
+        mBuilder.build();
+        mTarget.setFixedToUserRotation(true);
+
+        assertFalse("Display rotation shouldn't respect app requested orientation if"
+                + " fixed to user rotation.", mTarget.respectAppRequestedOrientation());
+    }
+
     /**
      * Call {@link DisplayRotation#configure(int, int, int, int)} to configure {@link #mTarget}
      * according to given parameters.
diff --git a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java
index a498a1a..0c363de 100644
--- a/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/InsetsSourceProviderTest.java
@@ -39,7 +39,6 @@
 import org.junit.Test;
 
 @SmallTest
-@FlakyTest(detail = "Promote once confirmed non-flaky")
 @Presubmit
 public class InsetsSourceProviderTest extends WindowTestsBase {
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java b/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java
index beaac8e..86bf3db 100644
--- a/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/PendingRemoteAnimationRegistryTest.java
@@ -40,7 +40,6 @@
  *  atest WmTests:PendingRemoteAnimationRegistryTest
  */
 @SmallTest
-@FlakyTest
 @Presubmit
 public class PendingRemoteAnimationRegistryTest extends ActivityTestsBase {
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/PersisterQueueTests.java b/services/tests/wmtests/src/com/android/server/wm/PersisterQueueTests.java
index 434ba93..c3d2f33 100644
--- a/services/tests/wmtests/src/com/android/server/wm/PersisterQueueTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/PersisterQueueTests.java
@@ -47,7 +47,6 @@
  *  atest WmTests:PersisterQueueTests
  */
 @MediumTest
-@FlakyTest(detail = "Confirm stable in post-submit before removing")
 @Presubmit
 public class PersisterQueueTests implements PersisterQueue.Listener {
     private static final long INTER_WRITE_DELAY_MS = 50;
diff --git a/services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java b/services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java
index 530fd6d..dad6c95 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java
@@ -31,7 +31,6 @@
  *  atest WmTests:SafeActivityOptionsTest
  */
 @MediumTest
-@FlakyTest
 @Presubmit
 public class SafeActivityOptionsTest {
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java
index 9b84215..8c32e8c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java
@@ -96,7 +96,7 @@
         callbackCaptor.getValue().onAnimationFinished(mSpec);
         assertNotAnimating(mAnimatable);
         assertTrue(mAnimatable.mFinishedCallbackCalled);
-        verify(mTransaction).reparent(eq(mAnimatable.mLeash), eq(null));
+        verify(mTransaction).remove(eq(mAnimatable.mLeash));
         // TODO: Verify reparenting once we use mPendingTransaction to reparent it back
     }
 
@@ -106,7 +106,7 @@
         final SurfaceControl firstLeash = mAnimatable.mLeash;
         mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec2, true /* hidden */);
 
-        verify(mTransaction).reparent(eq(firstLeash), eq(null));
+        verify(mTransaction).remove(eq(firstLeash));
         assertFalse(mAnimatable.mFinishedCallbackCalled);
 
         final ArgumentCaptor<OnAnimationFinishedCallback> callbackCaptor = ArgumentCaptor.forClass(
@@ -133,7 +133,7 @@
         assertNotAnimating(mAnimatable);
         verify(mSpec).onAnimationCancelled(any());
         assertTrue(mAnimatable.mFinishedCallbackCalled);
-        verify(mTransaction).reparent(eq(mAnimatable.mLeash), eq(null));
+        verify(mTransaction).remove(eq(mAnimatable.mLeash));
     }
 
     @Test
@@ -155,7 +155,7 @@
         verifyZeroInteractions(mSpec);
         assertNotAnimating(mAnimatable);
         assertTrue(mAnimatable.mFinishedCallbackCalled);
-        verify(mTransaction).reparent(eq(mAnimatable.mLeash), eq(null));
+        verify(mTransaction).remove(eq(mAnimatable.mLeash));
     }
 
     @Test
@@ -171,15 +171,14 @@
         assertNotAnimating(mAnimatable);
         assertAnimating(mAnimatable2);
         assertEquals(leash, mAnimatable2.mSurfaceAnimator.mLeash);
-        verify(mTransaction, never()).reparent(eq(leash), eq(null));
+        verify(mTransaction, never()).remove(eq(leash));
         callbackCaptor.getValue().onAnimationFinished(mSpec);
         assertNotAnimating(mAnimatable2);
         assertTrue(mAnimatable2.mFinishedCallbackCalled);
-        verify(mTransaction).reparent(eq(leash), eq(null));
+        verify(mTransaction).remove(eq(leash));
     }
 
     @Test
-    @FlakyTest(detail = "Promote once confirmed non-flaky")
     public void testDeferFinish() {
 
         // Start animation
@@ -198,7 +197,7 @@
         mDeferFinishAnimatable.mEndDeferFinishCallback.run();
         assertNotAnimating(mAnimatable2);
         assertTrue(mDeferFinishAnimatable.mFinishedCallbackCalled);
-        verify(mTransaction).reparent(eq(mDeferFinishAnimatable.mLeash), eq(null));
+        verify(mTransaction).remove(eq(mDeferFinishAnimatable.mLeash));
     }
 
     private void assertAnimating(MyAnimatable animatable) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskPersisterTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskPersisterTest.java
index df7bc11..12ed3c2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskPersisterTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskPersisterTest.java
@@ -41,7 +41,6 @@
  * Build/Install/Run:
  *  atest WmTests:TaskPersisterTest
  */
-@FlakyTest(detail = "Promote to presubmit if stable")
 @Presubmit
 public class TaskPersisterTest {
     private static final String TEST_USER_NAME = "AM-Test-User";
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
index e182c45..bcf9dd2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskRecordTests.java
@@ -25,13 +25,6 @@
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
 
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doCallRealMethod;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
 import static com.android.server.wm.WindowContainer.POSITION_TOP;
 
 import static org.hamcrest.Matchers.not;
@@ -41,6 +34,7 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
 
 import android.app.ActivityManager;
 import android.content.ComponentName;
@@ -53,7 +47,6 @@
 import android.service.voice.IVoiceInteractionSession;
 import android.util.Xml;
 import android.view.DisplayInfo;
-import android.view.Surface;
 
 import androidx.test.filters.MediumTest;
 
@@ -62,6 +55,7 @@
 
 import org.junit.Before;
 import org.junit.Test;
+import org.mockito.Mockito;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
 import org.xmlpull.v1.XmlSerializer;
@@ -284,48 +278,33 @@
     }
 
     @Test
-    public void testUpdatesForcedOrientationInBackground() {
-        final DisplayInfo info = new DisplayInfo();
-        info.logicalWidth = 1920;
-        info.logicalHeight = 1080;
-        final ActivityDisplay display = addNewActivityDisplayAt(info, POSITION_TOP);
-        doCallRealMethod().when(display.mDisplayContent).setDisplayRotation(any());
-        display.mDisplayContent.setDisplayRotation(mock(DisplayRotation.class));
-        doCallRealMethod().when(display.mDisplayContent).onDescendantOrientationChanged(any(),
-                any());
-        doCallRealMethod().when(display.mDisplayContent).setRotation(anyInt());
-        doAnswer(invocation -> {
-            display.mDisplayContent.setRotation(Surface.ROTATION_0);
-            return null;
-        }).when(display.mDisplayContent).updateOrientationFromAppTokens(any(), any(), anyBoolean());
+    public void testIgnoresForcedOrientationWhenParentHandles() {
+        final Rect fullScreenBounds = new Rect(0, 0, 1920, 1080);
+        DisplayInfo info = new DisplayInfo();
+        info.logicalWidth = fullScreenBounds.width();
+        info.logicalHeight = fullScreenBounds.height();
+        ActivityDisplay display = addNewActivityDisplayAt(info, POSITION_TOP);
 
-        final ActivityStack stack = new StackBuilder(mRootActivityContainer)
+        display.getRequestedOverrideConfiguration().orientation =
+                Configuration.ORIENTATION_LANDSCAPE;
+        display.onRequestedOverrideConfigurationChanged(
+                display.getRequestedOverrideConfiguration());
+        ActivityStack stack = new StackBuilder(mRootActivityContainer)
                 .setWindowingMode(WINDOWING_MODE_FULLSCREEN).setDisplay(display).build();
-        final TaskRecord task = stack.getChildAt(0);
-        final ActivityRecord activity = task.getRootActivity();
+        TaskRecord task = stack.getChildAt(0);
+        ActivityRecord root = task.getTopActivity();
 
-        // Wire up app window token and task.
-        doCallRealMethod().when(activity.mAppWindowToken).setOrientation(anyInt(), any(), any());
-        doCallRealMethod().when(activity.mAppWindowToken).onDescendantOrientationChanged(any(),
-                any());
-        doReturn(task.mTask).when(activity.mAppWindowToken).getParent();
+        final WindowContainer parentWindowContainer = mock(WindowContainer.class);
+        Mockito.doReturn(parentWindowContainer).when(task.mTask).getParent();
+        Mockito.doReturn(true).when(parentWindowContainer)
+                .handlesOrientationChangeFromDescendant();
 
-        // Wire up task and stack.
-        task.mTask.mTaskRecord = task;
-        doCallRealMethod().when(task.mTask).onDescendantOrientationChanged(any(), any());
-        doReturn(stack.getTaskStack()).when(task.mTask).getParent();
-
-        // Wire up stack and display content.
-        doCallRealMethod().when(stack.mTaskStack).onDescendantOrientationChanged(any(), any());
-        doReturn(display.mDisplayContent).when(stack.mTaskStack).getParent();
-
-        activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
-        assertTrue("Bounds of the task should be pillarboxed.",
-                task.getBounds().width() < task.getBounds().height());
-
-        activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED);
-        assertTrue("Bounds of the task should be fullscreen.",
-                task.getBounds().equals(new Rect(0, 0, 1920, 1080)));
+        // Setting app to fixed portrait fits within parent, but TaskRecord shouldn't adjust the
+        // bounds because its parent says it will handle it at a later time.
+        setActivityRequestedOrientation(root, SCREEN_ORIENTATION_PORTRAIT);
+        assertEquals(root, task.getRootActivity());
+        assertEquals(SCREEN_ORIENTATION_PORTRAIT, task.getRootActivity().getOrientation());
+        assertEquals(fullScreenBounds, task.getBounds());
     }
 
     /** Ensures that the alias intent won't have target component resolved. */
diff --git a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
index d1fe48a..bfb9193 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -28,6 +28,7 @@
 import android.content.res.Configuration;
 import android.os.Bundle;
 import android.os.IBinder;
+import android.os.PowerManager.WakeReason;
 import android.os.RemoteException;
 import android.util.proto.ProtoOutputStream;
 import android.view.IWindow;
@@ -182,11 +183,11 @@
     }
 
     @Override
-    public void startedWakingUp() {
+    public void startedWakingUp(@WakeReason int reason) {
     }
 
     @Override
-    public void finishedWakingUp() {
+    public void finishedWakingUp(@WakeReason int reason) {
     }
 
     @Override
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerControllerTests.java
index de3567e..af8ccc9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerControllerTests.java
@@ -37,7 +37,6 @@
  * Build/Install/Run:
  *  atest FrameworksServicesTests:WindowContainerControllerTests
  */
-@FlakyTest(bugId = 74078662)
 @SmallTest
 @Presubmit
 public class WindowContainerControllerTests extends WindowTestsBase {
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
index 8628575..a9a76c2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
@@ -51,6 +51,7 @@
 import androidx.test.filters.SmallTest;
 
 import org.junit.Test;
+import org.mockito.Mockito;
 
 import java.util.Comparator;
 
@@ -739,6 +740,18 @@
         verify(root).onDescendantOrientationChanged(binder, activityRecord);
     }
 
+    @Test
+    public void testHandlesOrientationChangeFromDescendantProgation() {
+        final TestWindowContainerBuilder builder = new TestWindowContainerBuilder(mWm);
+        final TestWindowContainer root = spy(builder.build());
+
+        final TestWindowContainer child = root.addChildWindow();
+        assertFalse(child.handlesOrientationChangeFromDescendant());
+
+        Mockito.doReturn(true).when(root).handlesOrientationChangeFromDescendant();
+        assertTrue(child.handlesOrientationChangeFromDescendant());
+    }
+
     /* Used so we can gain access to some protected members of the {@link WindowContainer} class */
     private static class TestWindowContainer extends WindowContainer<TestWindowContainer> {
         private final int mLayer;
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
index c09cd46..3eb9085 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java
@@ -21,6 +21,7 @@
 import static android.hardware.camera2.params.OutputConfiguration.ROTATION_90;
 import static android.view.InsetsState.TYPE_TOP_BAR;
 import static android.view.Surface.ROTATION_0;
+import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL;
 import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
 import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
@@ -38,6 +39,7 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.reset;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
 
 import static org.hamcrest.Matchers.is;
@@ -48,9 +50,11 @@
 import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.anyLong;
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doNothing;
 
 import android.graphics.Insets;
 import android.graphics.Matrix;
@@ -60,6 +64,7 @@
 import android.view.DisplayCutout;
 import android.view.InsetsSource;
 import android.view.SurfaceControl;
+import android.view.ViewRootImpl;
 import android.view.WindowManager;
 
 import androidx.test.filters.FlakyTest;
@@ -67,6 +72,9 @@
 
 import com.android.server.wm.utils.WmDisplayCutout;
 
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
 import org.junit.Test;
 
 import java.util.LinkedList;
@@ -77,10 +85,33 @@
  * Build/Install/Run:
  *  atest FrameworksServicesTests:WindowStateTests
  */
-@FlakyTest(bugId = 74078662)
 @SmallTest
 @Presubmit
 public class WindowStateTests extends WindowTestsBase {
+    private static int sPreviousNewInsetsMode;
+
+    @BeforeClass
+    public static void setUpOnce() {
+        // TODO: Make use of SettingsSession when it becomes feasible for this.
+        sPreviousNewInsetsMode = ViewRootImpl.sNewInsetsMode;
+        // To let the insets provider control the insets visibility, the insets mode has to be
+        // NEW_INSETS_MODE_FULL.
+        ViewRootImpl.sNewInsetsMode = NEW_INSETS_MODE_FULL;
+    }
+
+    @AfterClass
+    public static void tearDownOnce() {
+        ViewRootImpl.sNewInsetsMode = sPreviousNewInsetsMode;
+    }
+
+    @Before
+    public void setUp() {
+        // TODO: Let the insets source with new mode keep the visibility control, and remove this
+        // setup code. Now mTopFullscreenOpaqueWindowState will take back the control of insets
+        // visibility.
+        spyOn(mDisplayContent);
+        doNothing().when(mDisplayContent).layoutAndAssignWindowLayersIfNeeded();
+    }
 
     @Test
     public void testIsParentWindowHidden() {
@@ -263,12 +294,12 @@
 
         reset(sPowerManagerWrapper);
         first.prepareWindowToDisplayDuringRelayout(false /*wasVisible*/);
-        verify(sPowerManagerWrapper, never()).wakeUp(anyLong(), anyString());
+        verify(sPowerManagerWrapper, never()).wakeUp(anyLong(), anyInt(), anyString());
         assertTrue(appWindowToken.canTurnScreenOn());
 
         reset(sPowerManagerWrapper);
         second.prepareWindowToDisplayDuringRelayout(false /*wasVisible*/);
-        verify(sPowerManagerWrapper).wakeUp(anyLong(), anyString());
+        verify(sPowerManagerWrapper).wakeUp(anyLong(), anyInt(), anyString());
         assertFalse(appWindowToken.canTurnScreenOn());
 
         // Call prepareWindowToDisplayDuringRelayout for two window that have FLAG_TURN_SCREEN_ON
@@ -279,12 +310,12 @@
 
         reset(sPowerManagerWrapper);
         first.prepareWindowToDisplayDuringRelayout(false /*wasVisible*/);
-        verify(sPowerManagerWrapper).wakeUp(anyLong(), anyString());
+        verify(sPowerManagerWrapper).wakeUp(anyLong(), anyInt(), anyString());
         assertFalse(appWindowToken.canTurnScreenOn());
 
         reset(sPowerManagerWrapper);
         second.prepareWindowToDisplayDuringRelayout(false /*wasVisible*/);
-        verify(sPowerManagerWrapper, never()).wakeUp(anyLong(), anyString());
+        verify(sPowerManagerWrapper, never()).wakeUp(anyLong(), anyInt(), anyString());
         assertFalse(appWindowToken.canTurnScreenOn());
 
         // Call prepareWindowToDisplayDuringRelayout for a windows that are not children of an
@@ -300,11 +331,11 @@
 
         reset(sPowerManagerWrapper);
         firstWindow.prepareWindowToDisplayDuringRelayout(false /*wasVisible*/);
-        verify(sPowerManagerWrapper).wakeUp(anyLong(), anyString());
+        verify(sPowerManagerWrapper).wakeUp(anyLong(), anyInt(), anyString());
 
         reset(sPowerManagerWrapper);
         secondWindow.prepareWindowToDisplayDuringRelayout(false /*wasVisible*/);
-        verify(sPowerManagerWrapper).wakeUp(anyLong(), anyString());
+        verify(sPowerManagerWrapper).wakeUp(anyLong(), anyInt(), anyString());
     }
 
     @Test
@@ -328,6 +359,7 @@
         assertFalse(app.canAffectSystemUiFlags());
     }
 
+    @FlakyTest(detail = "Promote to presubmit when shown to be stable.")
     @Test
     public void testVisibleWithInsetsProvider() throws Exception {
         final WindowState topBar = createWindow(null, TYPE_STATUS_BAR, "topBar");
@@ -339,6 +371,7 @@
         mDisplayContent.getInsetsStateController().onBarControllingWindowChanged(app);
         mDisplayContent.getInsetsStateController().getSourceProvider(TYPE_TOP_BAR)
                 .onInsetsModified(app, new InsetsSource(TYPE_TOP_BAR));
+        waitUntilHandlersIdle();
         assertFalse(topBar.isVisible());
     }
 
@@ -435,6 +468,6 @@
         root.mAttrs.flags |= WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON;
 
         root.prepareWindowToDisplayDuringRelayout(wasVisible /*wasVisible*/);
-        verify(sPowerManagerWrapper).wakeUp(anyLong(), anyString());
+        verify(sPowerManagerWrapper).wakeUp(anyLong(), anyInt(), anyString());
     }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java
index 3048f1a..d556886 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java
@@ -39,7 +39,6 @@
  * Build/Install/Run:
  *  atest FrameworksServicesTests:WindowTokenTests
  */
-@FlakyTest(bugId = 74078662)
 @SmallTest
 @Presubmit
 public class WindowTokenTests extends WindowTestsBase {
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java b/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java
index b81a8e7..b6b9a86 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTracingTest.java
@@ -60,7 +60,6 @@
  * Build/Install/Run:
  *  atest FrameworksServicesTests:WindowTracingTest
  */
-@FlakyTest(bugId = 74078662)
 @SmallTest
 @Presubmit
 public class WindowTracingTest {
diff --git a/services/tests/wmtests/src/com/android/server/wm/utils/RotationCacheTest.java b/services/tests/wmtests/src/com/android/server/wm/utils/RotationCacheTest.java
index 33f34b4..05d8237 100644
--- a/services/tests/wmtests/src/com/android/server/wm/utils/RotationCacheTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/utils/RotationCacheTest.java
@@ -37,7 +37,6 @@
  *  atest WmTests:RotationCacheTest
  */
 @SmallTest
-@FlakyTest(bugId = 74078662)
 @Presubmit
 public class RotationCacheTest {
 
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index a6d7ee6..df2f455 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -493,6 +493,8 @@
             switch (event.mEventType) {
                 case Event.ACTIVITY_RESUMED:
                     synchronized (mVisibleActivities) {
+                        // check if this activity has already been resumed
+                        if (mVisibleActivities.get(event.mInstanceId) != null) break;
                         mVisibleActivities.put(event.mInstanceId, event.getClassName());
                         try {
                             mAppTimeLimit.noteUsageStart(packageName, userId);
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
index 7cab432..93f758c 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
@@ -1307,13 +1307,15 @@
 
                 List<String> roleHolders = mRm.getRoleHoldersAsUser(roleName, user);
 
+                int userId = user.getIdentifier();
                 if (roleHolders.isEmpty()) {
-                    Settings.Secure.putString(getContext().getContentResolver(),
-                            Settings.Secure.ASSISTANT, "");
-                    Settings.Secure.putString(getContext().getContentResolver(),
-                            Settings.Secure.VOICE_INTERACTION_SERVICE, "");
-                    Settings.Secure.putString(getContext().getContentResolver(),
-                            Settings.Secure.VOICE_RECOGNITION_SERVICE, getDefaultRecognizer(user));
+                    Settings.Secure.putStringForUser(getContext().getContentResolver(),
+                            Settings.Secure.ASSISTANT, "", userId);
+                    Settings.Secure.putStringForUser(getContext().getContentResolver(),
+                            Settings.Secure.VOICE_INTERACTION_SERVICE, "", userId);
+                    Settings.Secure.putStringForUser(getContext().getContentResolver(),
+                            Settings.Secure.VOICE_RECOGNITION_SERVICE, getDefaultRecognizer(user),
+                            userId);
                 } else {
                     // Assistant is singleton role
                     String pkg = roleHolders.get(0);
@@ -1321,7 +1323,7 @@
                     // Try to set role holder as VoiceInteractionService
                     List<ResolveInfo> services = mPm.queryIntentServicesAsUser(
                             new Intent(VoiceInteractionService.SERVICE_INTERFACE).setPackage(pkg),
-                            PackageManager.GET_META_DATA, user.getIdentifier());
+                            PackageManager.GET_META_DATA, userId);
 
                     for (ResolveInfo resolveInfo : services) {
                         ServiceInfo serviceInfo = resolveInfo.serviceInfo;
@@ -1339,12 +1341,14 @@
                                 voiceInteractionServiceInfo.getRecognitionService())
                                 .flattenToShortString();
 
-                        Settings.Secure.putString(getContext().getContentResolver(),
-                                Settings.Secure.ASSISTANT, serviceComponentName);
-                        Settings.Secure.putString(getContext().getContentResolver(),
-                                Settings.Secure.VOICE_INTERACTION_SERVICE, serviceComponentName);
-                        Settings.Secure.putString(getContext().getContentResolver(),
-                                Settings.Secure.VOICE_RECOGNITION_SERVICE, serviceRecognizerName);
+                        Settings.Secure.putStringForUser(getContext().getContentResolver(),
+                                Settings.Secure.ASSISTANT, serviceComponentName, userId);
+                        Settings.Secure.putStringForUser(getContext().getContentResolver(),
+                                Settings.Secure.VOICE_INTERACTION_SERVICE, serviceComponentName,
+                                userId);
+                        Settings.Secure.putStringForUser(getContext().getContentResolver(),
+                                Settings.Secure.VOICE_RECOGNITION_SERVICE, serviceRecognizerName,
+                                userId);
 
                         return;
                     }
@@ -1352,19 +1356,19 @@
                     // If no service could be found try to set assist activity
                     final List<ResolveInfo> activities = mPm.queryIntentActivitiesAsUser(
                             new Intent(Intent.ACTION_ASSIST).setPackage(pkg),
-                            PackageManager.MATCH_DEFAULT_ONLY, user.getIdentifier());
+                            PackageManager.MATCH_DEFAULT_ONLY, userId);
 
                     for (ResolveInfo resolveInfo : activities) {
                         ActivityInfo activityInfo = resolveInfo.activityInfo;
 
-                        Settings.Secure.putString(getContext().getContentResolver(),
+                        Settings.Secure.putStringForUser(getContext().getContentResolver(),
                                 Settings.Secure.ASSISTANT,
-                                activityInfo.getComponentName().flattenToShortString());
-                        Settings.Secure.putString(getContext().getContentResolver(),
-                                Settings.Secure.VOICE_INTERACTION_SERVICE, "");
-                        Settings.Secure.putString(getContext().getContentResolver(),
+                                activityInfo.getComponentName().flattenToShortString(), userId);
+                        Settings.Secure.putStringForUser(getContext().getContentResolver(),
+                                Settings.Secure.VOICE_INTERACTION_SERVICE, "", userId);
+                        Settings.Secure.putStringForUser(getContext().getContentResolver(),
                                 Settings.Secure.VOICE_RECOGNITION_SERVICE,
-                                getDefaultRecognizer(user));
+                                getDefaultRecognizer(user), userId);
                     }
                 }
             }
diff --git a/startop/view_compiler/Android.bp b/startop/view_compiler/Android.bp
index 37caeb2..f5b4308 100644
--- a/startop/view_compiler/Android.bp
+++ b/startop/view_compiler/Android.bp
@@ -58,8 +58,6 @@
         "util.cc",
         "layout_validation.cc",
     ],
-    // b/123880763, clang-tidy analyzer has segmentation fault with dex_builder.cc
-    tidy_checks: ["-clang-analyzer-*"],
     host_supported: true,
 }
 
diff --git a/startop/view_compiler/OWNERS b/startop/view_compiler/OWNERS
new file mode 100644
index 0000000..e5aead9
--- /dev/null
+++ b/startop/view_compiler/OWNERS
@@ -0,0 +1,2 @@
+eholk@google.com
+mathieuc@google.com
diff --git a/startop/view_compiler/dex_builder.cc b/startop/view_compiler/dex_builder.cc
index 4c1a0dc7..6047e8c 100644
--- a/startop/view_compiler/dex_builder.cc
+++ b/startop/view_compiler/dex_builder.cc
@@ -426,7 +426,7 @@
     // Some of the registers don't fit in the four bit short form of the invoke
     // instruction, so we need to do an invoke/range. To do this, we need to
     // first move all the arguments into contiguous temporary registers.
-    std::array<Value, kMaxArgs> scratch{GetScratchRegisters<kMaxArgs>()};
+    std::array<Value, kMaxArgs> scratch = GetScratchRegisters<kMaxArgs>();
 
     const auto& prototype = dex_->GetPrototypeByMethodId(instruction.method_id());
     CHECK(prototype.has_value());
diff --git a/telecomm/java/android/telecom/CallScreeningService.java b/telecomm/java/android/telecom/CallScreeningService.java
index 818ebd9..2fa388f 100644
--- a/telecomm/java/android/telecom/CallScreeningService.java
+++ b/telecomm/java/android/telecom/CallScreeningService.java
@@ -75,7 +75,7 @@
  *
  * public void requestRole() {
  *     RoleManager roleManager = (RoleManager) getSystemService(ROLE_SERVICE);
- *     Intent intent = roleManager.createRequestRoleIntent("android.app.role.CALL_SCREENING_APP");
+ *     Intent intent = roleManager.createRequestRoleIntent("android.app.role.CALL_SCREENING");
  *     startActivityForResult(intent, REQUEST_ID);
  * }
  *
diff --git a/telecomm/java/android/telecom/Conference.java b/telecomm/java/android/telecom/Conference.java
index 7d1f8ce..6382acf 100644
--- a/telecomm/java/android/telecom/Conference.java
+++ b/telecomm/java/android/telecom/Conference.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.SystemClock;
@@ -571,6 +572,7 @@
      * @return The primary connection.
      * @hide
      */
+    @TestApi
     @SystemApi
     public Connection getPrimaryConnection() {
         if (mUnmodifiableChildConnections == null || mUnmodifiableChildConnections.isEmpty()) {
diff --git a/telecomm/java/android/telecom/ConferenceParticipant.java b/telecomm/java/android/telecom/ConferenceParticipant.java
index 20b04eb..6317770 100644
--- a/telecomm/java/android/telecom/ConferenceParticipant.java
+++ b/telecomm/java/android/telecom/ConferenceParticipant.java
@@ -19,6 +19,10 @@
 import android.net.Uri;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.text.TextUtils;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.telephony.PhoneConstants;
 
 /**
  * Parcelable representation of a participant's state in a conference call.
@@ -27,6 +31,11 @@
 public class ConferenceParticipant implements Parcelable {
 
     /**
+     * RFC5767 states that a SIP URI with an unknown number should use an address of
+     * {@code anonymous@anonymous.invalid}.  E.g. the host name is anonymous.invalid.
+     */
+    private static final String ANONYMOUS_INVALID_HOST = "anonymous.invalid";
+    /**
      * The conference participant's handle (e.g., phone number).
      */
     private final Uri mHandle;
@@ -50,6 +59,16 @@
     private final int mState;
 
     /**
+     * The connect time of the participant.
+     */
+    private long mConnectTime;
+
+    /**
+     * The connect elapsed time of the participant.
+     */
+    private long mConnectElapsedTime;
+
+    /**
      * Creates an instance of {@code ConferenceParticipant}.
      *
      * @param handle      The conference participant's handle (e.g., phone number).
@@ -92,6 +111,54 @@
     }
 
     /**
+     * Determines the number presentation for a conference participant.  Per RFC5767, if the host
+     * name contains {@code anonymous.invalid} we can assume that there is no valid caller ID
+     * information for the caller, otherwise we'll assume that the URI can be shown.
+     *
+     * @return The number presentation.
+     */
+    @VisibleForTesting
+    public int getParticipantPresentation() {
+        Uri address = getHandle();
+        if (address == null) {
+            return PhoneConstants.PRESENTATION_RESTRICTED;
+        }
+
+        String number = address.getSchemeSpecificPart();
+        // If no number, bail early and set restricted presentation.
+        if (TextUtils.isEmpty(number)) {
+            return PhoneConstants.PRESENTATION_RESTRICTED;
+        }
+        // Per RFC3261, the host name portion can also potentially include extra information:
+        // E.g. sip:anonymous1@anonymous.invalid;legid=1
+        // In this case, hostName will be anonymous.invalid and there is an extra parameter for
+        // legid=1.
+        // Parameters are optional, and the address (e.g. test@test.com) will always be the first
+        // part, with any parameters coming afterwards.
+        String [] hostParts = number.split("[;]");
+        String addressPart = hostParts[0];
+
+        // Get the number portion from the address part.
+        // This will typically be formatted similar to: 6505551212@test.com
+        String [] numberParts = addressPart.split("[@]");
+
+        // If we can't parse the host name out of the URI, then there is probably other data
+        // present, and is likely a valid SIP URI.
+        if (numberParts.length != 2) {
+            return PhoneConstants.PRESENTATION_ALLOWED;
+        }
+        String hostName = numberParts[1];
+
+        // If the hostname portion of the SIP URI is the invalid host string, presentation is
+        // restricted.
+        if (hostName.equals(ANONYMOUS_INVALID_HOST)) {
+            return PhoneConstants.PRESENTATION_RESTRICTED;
+        }
+
+        return PhoneConstants.PRESENTATION_ALLOWED;
+    }
+
+    /**
      * Writes the {@code ConferenceParticipant} to a parcel.
      *
      * @param dest The Parcel in which the object should be written.
@@ -121,6 +188,10 @@
         sb.append(Log.pii(mEndpoint));
         sb.append(" State: ");
         sb.append(Connection.stateToString(mState));
+        sb.append(" ConnectTime: ");
+        sb.append(getConnectTime());
+        sb.append(" ConnectElapsedTime: ");
+        sb.append(getConnectElapsedTime());
         sb.append("]");
         return sb.toString();
     }
@@ -155,4 +226,26 @@
     public int getState() {
         return mState;
     }
+
+    /**
+     * The connect time of the participant to the conference.
+     */
+    public long getConnectTime() {
+        return mConnectTime;
+    }
+
+    public void setConnectTime(long connectTime) {
+        this.mConnectTime = connectTime;
+    }
+
+    /**
+     * The connect elpased time of the participant to the conference.
+     */
+    public long getConnectElapsedTime() {
+        return mConnectElapsedTime;
+    }
+
+    public void setConnectElapsedTime(long connectElapsedTime) {
+        mConnectElapsedTime = connectElapsedTime;
+    }
 }
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 05d5a13..bd0d4ae 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -16,10 +16,6 @@
 
 package android.telecom;
 
-import com.android.internal.os.SomeArgs;
-import com.android.internal.telecom.IVideoCallback;
-import com.android.internal.telecom.IVideoProvider;
-
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
@@ -43,6 +39,10 @@
 import android.util.ArraySet;
 import android.view.Surface;
 
+import com.android.internal.os.SomeArgs;
+import com.android.internal.telecom.IVideoCallback;
+import com.android.internal.telecom.IVideoProvider;
+
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
diff --git a/telecomm/java/android/telecom/DefaultDialerManager.java b/telecomm/java/android/telecom/DefaultDialerManager.java
index 57ae5d3..aac0956d 100644
--- a/telecomm/java/android/telecom/DefaultDialerManager.java
+++ b/telecomm/java/android/telecom/DefaultDialerManager.java
@@ -78,7 +78,7 @@
         try {
             RoleManagerCallback.Future cb = new RoleManagerCallback.Future();
             context.getSystemService(RoleManager.class).addRoleHolderAsUser(
-                    RoleManager.ROLE_DIALER, packageName, UserHandle.of(user),
+                    RoleManager.ROLE_DIALER, packageName, 0, UserHandle.of(user),
                     AsyncTask.THREAD_POOL_EXECUTOR, cb);
             cb.get(5, TimeUnit.SECONDS);
             return true;
diff --git a/telecomm/java/android/telecom/DisconnectCause.java b/telecomm/java/android/telecom/DisconnectCause.java
index 1de67a5..5a97c94 100644
--- a/telecomm/java/android/telecom/DisconnectCause.java
+++ b/telecomm/java/android/telecom/DisconnectCause.java
@@ -16,9 +16,9 @@
 
 package android.telecom;
 
+import android.media.ToneGenerator;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.media.ToneGenerator;
 import android.text.TextUtils;
 
 import java.util.Objects;
@@ -91,6 +91,12 @@
      */
     public static final String REASON_IMS_ACCESS_BLOCKED = "REASON_IMS_ACCESS_BLOCKED";
 
+    /**
+     * Reason code, which indicates that the conference call is simulating single party conference.
+     * @hide
+     */
+    public static final String REASON_EMULATING_SINGLE_CALL = "EMULATING_SINGLE_CALL";
+
     private int mDisconnectCode;
     private CharSequence mDisconnectLabel;
     private CharSequence mDisconnectDescription;
diff --git a/telecomm/java/android/telecom/InCallService.java b/telecomm/java/android/telecom/InCallService.java
index f5f0af7..cbcd40f 100644
--- a/telecomm/java/android/telecom/InCallService.java
+++ b/telecomm/java/android/telecom/InCallService.java
@@ -35,7 +35,6 @@
 import com.android.internal.telecom.IInCallAdapter;
 import com.android.internal.telecom.IInCallService;
 
-import java.lang.String;
 import java.util.Collections;
 import java.util.List;
 
@@ -212,7 +211,7 @@
  *     {@link android.Manifest.permission.CALL_COMPANION_APP}.</li>
  * </ul>
  * <p>
- * Your app should request to fill the role {@code android.app.role.CAR_MODE_DIALER_APP} in order to
+ * Your app should request to fill the role {@code android.app.role.CAR_MODE_DIALER} in order to
  * become the default (see <a href="#requestRole">above</a> for how to request your app fills this
  * role).
  *
@@ -232,7 +231,7 @@
  *     {@link android.Manifest.permission.CALL_COMPANION_APP}.</li>
  * </ul>
  * <p>
- * Your app should request to fill the role {@code android.app.role.CALL_COMPANION_APP} in order to
+ * Your app should request to fill the role {@code android.app.role.CALL_COMPANION} in order to
  * become a call companion app (see <a href="#requestRole">above</a> for how to request your app
  * fills this role).
  */
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 0e17a33..e99a289 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -22,6 +22,7 @@
 import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
+import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
 import android.app.role.RoleManagerCallback;
 import android.content.ComponentName;
@@ -552,6 +553,7 @@
      *
      * @hide
      */
+    @TestApi
     @SystemApi
     public static final int TTY_MODE_OFF = 0;
 
@@ -561,6 +563,7 @@
      *
      * @hide
      */
+    @TestApi
     @SystemApi
     public static final int TTY_MODE_FULL = 1;
 
@@ -571,6 +574,7 @@
      *
      * @hide
      */
+    @TestApi
     @SystemApi
     public static final int TTY_MODE_HCO = 2;
 
@@ -581,6 +585,7 @@
      *
      * @hide
      */
+    @TestApi
     @SystemApi
     public static final int TTY_MODE_VCO = 3;
 
@@ -819,6 +824,7 @@
      * @hide
      */
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+    @TestApi
     @SystemApi
     public void setUserSelectedOutgoingPhoneAccount(PhoneAccountHandle accountHandle) {
         try {
@@ -1521,6 +1527,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
     public @TtyMode int getCurrentTtyMode() {
         try {
@@ -1969,6 +1976,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
     public boolean isInEmergencyCall() {
         try {
diff --git a/telephony/java/android/provider/Telephony.java b/telephony/java/android/provider/Telephony.java
index 5482270..4539ab3 100644
--- a/telephony/java/android/provider/Telephony.java
+++ b/telephony/java/android/provider/Telephony.java
@@ -2118,6 +2118,608 @@
     }
 
     /**
+     * Columns for the "rcs_*" tables used by {@link android.telephony.ims.RcsMessageStore} classes.
+     *
+     * @hide - not meant for public use
+     */
+    public interface RcsColumns {
+        /**
+         * The authority for the content provider
+         */
+        String AUTHORITY = "rcs";
+
+        /**
+         * The URI to start building upon to use {@link com.android.providers.telephony.RcsProvider}
+         */
+        Uri CONTENT_AND_AUTHORITY = Uri.parse("content://" + AUTHORITY);
+
+        /**
+         * The value to be used whenever a transaction that expects an integer to be returned
+         * failed.
+         */
+        int TRANSACTION_FAILED = Integer.MIN_VALUE;
+
+        /**
+         * The value that denotes a timestamp was not set before (e.g. a message that is not
+         * delivered yet will not have a DELIVERED_TIMESTAMP)
+         */
+        long TIMESTAMP_NOT_SET = 0;
+
+        /**
+         * The table that {@link android.telephony.ims.RcsThread} gets persisted to
+         */
+        interface RcsThreadColumns {
+            /**
+             * The path that should be used for referring to
+             * {@link android.telephony.ims.RcsThread}s in
+             * {@link com.android.providers.telephony.RcsProvider} URIs.
+             */
+            String RCS_THREAD_URI_PART = "thread";
+
+            /**
+             * The URI to query or modify {@link android.telephony.ims.RcsThread} via the content
+             * provider.
+             */
+            Uri RCS_THREAD_URI = Uri.withAppendedPath(CONTENT_AND_AUTHORITY, RCS_THREAD_URI_PART);
+
+            /**
+             * The unique identifier of an {@link android.telephony.ims.RcsThread}
+             */
+            String RCS_THREAD_ID_COLUMN = "rcs_thread_id";
+        }
+
+        /**
+         * The table that {@link android.telephony.ims.Rcs1To1Thread} gets persisted to
+         */
+        interface Rcs1To1ThreadColumns extends RcsThreadColumns {
+            /**
+             * The path that should be used for referring to
+             * {@link android.telephony.ims.Rcs1To1Thread}s in
+             * {@link com.android.providers.telephony.RcsProvider} URIs.
+             */
+            String RCS_1_TO_1_THREAD_URI_PART = "p2p_thread";
+
+            /**
+             * The URI to query or modify {@link android.telephony.ims.Rcs1To1Thread}s via the
+             * content provider
+             */
+            Uri RCS_1_TO_1_THREAD_URI = Uri.withAppendedPath(CONTENT_AND_AUTHORITY,
+                    RCS_1_TO_1_THREAD_URI_PART);
+
+            /**
+             * The SMS/MMS thread to fallback to in case of an RCS outage
+             */
+            String FALLBACK_THREAD_ID_COLUMN = "rcs_fallback_thread_id";
+        }
+
+        /**
+         * The table that {@link android.telephony.ims.RcsGroupThread} gets persisted to
+         */
+        interface RcsGroupThreadColumns extends RcsThreadColumns {
+            /**
+             * The path that should be used for referring to
+             * {@link android.telephony.ims.RcsGroupThread}s in
+             * {@link com.android.providers.telephony.RcsProvider} URIs.
+             */
+            String RCS_GROUP_THREAD_URI_PART = "group_thread";
+
+            /**
+             * The URI to query or modify {@link android.telephony.ims.RcsGroupThread}s via the
+             * content provider
+             */
+            Uri RCS_GROUP_THREAD_URI = Uri.withAppendedPath(CONTENT_AND_AUTHORITY,
+                    RCS_GROUP_THREAD_URI_PART);
+
+            /**
+             * The owner/admin of the {@link android.telephony.ims.RcsGroupThread}
+             */
+            String OWNER_PARTICIPANT_COLUMN = "owner_participant";
+
+            /**
+             * The user visible name of the group
+             */
+            String GROUP_NAME_COLUMN = "group_name";
+
+            /**
+             * The user visible icon of the group
+             */
+            String GROUP_ICON_COLUMN = "group_icon";
+
+            /**
+             * The RCS conference URI for this group
+             */
+            String CONFERENCE_URI_COLUMN = "conference_uri";
+        }
+
+        /**
+         * The view that enables polling from all types of RCS threads at once
+         */
+        interface RcsUnifiedThreadColumns extends RcsThreadColumns, Rcs1To1ThreadColumns,
+                RcsGroupThreadColumns {
+            /**
+             * The type of this {@link android.telephony.ims.RcsThread}
+             */
+            String THREAD_TYPE_COLUMN = "thread_type";
+
+            /**
+             * Integer returned as a result from a database query that denotes the thread is 1 to 1
+             */
+            int THREAD_TYPE_1_TO_1 = 0;
+
+            /**
+             * Integer returned as a result from a database query that denotes the thread is 1 to 1
+             */
+            int THREAD_TYPE_GROUP = 1;
+        }
+
+        /**
+         * The table that {@link android.telephony.ims.RcsParticipant} gets persisted to
+         */
+        interface RcsParticipantColumns {
+            /**
+             * The path that should be used for referring to
+             * {@link android.telephony.ims.RcsParticipant}s in
+             * {@link com.android.providers.telephony.RcsProvider} URIs.
+             */
+            String RCS_PARTICIPANT_URI_PART = "participant";
+
+            /**
+             * The URI to query or modify {@link android.telephony.ims.RcsParticipant}s via the
+             * content provider
+             */
+            Uri RCS_PARTICIPANT_URI = Uri.withAppendedPath(CONTENT_AND_AUTHORITY,
+                    RCS_PARTICIPANT_URI_PART);
+
+            /**
+             * The unique identifier of the entry in the database
+             */
+            String RCS_PARTICIPANT_ID_COLUMN = "rcs_participant_id";
+
+            /**
+             * A foreign key on canonical_address table, also used by SMS/MMS
+             */
+            String CANONICAL_ADDRESS_ID_COLUMN = "canonical_address_id";
+
+            /**
+             * The user visible RCS alias for this participant.
+             */
+            String RCS_ALIAS_COLUMN = "rcs_alias";
+        }
+
+        /**
+         * Additional constants to enable access to {@link android.telephony.ims.RcsParticipant}
+         * related data
+         */
+        interface RcsParticipantHelpers extends RcsParticipantColumns {
+            /**
+             * The view that unifies "rcs_participant" and "canonical_addresses" tables for easy
+             * access to participant address.
+             */
+            String RCS_PARTICIPANT_WITH_ADDRESS_VIEW = "rcs_participant_with_address_view";
+
+            /**
+             * The view that unifies "rcs_participant", "canonical_addresses" and
+             * "rcs_thread_participant" junction table to get full information on participants that
+             * contribute to threads.
+             */
+            String RCS_PARTICIPANT_WITH_THREAD_VIEW = "rcs_participant_with_thread_view";
+        }
+
+        /**
+         * The table that {@link android.telephony.ims.RcsMessage} gets persisted to
+         */
+        interface RcsMessageColumns {
+            /**
+             * Denotes the type of this message (i.e.
+             * {@link android.telephony.ims.RcsIncomingMessage} or
+             * {@link android.telephony.ims.RcsOutgoingMessage}
+             */
+            String MESSAGE_TYPE_COLUMN = "rcs_message_type";
+
+            /**
+             * The unique identifier for the message in the database - i.e. the primary key.
+             */
+            String MESSAGE_ID_COLUMN = "rcs_message_row_id";
+
+            /**
+             * The globally unique RCS identifier for the message. Please see 4.4.5.2 - GSMA
+             * RCC.53 (RCS Device API 1.6 Specification)
+             */
+            String GLOBAL_ID_COLUMN = "rcs_message_global_id";
+
+            /**
+             * The subscription where this message was sent from/to.
+             */
+            String SUB_ID_COLUMN = "sub_id";
+
+            /**
+             * The sending status of the message.
+             * @see android.telephony.ims.RcsMessage.RcsMessageStatus
+             */
+            String STATUS_COLUMN = "status";
+
+            /**
+             * The creation timestamp of the message.
+             */
+            String ORIGINATION_TIMESTAMP_COLUMN = "origination_timestamp";
+
+            /**
+             * The text content of the message.
+             */
+            String MESSAGE_TEXT_COLUMN = "rcs_text";
+
+            /**
+             * The latitude content of the message, if it contains a location.
+             */
+            String LATITUDE_COLUMN = "latitude";
+
+            /**
+             * The longitude content of the message, if it contains a location.
+             */
+            String LONGITUDE_COLUMN = "longitude";
+        }
+
+        /**
+         * The table that additional information of {@link android.telephony.ims.RcsIncomingMessage}
+         * gets persisted to.
+         */
+        interface RcsIncomingMessageColumns extends RcsMessageColumns {
+            /**
+             The path that should be used for referring to
+             * {@link android.telephony.ims.RcsIncomingMessage}s in
+             * {@link com.android.providers.telephony.RcsProvider} URIs.
+             */
+            String INCOMING_MESSAGE_URI_PART = "incoming_message";
+
+            /**
+             * The URI to query incoming messages through
+             * {@link com.android.providers.telephony.RcsProvider}
+             */
+            Uri INCOMING_MESSAGE_URI = Uri.withAppendedPath(CONTENT_AND_AUTHORITY,
+                    INCOMING_MESSAGE_URI_PART);
+
+            /**
+             * The ID of the {@link android.telephony.ims.RcsParticipant} that sent this message
+             */
+            String SENDER_PARTICIPANT_ID_COLUMN = "sender_participant";
+
+            /**
+             * The timestamp of arrival for this message.
+             */
+            String ARRIVAL_TIMESTAMP_COLUMN = "arrival_timestamp";
+
+            /**
+             * The time when the recipient has read this message.
+             */
+            String SEEN_TIMESTAMP_COLUMN = "seen_timestamp";
+        }
+
+        /**
+         * The table that additional information of {@link android.telephony.ims.RcsOutgoingMessage}
+         * gets persisted to.
+         */
+        interface RcsOutgoingMessageColumns extends RcsMessageColumns {
+            /**
+             * The path that should be used for referring to
+             * {@link android.telephony.ims.RcsOutgoingMessage}s in
+             * {@link com.android.providers.telephony.RcsProvider} URIs.
+             */
+            String OUTGOING_MESSAGE_URI_PART = "outgoing_message";
+
+            /**
+             * The URI to query or modify {@link android.telephony.ims.RcsOutgoingMessage}s via the
+             * content provider
+             */
+            Uri OUTGOING_MESSAGE_URI = Uri.withAppendedPath(CONTENT_AND_AUTHORITY,
+                    OUTGOING_MESSAGE_URI_PART);
+        }
+
+        /**
+         * The delivery information of an {@link android.telephony.ims.RcsOutgoingMessage}
+         */
+        interface RcsMessageDeliveryColumns extends RcsOutgoingMessageColumns {
+            /**
+             * The path that should be used for referring to
+             * {@link android.telephony.ims.RcsOutgoingMessageDelivery}s in
+             * {@link com.android.providers.telephony.RcsProvider} URIs.
+             */
+            String DELIVERY_URI_PART = "delivery";
+
+            /**
+             * The timestamp of delivery of this message.
+             */
+            String DELIVERED_TIMESTAMP_COLUMN = "delivered_timestamp";
+
+            /**
+             * The time when the recipient has read this message.
+             */
+            String SEEN_TIMESTAMP_COLUMN = "seen_timestamp";
+        }
+
+        /**
+         * The views that allow querying {@link android.telephony.ims.RcsIncomingMessage} and
+         * {@link android.telephony.ims.RcsOutgoingMessage} at the same time.
+         */
+        interface RcsUnifiedMessageColumns extends RcsIncomingMessageColumns,
+                RcsOutgoingMessageColumns {
+            /**
+             * The path that is used to query all {@link android.telephony.ims.RcsMessage} in
+             * {@link com.android.providers.telephony.RcsProvider} URIs.
+             */
+            String UNIFIED_MESSAGE_URI_PART = "message";
+
+            /**
+             * The URI to query all types of {@link android.telephony.ims.RcsMessage}s
+             */
+            Uri UNIFIED_MESSAGE_URI = Uri.withAppendedPath(CONTENT_AND_AUTHORITY,
+                    UNIFIED_MESSAGE_URI_PART);
+
+            /**
+             * The name of the view that unites rcs_message and rcs_incoming_message tables.
+             */
+            String UNIFIED_INCOMING_MESSAGE_VIEW = "unified_incoming_message_view";
+
+            /**
+             * The name of the view that unites rcs_message and rcs_outgoing_message tables.
+             */
+            String UNIFIED_OUTGOING_MESSAGE_VIEW = "unified_outgoing_message_view";
+
+            /**
+             * The column that shows from which table the message entry came from.
+             */
+            String MESSAGE_TYPE_COLUMN = "message_type";
+
+            /**
+             * Integer returned as a result from a database query that denotes that the message is
+             * an incoming message
+             */
+            int MESSAGE_TYPE_INCOMING = 1;
+
+            /**
+             * Integer returned as a result from a database query that denotes that the message is
+             * an outgoing message
+             */
+            int MESSAGE_TYPE_OUTGOING = 0;
+        }
+
+        /**
+         * The table that {@link android.telephony.ims.RcsFileTransferPart} gets persisted to.
+         */
+        interface RcsFileTransferColumns {
+            /**
+             * The path that should be used for referring to
+             * {@link android.telephony.ims.RcsFileTransferPart}s in
+             * {@link com.android.providers.telephony.RcsProvider} URIs.
+             */
+            String FILE_TRANSFER_URI_PART = "file_transfer";
+
+            /**
+             * The URI to query or modify {@link android.telephony.ims.RcsFileTransferPart}s via the
+             * content provider
+             */
+            Uri FILE_TRANSFER_URI = Uri.withAppendedPath(CONTENT_AND_AUTHORITY,
+                    FILE_TRANSFER_URI_PART);
+
+            /**
+             * The globally unique file transfer ID for this RCS file transfer.
+             */
+            String FILE_TRANSFER_ID_COLUMN = "rcs_file_transfer_id";
+
+            /**
+             * The RCS session ID for this file transfer. The ID is implementation dependent but
+             * should be unique.
+             */
+            String SESSION_ID_COLUMN = "session_id";
+
+            /**
+             * The URI that points to the content of this file transfer
+             */
+            String CONTENT_URI_COLUMN = "content_uri";
+
+            /**
+             * The file type of this file transfer in bytes. The validity of types is not enforced
+             * in {@link android.telephony.ims.RcsMessageStore} APIs.
+             */
+            String CONTENT_TYPE_COLUMN = "content_type";
+
+            /**
+             * The size of the file transfer in bytes.
+             */
+            String FILE_SIZE_COLUMN = "file_size";
+
+            /**
+             * Number of bytes that was successfully transmitted for this file transfer
+             */
+            String SUCCESSFULLY_TRANSFERRED_BYTES = "transfer_offset";
+
+            /**
+             * The status of this file transfer
+             * @see android.telephony.ims.RcsFileTransferPart.RcsFileTransferStatus
+             */
+            String TRANSFER_STATUS_COLUMN = "transfer_status";
+
+            /**
+             * The on-screen width of the file transfer, if it contains multi-media
+             */
+            String WIDTH_COLUMN = "width";
+
+            /**
+             * The on-screen height of the file transfer, if it contains multi-media
+             */
+            String HEIGHT_COLUMN = "height";
+
+            /**
+             * The duration of the content in milliseconds if this file transfer contains
+             * multi-media
+             */
+            String DURATION_MILLIS_COLUMN = "duration";
+
+            /**
+             * The URI to the preview of the content of this file transfer
+             */
+            String PREVIEW_URI_COLUMN = "preview_uri";
+
+            /**
+             * The type of the preview of the content of this file transfer. The validity of types
+             * is not enforced in {@link android.telephony.ims.RcsMessageStore} APIs.
+             */
+            String PREVIEW_TYPE_COLUMN = "preview_type";
+        }
+
+        /**
+         * The table that holds the information for
+         * {@link android.telephony.ims.RcsGroupThreadEvent} and its subclasses.
+         */
+        interface RcsThreadEventColumns {
+            /**
+             * The string used in the {@link com.android.providers.telephony.RcsProvider} URI to
+             * refer to participant joined events (example URI:
+             * {@code content://rcs/group_thread/3/participant_joined_event})
+             */
+            String PARTICIPANT_JOINED_URI_PART = "participant_joined_event";
+
+            /**
+             * The string used in the {@link com.android.providers.telephony.RcsProvider} URI to
+             * refer to participant left events. (example URI:
+             * {@code content://rcs/group_thread/3/participant_left_event/4})
+             */
+            String PARTICIPANT_LEFT_URI_PART = "participant_left_event";
+
+            /**
+             * The string used in the {@link com.android.providers.telephony.RcsProvider} URI to
+             * refer to name changed events. (example URI:
+             * {@code content://rcs/group_thread/3/name_changed_event})
+             */
+            String NAME_CHANGED_URI_PART = "name_changed_event";
+
+            /**
+             * The string used in the {@link com.android.providers.telephony.RcsProvider} URI to
+             * refer to icon changed events. (example URI:
+             * {@code content://rcs/group_thread/3/icon_changed_event})
+             */
+            String ICON_CHANGED_URI_PART = "icon_changed_event";
+
+            /**
+             * The unique ID of this event in the database, i.e. the primary key
+             */
+            String EVENT_ID_COLUMN = "event_id";
+
+            /**
+             * The type of this event
+             *
+             * @see RcsEventTypes
+             */
+            String EVENT_TYPE_COLUMN = "event_type";
+
+            /**
+             * The timestamp in milliseconds of when this event happened
+             */
+            String TIMESTAMP_COLUMN = "origination_timestamp";
+
+            /**
+             * The participant that generated this event
+             */
+            String SOURCE_PARTICIPANT_ID_COLUMN = "source_participant";
+
+            /**
+             * The receiving participant of this event if this was an
+             * {@link android.telephony.ims.RcsGroupThreadParticipantJoinedEvent} or
+             * {@link android.telephony.ims.RcsGroupThreadParticipantLeftEvent}
+             */
+            String DESTINATION_PARTICIPANT_ID_COLUMN = "destination_participant";
+
+            /**
+             * The URI for the new icon of the group thread if this was an
+             * {@link android.telephony.ims.RcsGroupThreadIconChangedEvent}
+             */
+            String NEW_ICON_URI_COLUMN = "new_icon_uri";
+
+            /**
+             * The URI for the new name of the group thread if this was an
+             * {@link android.telephony.ims.RcsGroupThreadNameChangedEvent}
+             */
+            String NEW_NAME_COLUMN = "new_name";
+        }
+
+        /**
+         * The table that {@link android.telephony.ims.RcsParticipantAliasChangedEvent} gets
+         * persisted to
+         */
+        interface RcsParticipantEventColumns {
+            /**
+             * The path that should be used for referring to
+             * {@link android.telephony.ims.RcsParticipantAliasChangedEvent}s in
+             * {@link com.android.providers.telephony.RcsProvider} URIs.
+             */
+            String ALIAS_CHANGE_EVENT_URI_PART = "alias_change_event";
+
+            /**
+             * The new alias of the participant
+             */
+            String NEW_ALIAS_COLUMN = "new_alias";
+        }
+
+        /**
+         * These values are used in {@link com.android.providers.telephony.RcsProvider} to determine
+         * what kind of event is present in the storage.
+         */
+        interface RcsEventTypes {
+            /**
+             * Integer constant that is stored in the
+             * {@link com.android.providers.telephony.RcsProvider} database that denotes the event
+             * is of type {@link android.telephony.ims.RcsParticipantAliasChangedEvent}
+             */
+            int PARTICIPANT_ALIAS_CHANGED_EVENT_TYPE = 1;
+
+            /**
+             * Integer constant that is stored in the
+             * {@link com.android.providers.telephony.RcsProvider} database that denotes the event
+             * is of type {@link android.telephony.ims.RcsGroupThreadParticipantJoinedEvent}
+             */
+            int PARTICIPANT_JOINED_EVENT_TYPE = 2;
+
+            /**
+             * Integer constant that is stored in the
+             * {@link com.android.providers.telephony.RcsProvider} database that denotes the event
+             * is of type {@link android.telephony.ims.RcsGroupThreadParticipantLeftEvent}
+             */
+            int PARTICIPANT_LEFT_EVENT_TYPE = 4;
+
+            /**
+             * Integer constant that is stored in the
+             * {@link com.android.providers.telephony.RcsProvider} database that denotes the event
+             * is of type {@link android.telephony.ims.RcsGroupThreadIconChangedEvent}
+             */
+            int ICON_CHANGED_EVENT_TYPE = 8;
+
+            /**
+             * Integer constant that is stored in the
+             * {@link com.android.providers.telephony.RcsProvider} database that denotes the event
+             * is of type {@link android.telephony.ims.RcsGroupThreadNameChangedEvent}
+             */
+            int NAME_CHANGED_EVENT_TYPE = 16;
+        }
+
+        /**
+         * The view that allows unified querying across all events
+         */
+        interface RcsUnifiedEventHelper extends RcsParticipantEventColumns, RcsThreadEventColumns {
+            /**
+             * The path that should be used for referring to
+             * {@link android.telephony.ims.RcsEvent}s in
+             * {@link com.android.providers.telephony.RcsProvider} URIs.
+             */
+            String RCS_EVENT_QUERY_URI_PATH = "event";
+
+            /**
+             * The URI to query {@link android.telephony.ims.RcsEvent}s via the content provider.
+             */
+            Uri RCS_EVENT_QUERY_URI = Uri.withAppendedPath(CONTENT_AND_AUTHORITY,
+                    RCS_EVENT_QUERY_URI_PATH);
+        }
+    }
+
+    /**
      * Contains all MMS messages.
      */
     public static final class Mms implements BaseMmsColumns {
diff --git a/telephony/java/android/telephony/AccessNetworkConstants.java b/telephony/java/android/telephony/AccessNetworkConstants.java
index 9c64cf6..75165af 100644
--- a/telephony/java/android/telephony/AccessNetworkConstants.java
+++ b/telephony/java/android/telephony/AccessNetworkConstants.java
@@ -54,8 +54,15 @@
      */
     @SystemApi
     public static final class TransportType {
+        /**
+         * Invalid transport type.
+         * @hide
+         */
+        public static final int INVALID = -1;
+
         /** Wireless Wide Area Networks (i.e. Cellular) */
         public static final int WWAN = 1;
+
         /** Wireless Local Area Networks (i.e. Wifi) */
         public static final int WLAN = 2;
 
@@ -65,6 +72,7 @@
         /** @hide */
         public static String toString(int type) {
             switch (type) {
+                case INVALID: return "INVALID";
                 case WWAN: return "WWAN";
                 case WLAN: return "WLAN";
                 default: return Integer.toString(type);
diff --git a/telephony/java/android/telephony/CellSignalStrengthGsm.java b/telephony/java/android/telephony/CellSignalStrengthGsm.java
index 30e641d..a4207c9 100644
--- a/telephony/java/android/telephony/CellSignalStrengthGsm.java
+++ b/telephony/java/android/telephony/CellSignalStrengthGsm.java
@@ -63,6 +63,10 @@
     public CellSignalStrengthGsm(android.hardware.radio.V1_0.GsmSignalStrength gsm) {
         // Convert from HAL values as part of construction.
         this(getRssiDbmFromAsu(gsm.signalStrength), gsm.bitErrorRate, gsm.timingAdvance);
+
+        if (mRssi == CellInfo.UNAVAILABLE) {
+            setDefaultValues();
+        }
     }
 
     /** @hide */
diff --git a/telephony/java/android/telephony/CellSignalStrengthTdscdma.java b/telephony/java/android/telephony/CellSignalStrengthTdscdma.java
index 6f52b85..5ae89b0 100644
--- a/telephony/java/android/telephony/CellSignalStrengthTdscdma.java
+++ b/telephony/java/android/telephony/CellSignalStrengthTdscdma.java
@@ -72,6 +72,10 @@
         // Convert from HAL values as part of construction.
         this(CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE,
                 tdscdma.rscp != CellInfo.UNAVAILABLE ? -tdscdma.rscp : tdscdma.rscp);
+
+        if (mRssi == CellInfo.UNAVAILABLE && mRscp == CellInfo.UNAVAILABLE) {
+            setDefaultValues();
+        }
     }
 
     /** @hide */
@@ -79,6 +83,10 @@
         // Convert from HAL values as part of construction.
         this(getRssiDbmFromAsu(tdscdma.signalStrength),
                 tdscdma.bitErrorRate, getRscpDbmFromAsu(tdscdma.rscp));
+
+        if (mRssi == CellInfo.UNAVAILABLE && mRscp == CellInfo.UNAVAILABLE) {
+            setDefaultValues();
+        }
     }
 
     /** @hide */
diff --git a/telephony/java/android/telephony/CellSignalStrengthWcdma.java b/telephony/java/android/telephony/CellSignalStrengthWcdma.java
index 0760407..efa3647 100644
--- a/telephony/java/android/telephony/CellSignalStrengthWcdma.java
+++ b/telephony/java/android/telephony/CellSignalStrengthWcdma.java
@@ -92,8 +92,12 @@
     /** @hide */
     public CellSignalStrengthWcdma(android.hardware.radio.V1_0.WcdmaSignalStrength wcdma) {
         // Convert from HAL values as part of construction.
-        this(getRssiDbmFromAsu(wcdma.signalStrength),
-                wcdma.bitErrorRate, CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE);
+        this(getRssiDbmFromAsu(wcdma.signalStrength), wcdma.bitErrorRate,
+                CellInfo.UNAVAILABLE, CellInfo.UNAVAILABLE);
+
+        if (mRssi == CellInfo.UNAVAILABLE && mRscp == CellInfo.UNAVAILABLE) {
+            setDefaultValues();
+        }
     }
 
     /** @hide */
@@ -103,6 +107,10 @@
                     wcdma.base.bitErrorRate,
                     getRscpDbmFromAsu(wcdma.rscp),
                     getEcNoDbFromAsu(wcdma.ecno));
+
+        if (mRssi == CellInfo.UNAVAILABLE && mRscp == CellInfo.UNAVAILABLE) {
+            setDefaultValues();
+        }
     }
 
     /** @hide */
diff --git a/telephony/java/android/telephony/SmsMessage.java b/telephony/java/android/telephony/SmsMessage.java
index e40bae1..099015f 100644
--- a/telephony/java/android/telephony/SmsMessage.java
+++ b/telephony/java/android/telephony/SmsMessage.java
@@ -187,15 +187,7 @@
         int activePhone = TelephonyManager.getDefault().getCurrentPhoneType();
         String format = (PHONE_TYPE_CDMA == activePhone) ?
                 SmsConstants.FORMAT_3GPP2 : SmsConstants.FORMAT_3GPP;
-        message = createFromPdu(pdu, format);
-
-        if (null == message || null == message.mWrappedSmsMessage) {
-            // decoding pdu failed based on activePhone type, must be other format
-            format = (PHONE_TYPE_CDMA == activePhone) ?
-                    SmsConstants.FORMAT_3GPP : SmsConstants.FORMAT_3GPP2;
-            message = createFromPdu(pdu, format);
-        }
-        return message;
+        return createFromPdu(pdu, format);
     }
 
     /**
@@ -211,11 +203,18 @@
      * {@link android.provider.Telephony.Sms.Intents#SMS_RECEIVED_ACTION} intent
      */
     public static SmsMessage createFromPdu(byte[] pdu, String format) {
-        SmsMessageBase wrappedMessage;
+        return createFromPdu(pdu, format, true);
+    }
+
+    private static SmsMessage createFromPdu(byte[] pdu, String format,
+            boolean fallbackToOtherFormat) {
         if (pdu == null) {
             Rlog.i(LOG_TAG, "createFromPdu(): pdu is null");
             return null;
         }
+        SmsMessageBase wrappedMessage;
+        String otherFormat = SmsConstants.FORMAT_3GPP2.equals(format) ? SmsConstants.FORMAT_3GPP :
+                SmsConstants.FORMAT_3GPP2;
         if (SmsConstants.FORMAT_3GPP2.equals(format)) {
             wrappedMessage = com.android.internal.telephony.cdma.SmsMessage.createFromPdu(pdu);
         } else if (SmsConstants.FORMAT_3GPP.equals(format)) {
@@ -228,8 +227,12 @@
         if (wrappedMessage != null) {
             return new SmsMessage(wrappedMessage);
         } else {
-            Rlog.e(LOG_TAG, "createFromPdu(): wrappedMessage is null");
-            return null;
+            if (fallbackToOtherFormat) {
+                return createFromPdu(pdu, otherFormat, false);
+            } else {
+                Rlog.e(LOG_TAG, "createFromPdu(): wrappedMessage is null");
+                return null;
+            }
         }
     }
 
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index dfe36ef..313146d 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -2047,6 +2047,8 @@
             putPhoneIdAndSubIdExtra(intent, phoneId, subIds[0]);
         } else {
             logd("putPhoneIdAndSubIdExtra: no valid subs");
+            intent.putExtra(PhoneConstants.PHONE_KEY, phoneId);
+            intent.putExtra(PhoneConstants.SLOT_KEY, phoneId);
         }
     }
 
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 7395894..f5d452e 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -1326,13 +1326,15 @@
             "android.intent.action.DATA_STALL_DETECTED";
 
     /**
-     * A service action that identifies a {@link android.app.SmsAppService} subclass in the
+     * A service action that identifies
+     * a {@link android.service.carrier.CarrierMessagingClientService} subclass in the
      * AndroidManifest.xml.
      *
-     * <p>See {@link android.app.SmsAppService} for the details.
+     * <p>See {@link android.service.carrier.CarrierMessagingClientService} for the details.
      */
     @SdkConstant(SdkConstantType.SERVICE_ACTION)
-    public static final String ACTION_SMS_APP_SERVICE = "android.telephony.action.SMS_APP_SERVICE";
+    public static final String ACTION_CARRIER_MESSAGING_CLIENT_SERVICE =
+            "android.telephony.action.CARRIER_MESSAGING_CLIENT_SERVICE";
 
     /**
      * An int extra used with {@link #ACTION_DATA_STALL_DETECTED} to indicate the
@@ -4918,12 +4920,13 @@
      *
      * <p>Apps targeting {@link android.os.Build.VERSION_CODES#Q Android Q} or higher will no
      * longer trigger a refresh of the cached CellInfo by invoking this API. Instead, those apps
-     * will receive the latest cached results. Apps targeting
+     * will receive the latest cached results, which may not be current. Apps targeting
      * {@link android.os.Build.VERSION_CODES#Q Android Q} or higher that wish to request updated
      * CellInfo should call
-     * {android.telephony.TelephonyManager#requestCellInfoUpdate requestCellInfoUpdate()} and
-     * listen for responses via {@link android.telephony.PhoneStateListener#onCellInfoChanged
-     * onCellInfoChanged()}.
+     * {@link android.telephony.TelephonyManager#requestCellInfoUpdate requestCellInfoUpdate()};
+     * however, in all cases, updates will be rate-limited and are not guaranteed. To determine the
+     * recency of CellInfo data, callers should check
+     * {@link android.telephony.CellInfo#getTimeStamp CellInfo#getTimeStamp()}.
      *
      * <p>This method returns valid data for devices with
      * {@link android.content.pm.PackageManager#FEATURE_TELEPHONY FEATURE_TELEPHONY}. In cases
diff --git a/telephony/java/android/telephony/ims/Rcs1To1Thread.java b/telephony/java/android/telephony/ims/Rcs1To1Thread.java
index 709b3aa..3255f8d 100644
--- a/telephony/java/android/telephony/ims/Rcs1To1Thread.java
+++ b/telephony/java/android/telephony/ims/Rcs1To1Thread.java
@@ -15,42 +15,72 @@
  */
 package android.telephony.ims;
 
-import android.os.Parcel;
+import android.annotation.NonNull;
+import android.annotation.WorkerThread;
 
 /**
  * Rcs1To1Thread represents a single RCS conversation thread with a total of two
- * {@link RcsParticipant}s.
- * @hide - TODO(sahinc) make this public
+ * {@link RcsParticipant}s. Please see Section 5 (1-to-1 Messaging) - GSMA RCC.71 (RCS Universal
+ * Profile Service Definition Document)
+ *
+ * @hide - TODO: make public
  */
 public class Rcs1To1Thread extends RcsThread {
+    private int mThreadId;
+
+    /**
+     * Public constructor only for RcsMessageStoreController to initialize new threads.
+     *
+     * @hide
+     */
     public Rcs1To1Thread(int threadId) {
         super(threadId);
+        mThreadId = threadId;
     }
 
-    public static final Creator<Rcs1To1Thread> CREATOR = new Creator<Rcs1To1Thread>() {
-        @Override
-        public Rcs1To1Thread createFromParcel(Parcel in) {
-            return new Rcs1To1Thread(in);
-        }
-
-        @Override
-        public Rcs1To1Thread[] newArray(int size) {
-            return new Rcs1To1Thread[size];
-        }
-    };
-
-    protected Rcs1To1Thread(Parcel in) {
-        super(in);
-    }
-
+    /**
+     * @return Returns {@code false} as this is always a 1 to 1 thread.
+     */
     @Override
-    public int describeContents() {
-        return 0;
+    public boolean isGroup() {
+        return false;
     }
 
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeInt(RCS_1_TO_1_TYPE);
-        super.writeToParcel(dest, flags);
+    /**
+     * {@link Rcs1To1Thread}s can fall back to SMS as a back-up protocol. This function returns the
+     * thread id to be used to query {@code content://mms-sms/conversation/#} to get the fallback
+     * thread.
+     *
+     * @return The thread id to be used to query the mms-sms authority
+     * @throws RcsMessageStoreException if the value could not be read from the storage
+     */
+    @WorkerThread
+    public long getFallbackThreadId() throws RcsMessageStoreException {
+        return RcsControllerCall.call(iRcs -> iRcs.get1To1ThreadFallbackThreadId(mThreadId));
+    }
+
+    /**
+     * If the RCS client allows falling back to SMS, it needs to create an MMS-SMS thread in the
+     * SMS/MMS Provider( see {@link android.provider.Telephony.MmsSms#CONTENT_CONVERSATIONS_URI}.
+     * Use this function to link the {@link Rcs1To1Thread} to the MMS-SMS thread. This function
+     * also updates the storage.
+     *
+     * @throws RcsMessageStoreException if the value could not be persisted into storage
+     */
+    @WorkerThread
+    public void setFallbackThreadId(long fallbackThreadId) throws RcsMessageStoreException {
+        RcsControllerCall.callWithNoReturn(
+                iRcs -> iRcs.set1To1ThreadFallbackThreadId(mThreadId, fallbackThreadId));
+    }
+
+    /**
+     * @return Returns the {@link RcsParticipant} that receives the messages sent in this thread.
+     * @throws RcsMessageStoreException if the value could not be read from the storage
+     */
+    @NonNull
+    @WorkerThread
+    public RcsParticipant getRecipient() throws RcsMessageStoreException {
+        return new RcsParticipant(
+                RcsControllerCall.call(iRcs -> iRcs.get1To1ThreadOtherParticipantId(mThreadId)));
     }
 }
diff --git a/telephony/java/android/telephony/ims/RcsControllerCall.java b/telephony/java/android/telephony/ims/RcsControllerCall.java
new file mode 100644
index 0000000..5512c4c
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsControllerCall.java
@@ -0,0 +1,64 @@
+/*
+ * 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.telephony.ims;
+
+import android.content.Context;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.telephony.ims.aidl.IRcs;
+
+/**
+ * A wrapper class around RPC calls that {@link RcsMessageStore} APIs to minimize boilerplate code.
+ *
+ * @hide - not meant for public use
+ */
+class RcsControllerCall {
+    static <R> R call(RcsServiceCall<R> serviceCall) throws RcsMessageStoreException {
+        IRcs iRcs = IRcs.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_RCS_SERVICE));
+        if (iRcs == null) {
+            throw new RcsMessageStoreException("Could not connect to RCS storage service");
+        }
+
+        try {
+            return serviceCall.methodOnIRcs(iRcs);
+        } catch (RemoteException exception) {
+            throw new RcsMessageStoreException(exception.getMessage());
+        }
+    }
+
+    static void callWithNoReturn(RcsServiceCallWithNoReturn serviceCall)
+            throws RcsMessageStoreException {
+        IRcs iRcs = IRcs.Stub.asInterface(ServiceManager.getService(Context.TELEPHONY_RCS_SERVICE));
+        if (iRcs == null) {
+            throw new RcsMessageStoreException("Could not connect to RCS storage service");
+        }
+
+        try {
+            serviceCall.methodOnIRcs(iRcs);
+        } catch (RemoteException exception) {
+            throw new RcsMessageStoreException(exception.getMessage());
+        }
+    }
+
+    interface RcsServiceCall<R> {
+        R methodOnIRcs(IRcs iRcs) throws RemoteException;
+    }
+
+    interface RcsServiceCallWithNoReturn {
+        void methodOnIRcs(IRcs iRcs) throws RemoteException;
+    }
+}
diff --git a/telephony/java/android/telephony/ims/RcsPart.aidl b/telephony/java/android/telephony/ims/RcsEvent.aidl
similarity index 96%
rename from telephony/java/android/telephony/ims/RcsPart.aidl
rename to telephony/java/android/telephony/ims/RcsEvent.aidl
index 8b8077d..08974e0 100644
--- a/telephony/java/android/telephony/ims/RcsPart.aidl
+++ b/telephony/java/android/telephony/ims/RcsEvent.aidl
@@ -17,4 +17,4 @@
 
 package android.telephony.ims;
 
-parcelable RcsPart;
+parcelable RcsEvent;
diff --git a/telephony/java/android/telephony/ims/RcsEvent.java b/telephony/java/android/telephony/ims/RcsEvent.java
new file mode 100644
index 0000000..ef359a1
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsEvent.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2018 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.telephony.ims;
+
+import android.os.Parcel;
+
+/**
+ * The base class for events that can happen on {@link RcsParticipant}s and {@link RcsThread}s.
+ *
+ * @hide - TODO: make public
+ */
+public abstract class RcsEvent {
+    /**
+     * @hide
+     */
+    protected final long mTimestamp;
+
+    protected RcsEvent(long timestamp) {
+        mTimestamp = timestamp;
+    }
+
+    /**
+     * @return Returns the time of when this event happened. The timestamp is defined as
+     * milliseconds passed after midnight, January 1, 1970 UTC
+     */
+    public long getTimestamp() {
+        return mTimestamp;
+    }
+
+    /**
+     * Persists the event to the data store
+     *
+     * @hide
+     */
+    abstract void persist() throws RcsMessageStoreException;
+
+    /**
+     * @hide
+     */
+    RcsEvent(Parcel in) {
+        mTimestamp = in.readLong();
+    }
+
+    /**
+     * @hide
+     */
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeLong(mTimestamp);
+    }
+}
diff --git a/telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl b/telephony/java/android/telephony/ims/RcsEventQueryParams.aidl
similarity index 94%
copy from telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl
copy to telephony/java/android/telephony/ims/RcsEventQueryParams.aidl
index 82d985d..f18c4df 100644
--- a/telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl
+++ b/telephony/java/android/telephony/ims/RcsEventQueryParams.aidl
@@ -17,4 +17,4 @@
 
 package android.telephony.ims;
 
-parcelable RcsThreadIconChangedEvent;
+parcelable RcsEventQueryParams;
diff --git a/telephony/java/android/telephony/ims/RcsEventQueryParams.java b/telephony/java/android/telephony/ims/RcsEventQueryParams.java
new file mode 100644
index 0000000..5249bec
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsEventQueryParams.java
@@ -0,0 +1,321 @@
+/*
+ * 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.telephony.ims;
+
+import static android.provider.Telephony.RcsColumns.RcsEventTypes.ICON_CHANGED_EVENT_TYPE;
+import static android.provider.Telephony.RcsColumns.RcsEventTypes.NAME_CHANGED_EVENT_TYPE;
+import static android.provider.Telephony.RcsColumns.RcsEventTypes.PARTICIPANT_ALIAS_CHANGED_EVENT_TYPE;
+import static android.provider.Telephony.RcsColumns.RcsEventTypes.PARTICIPANT_JOINED_EVENT_TYPE;
+import static android.provider.Telephony.RcsColumns.RcsEventTypes.PARTICIPANT_LEFT_EVENT_TYPE;
+
+import android.annotation.CheckResult;
+import android.annotation.IntDef;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.security.InvalidParameterException;
+
+/**
+ * The parameters to pass into
+ * {@link RcsMessageStore#getRcsEvents(RcsEventQueryParams)} in order to select a
+ * subset of {@link RcsEvent}s present in the message store.
+ *
+ * @hide - TODO: make public
+ */
+public final class RcsEventQueryParams implements Parcelable {
+    /**
+     * Flag to be used with {@link Builder#setEventType(int)} to make
+     * {@link RcsMessageStore#getRcsEvents(RcsEventQueryParams)} return all types of
+     * {@link RcsEvent}s
+     */
+    public static final int ALL_EVENTS = -1;
+
+    /**
+     * Flag to be used with {@link Builder#setEventType(int)} to make
+     * {@link RcsMessageStore#getRcsEvents(RcsEventQueryParams)} return sub-types of
+     * {@link RcsGroupThreadEvent}s
+     */
+    public static final int ALL_GROUP_THREAD_EVENTS = 0;
+
+    /**
+     * Flag to be used with {@link Builder#setEventType(int)} to make
+     * {@link RcsMessageStore#getRcsEvents(RcsEventQueryParams)} return only
+     * {@link RcsParticipantAliasChangedEvent}s
+     */
+    public static final int PARTICIPANT_ALIAS_CHANGED_EVENT =
+            PARTICIPANT_ALIAS_CHANGED_EVENT_TYPE;
+
+    /**
+     * Flag to be used with {@link Builder#setEventType(int)} to make
+     * {@link RcsMessageStore#getRcsEvents(RcsEventQueryParams)} return only
+     * {@link RcsGroupThreadParticipantJoinedEvent}s
+     */
+    public static final int GROUP_THREAD_PARTICIPANT_JOINED_EVENT =
+            PARTICIPANT_JOINED_EVENT_TYPE;
+
+    /**
+     * Flag to be used with {@link Builder#setEventType(int)} to make
+     * {@link RcsMessageStore#getRcsEvents(RcsEventQueryParams)} return only
+     * {@link RcsGroupThreadParticipantLeftEvent}s
+     */
+    public static final int GROUP_THREAD_PARTICIPANT_LEFT_EVENT =
+            PARTICIPANT_LEFT_EVENT_TYPE;
+
+    /**
+     * Flag to be used with {@link Builder#setEventType(int)} to make
+     * {@link RcsMessageStore#getRcsEvents(RcsEventQueryParams)} return only
+     * {@link RcsGroupThreadNameChangedEvent}s
+     */
+    public static final int GROUP_THREAD_NAME_CHANGED_EVENT = NAME_CHANGED_EVENT_TYPE;
+
+    /**
+     * Flag to be used with {@link Builder#setEventType(int)} to make
+     * {@link RcsMessageStore#getRcsEvents(RcsEventQueryParams)} return only
+     * {@link RcsGroupThreadIconChangedEvent}s
+     */
+    public static final int GROUP_THREAD_ICON_CHANGED_EVENT = ICON_CHANGED_EVENT_TYPE;
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({ALL_EVENTS, ALL_GROUP_THREAD_EVENTS, PARTICIPANT_ALIAS_CHANGED_EVENT,
+            GROUP_THREAD_PARTICIPANT_JOINED_EVENT, GROUP_THREAD_PARTICIPANT_LEFT_EVENT,
+            GROUP_THREAD_NAME_CHANGED_EVENT, GROUP_THREAD_ICON_CHANGED_EVENT})
+    public @interface EventType {
+    }
+
+    /**
+     * Flag to be used with {@link Builder#setSortProperty(int)} that makes the result set sorted
+     * in the order of creation for faster query results.
+     */
+    public static final int SORT_BY_CREATION_ORDER = 0;
+
+    /**
+     * Flag to be used with {@link Builder#setSortProperty(int)} that makes the result set sorted
+     * with respect to {@link RcsEvent#getTimestamp()}
+     */
+    public static final int SORT_BY_TIMESTAMP = 1;
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({SORT_BY_CREATION_ORDER, SORT_BY_TIMESTAMP})
+    public @interface SortingProperty {
+    }
+
+    /**
+     * The key to pass into a Bundle, for usage in RcsProvider.query(Bundle)
+     * @hide - not meant for public use
+     */
+    public static final String EVENT_QUERY_PARAMETERS_KEY = "event_query_parameters";
+
+    // Which types of events the results should be limited to
+    private @EventType int mEventType;
+    // The property which the results should be sorted against
+    private int mSortingProperty;
+    // Whether the results should be sorted in ascending order
+    private boolean mIsAscending;
+    // The number of results that should be returned with this query
+    private int mLimit;
+    // The thread that the results are limited to
+    private int mThreadId;
+
+    RcsEventQueryParams(@EventType int eventType, int threadId,
+            @SortingProperty int sortingProperty, boolean isAscending, int limit) {
+        mEventType = eventType;
+        mSortingProperty = sortingProperty;
+        mIsAscending = isAscending;
+        mLimit = limit;
+        mThreadId = threadId;
+    }
+
+    /**
+     * @return Returns the type of {@link RcsEvent}s that this {@link RcsEventQueryParams} is
+     * set to query for.
+     */
+    public @EventType int getEventType() {
+        return mEventType;
+    }
+
+    /**
+     * @return Returns the type of {@link RcsEvent}s that this {@link RcsEventQueryParams} is
+     * set to query for.
+     */
+    public int getLimit() {
+        return mLimit;
+    }
+
+    /**
+     * @return Returns the property where the results should be sorted against.
+     * @see SortingProperty
+     */
+    public int getSortingProperty() {
+        return mSortingProperty;
+    }
+
+    /**
+     * @return Returns {@code true} if the result set will be sorted in ascending order,
+     * {@code false} if it will be sorted in descending order.
+     */
+    public boolean getSortDirection() {
+        return mIsAscending;
+    }
+
+    /**
+     * @return Returns the ID of the {@link RcsGroupThread} that the results are limited to. As this
+     * API exposes an ID, it should stay hidden.
+     *
+     * @hide
+     */
+    public int getThreadId() {
+        return mThreadId;
+    }
+
+    /**
+     * A helper class to build the {@link RcsEventQueryParams}.
+     */
+    public static class Builder {
+        private @EventType int mEventType;
+        private @SortingProperty int mSortingProperty;
+        private boolean mIsAscending;
+        private int mLimit = 100;
+        private int mThreadId;
+
+        /**
+         * Creates a new builder for {@link RcsEventQueryParams} to be used in
+         * {@link RcsMessageStore#getRcsEvents(RcsEventQueryParams)}
+         */
+        public Builder() {
+            // empty implementation
+        }
+
+        /**
+         * Desired number of events to be returned from the query. Passing in 0 will return all
+         * existing events at once. The limit defaults to 100.
+         *
+         * @param limit The number to limit the query result to.
+         * @return The same instance of the builder to chain parameters.
+         * @throws InvalidParameterException If the given limit is negative.
+         */
+        @CheckResult
+        public Builder setResultLimit(@IntRange(from = 0) int limit)
+                throws InvalidParameterException {
+            if (limit < 0) {
+                throw new InvalidParameterException("The query limit must be non-negative");
+            }
+
+            mLimit = limit;
+            return this;
+        }
+
+        /**
+         * Sets the type of events to be returned from the query.
+         *
+         * @param eventType The type of event to be returned.
+         * @return The same instance of the builder to chain parameters.
+         */
+        @CheckResult
+        public Builder setEventType(@EventType int eventType) {
+            mEventType = eventType;
+            return this;
+        }
+
+        /**
+         * Sets the property where the results should be sorted against. Defaults to
+         * {@link RcsEventQueryParams.SortingProperty#SORT_BY_CREATION_ORDER}
+         *
+         * @param sortingProperty against which property the results should be sorted
+         * @return The same instance of the builder to chain parameters.
+         */
+        @CheckResult
+        public Builder setSortProperty(@SortingProperty int sortingProperty) {
+            mSortingProperty = sortingProperty;
+            return this;
+        }
+
+        /**
+         * Sets whether the results should be sorted ascending or descending
+         *
+         * @param isAscending whether the results should be sorted ascending
+         * @return The same instance of the builder to chain parameters.
+         */
+        @CheckResult
+        public Builder setSortDirection(boolean isAscending) {
+            mIsAscending = isAscending;
+            return this;
+        }
+
+        /**
+         * Limits the results to the given {@link RcsGroupThread}. Setting this value prevents
+         * returning any instances of {@link RcsParticipantAliasChangedEvent}.
+         *
+         * @param groupThread The thread to limit the results to.
+         * @return The same instance of the builder to chain parameters.
+         */
+        @CheckResult
+        public Builder setGroupThread(@NonNull RcsGroupThread groupThread) {
+            mThreadId = groupThread.getThreadId();
+            return this;
+        }
+
+        /**
+         * Builds the {@link RcsEventQueryParams} to use in
+         * {@link RcsMessageStore#getRcsEvents(RcsEventQueryParams)}
+         *
+         * @return An instance of {@link RcsEventQueryParams} to use with the event query.
+         */
+        public RcsEventQueryParams build() {
+            return new RcsEventQueryParams(mEventType, mThreadId, mSortingProperty,
+                    mIsAscending, mLimit);
+        }
+    }
+
+    private RcsEventQueryParams(Parcel in) {
+        mEventType = in.readInt();
+        mThreadId = in.readInt();
+        mSortingProperty = in.readInt();
+        mIsAscending = in.readBoolean();
+        mLimit = in.readInt();
+    }
+
+    public static final Creator<RcsEventQueryParams> CREATOR =
+            new Creator<RcsEventQueryParams>() {
+                @Override
+                public RcsEventQueryParams createFromParcel(Parcel in) {
+                    return new RcsEventQueryParams(in);
+                }
+
+                @Override
+                public RcsEventQueryParams[] newArray(int size) {
+                    return new RcsEventQueryParams[size];
+                }
+            };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mEventType);
+        dest.writeInt(mThreadId);
+        dest.writeInt(mSortingProperty);
+        dest.writeBoolean(mIsAscending);
+        dest.writeInt(mLimit);
+    }
+}
diff --git a/telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl b/telephony/java/android/telephony/ims/RcsEventQueryResult.aidl
similarity index 94%
copy from telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl
copy to telephony/java/android/telephony/ims/RcsEventQueryResult.aidl
index 82d985d..7d13335 100644
--- a/telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl
+++ b/telephony/java/android/telephony/ims/RcsEventQueryResult.aidl
@@ -17,4 +17,4 @@
 
 package android.telephony.ims;
 
-parcelable RcsThreadIconChangedEvent;
+parcelable RcsEventQueryResult;
diff --git a/telephony/java/android/telephony/ims/RcsEventQueryResult.java b/telephony/java/android/telephony/ims/RcsEventQueryResult.java
new file mode 100644
index 0000000..f8d57fa
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsEventQueryResult.java
@@ -0,0 +1,91 @@
+/*
+ * 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.telephony.ims;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.List;
+
+/**
+ * The result of a {@link RcsMessageStore#getRcsEvents(RcsEventQueryParams)}
+ * call. This class allows getting the token for querying the next batch of events in order to
+ * prevent handling large amounts of data at once.
+ *
+ * @hide - TODO: make public
+ */
+public final class RcsEventQueryResult implements Parcelable {
+    private RcsQueryContinuationToken mContinuationToken;
+    private List<RcsEvent> mEvents;
+
+    /**
+     * Internal constructor for {@link com.android.internal.telephony.ims.RcsMessageStoreController}
+     * to create query results
+     *
+     * @hide
+     */
+    public RcsEventQueryResult(
+            RcsQueryContinuationToken continuationToken,
+            List<RcsEvent> events) {
+        mContinuationToken = continuationToken;
+        mEvents = events;
+    }
+
+    /**
+     * Returns a token to call
+     * {@link RcsMessageStore#getRcsEvents(RcsQueryContinuationToken)}
+     * to get the next batch of {@link RcsEvent}s.
+     */
+    public RcsQueryContinuationToken getContinuationToken() {
+        return mContinuationToken;
+    }
+
+    /**
+     * Returns all the {@link RcsEvent}s in the current query result. Call {@link
+     * RcsMessageStore#getRcsEvents(RcsQueryContinuationToken)} to get the next batch
+     * of {@link RcsEvent}s.
+     */
+    public List<RcsEvent> getEvents() {
+        return mEvents;
+    }
+
+    private RcsEventQueryResult(Parcel in) {
+        mContinuationToken = in.readParcelable(RcsQueryContinuationToken.class.getClassLoader());
+    }
+
+    public static final Creator<RcsEventQueryResult> CREATOR = new Creator<RcsEventQueryResult>() {
+        @Override
+        public RcsEventQueryResult createFromParcel(Parcel in) {
+            return new RcsEventQueryResult(in);
+        }
+
+        @Override
+        public RcsEventQueryResult[] newArray(int size) {
+            return new RcsEventQueryResult[size];
+        }
+    };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeParcelable(mContinuationToken, flags);
+    }
+}
diff --git a/telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl b/telephony/java/android/telephony/ims/RcsFileTransferCreationParams.aidl
similarity index 93%
copy from telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl
copy to telephony/java/android/telephony/ims/RcsFileTransferCreationParams.aidl
index 82d985d..1552190 100644
--- a/telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl
+++ b/telephony/java/android/telephony/ims/RcsFileTransferCreationParams.aidl
@@ -17,4 +17,4 @@
 
 package android.telephony.ims;
 
-parcelable RcsThreadIconChangedEvent;
+parcelable RcsFileTransferCreationParams;
diff --git a/telephony/java/android/telephony/ims/RcsFileTransferCreationParams.java b/telephony/java/android/telephony/ims/RcsFileTransferCreationParams.java
new file mode 100644
index 0000000..663def5
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsFileTransferCreationParams.java
@@ -0,0 +1,360 @@
+/*
+ * 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.telephony.ims;
+
+import android.annotation.CheckResult;
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * Pass an instance of this class to
+ * {@link RcsMessage#insertFileTransfer(RcsFileTransferCreationParams)} create an
+ * {@link RcsFileTransferPart} and save it into storage.
+ *
+ * @hide - TODO: make public
+ */
+public final class RcsFileTransferCreationParams implements Parcelable {
+    private String mRcsFileTransferSessionId;
+    private Uri mContentUri;
+    private String mContentMimeType;
+    private long mFileSize;
+    private long mTransferOffset;
+    private int mWidth;
+    private int mHeight;
+    private long mMediaDuration;
+    private Uri mPreviewUri;
+    private String mPreviewMimeType;
+    private @RcsFileTransferPart.RcsFileTransferStatus int mFileTransferStatus;
+
+    /**
+     * @return Returns the globally unique RCS file transfer session ID for the
+     * {@link RcsFileTransferPart} to be created
+     */
+    public String getRcsFileTransferSessionId() {
+        return mRcsFileTransferSessionId;
+    }
+
+    /**
+     * @return Returns the URI for the content of the {@link RcsFileTransferPart} to be created
+     */
+    public Uri getContentUri() {
+        return mContentUri;
+    }
+
+    /**
+     * @return Returns the MIME type for the content of the {@link RcsFileTransferPart} to be
+     * created
+     */
+    public String getContentMimeType() {
+        return mContentMimeType;
+    }
+
+    /**
+     * @return Returns the file size in bytes for the {@link RcsFileTransferPart} to be created
+     */
+    public long getFileSize() {
+        return mFileSize;
+    }
+
+    /**
+     * @return Returns the transfer offset for the {@link RcsFileTransferPart} to be created. The
+     * file transfer offset is defined as how many bytes have been successfully transferred to the
+     * receiver of this file transfer.
+     */
+    public long getTransferOffset() {
+        return mTransferOffset;
+    }
+
+    /**
+     * @return Returns the width of the {@link RcsFileTransferPart} to be created. The value is in
+     * pixels.
+     */
+    public int getWidth() {
+        return mWidth;
+    }
+
+    /**
+     * @return Returns the height of the {@link RcsFileTransferPart} to be created. The value is in
+     * pixels.
+     */
+    public int getHeight() {
+        return mHeight;
+    }
+
+    /**
+     * @return Returns the duration of the {@link RcsFileTransferPart} to be created.
+     */
+    public long getMediaDuration() {
+        return mMediaDuration;
+    }
+
+    /**
+     * @return Returns the URI of the preview of the content of the {@link RcsFileTransferPart} to
+     * be created. This should only be used for multi-media files.
+     */
+    public Uri getPreviewUri() {
+        return mPreviewUri;
+    }
+
+    /**
+     * @return Returns the MIME type of the preview of the content of the
+     * {@link RcsFileTransferPart} to be created. This should only be used for multi-media files.
+     */
+    public String getPreviewMimeType() {
+        return mPreviewMimeType;
+    }
+
+    /**
+     * @return Returns the status of the {@link RcsFileTransferPart} to be created.
+     */
+    public @RcsFileTransferPart.RcsFileTransferStatus int getFileTransferStatus() {
+        return mFileTransferStatus;
+    }
+
+    /**
+     * @hide
+     */
+    RcsFileTransferCreationParams(Builder builder) {
+        mRcsFileTransferSessionId = builder.mRcsFileTransferSessionId;
+        mContentUri = builder.mContentUri;
+        mContentMimeType = builder.mContentMimeType;
+        mFileSize = builder.mFileSize;
+        mTransferOffset = builder.mTransferOffset;
+        mWidth = builder.mWidth;
+        mHeight = builder.mHeight;
+        mMediaDuration = builder.mLength;
+        mPreviewUri = builder.mPreviewUri;
+        mPreviewMimeType = builder.mPreviewMimeType;
+        mFileTransferStatus = builder.mFileTransferStatus;
+    }
+
+    /**
+     * A builder to create instances of {@link RcsFileTransferCreationParams}
+     */
+    public class Builder {
+        private String mRcsFileTransferSessionId;
+        private Uri mContentUri;
+        private String mContentMimeType;
+        private long mFileSize;
+        private long mTransferOffset;
+        private int mWidth;
+        private int mHeight;
+        private long mLength;
+        private Uri mPreviewUri;
+        private String mPreviewMimeType;
+        private @RcsFileTransferPart.RcsFileTransferStatus int mFileTransferStatus;
+
+        /**
+         * Sets the globally unique RCS file transfer session ID for the {@link RcsFileTransferPart}
+         * to be created
+         *
+         * @param sessionId The RCS file transfer session ID
+         * @return The same instance of {@link Builder} to chain methods
+         */
+        @CheckResult
+        public Builder setFileTransferSessionId(String sessionId) {
+            mRcsFileTransferSessionId = sessionId;
+            return this;
+        }
+
+        /**
+         * Sets the URI for the content of the {@link RcsFileTransferPart} to be created
+         *
+         * @param contentUri The URI for the file
+         * @return The same instance of {@link Builder} to chain methods
+         */
+        @CheckResult
+        public Builder setContentUri(Uri contentUri) {
+            mContentUri = contentUri;
+            return this;
+        }
+
+        /**
+         * Sets the MIME type for the content of the {@link RcsFileTransferPart} to be created
+         *
+         * @param contentType The MIME type of the file
+         * @return The same instance of {@link Builder} to chain methods
+         */
+        @CheckResult
+        public Builder setContentMimeType(String contentType) {
+            mContentMimeType = contentType;
+            return this;
+        }
+
+        /**
+         * Sets the file size for the {@link RcsFileTransferPart} to be created
+         *
+         * @param size The size of the file in bytes
+         * @return The same instance of {@link Builder} to chain methods
+         */
+        @CheckResult
+        public Builder setFileSize(long size) {
+            mFileSize = size;
+            return this;
+        }
+
+        /**
+         * Sets the transfer offset for the {@link RcsFileTransferPart} to be created. The file
+         * transfer offset is defined as how many bytes have been successfully transferred to the
+         * receiver of this file transfer.
+         *
+         * @param offset The transfer offset in bytes
+         * @return The same instance of {@link Builder} to chain methods
+         */
+        @CheckResult
+        public Builder setTransferOffset(long offset) {
+            mTransferOffset = offset;
+            return this;
+        }
+
+        /**
+         * Sets the width of the {@link RcsFileTransferPart} to be created. This should only be used
+         * for multi-media files.
+         *
+         * @param width The width of the multi-media file in pixels.
+         * @return The same instance of {@link Builder} to chain methods
+         */
+        @CheckResult
+        public Builder setWidth(int width) {
+            mWidth = width;
+            return this;
+        }
+
+        /**
+         * Sets the height of the {@link RcsFileTransferPart} to be created. This should only be
+         * used for multi-media files.
+         *
+         * @param height The height of the multi-media file in pixels.
+         * @return The same instance of {@link Builder} to chain methods
+         */
+        @CheckResult
+        public Builder setHeight(int height) {
+            mHeight = height;
+            return this;
+        }
+
+        /**
+         * Sets the length of the {@link RcsFileTransferPart} to be created. This should only be
+         * used for multi-media files such as audio or video.
+         *
+         * @param length The length of the multi-media file in milliseconds
+         * @return The same instance of {@link Builder} to chain methods
+         */
+        @CheckResult
+        public Builder setMediaDuration(long length) {
+            mLength = length;
+            return this;
+        }
+
+        /**
+         * Sets the URI of the preview of the content of the {@link RcsFileTransferPart} to be
+         * created. This should only be used for multi-media files.
+         *
+         * @param previewUri The URI of the preview of the file transfer
+         * @return The same instance of {@link Builder} to chain methods
+         */
+        @CheckResult
+        public Builder setPreviewUri(Uri previewUri) {
+            mPreviewUri = previewUri;
+            return this;
+        }
+
+        /**
+         * Sets the MIME type of the preview of the content of the {@link RcsFileTransferPart} to
+         * be created. This should only be used for multi-media files.
+         *
+         * @param previewType The MIME type of the preview of the file transfer
+         * @return The same instance of {@link Builder} to chain methods
+         */
+        @CheckResult
+        public Builder setPreviewMimeType(String previewType) {
+            mPreviewMimeType = previewType;
+            return this;
+        }
+
+        /**
+         * Sets the status of the {@link RcsFileTransferPart} to be created.
+         *
+         * @param status The status of the file transfer
+         * @return The same instance of {@link Builder} to chain methods
+         */
+        @CheckResult
+        public Builder setFileTransferStatus(
+                @RcsFileTransferPart.RcsFileTransferStatus int status) {
+            mFileTransferStatus = status;
+            return this;
+        }
+
+        /**
+         * Creates an instance of {@link RcsFileTransferCreationParams} with the given
+         * parameters.
+         *
+         * @return The same instance of {@link Builder} to chain methods
+         * @see RcsMessage#insertFileTransfer(RcsFileTransferCreationParams)
+         */
+        public RcsFileTransferCreationParams build() {
+            return new RcsFileTransferCreationParams(this);
+        }
+    }
+
+    private RcsFileTransferCreationParams(Parcel in) {
+        mRcsFileTransferSessionId = in.readString();
+        mContentUri = in.readParcelable(Uri.class.getClassLoader());
+        mContentMimeType = in.readString();
+        mFileSize = in.readLong();
+        mTransferOffset = in.readLong();
+        mWidth = in.readInt();
+        mHeight = in.readInt();
+        mMediaDuration = in.readLong();
+        mPreviewUri = in.readParcelable(Uri.class.getClassLoader());
+        mPreviewMimeType = in.readString();
+        mFileTransferStatus = in.readInt();
+    }
+
+    public static final Creator<RcsFileTransferCreationParams> CREATOR =
+            new Creator<RcsFileTransferCreationParams>() {
+                @Override
+                public RcsFileTransferCreationParams createFromParcel(Parcel in) {
+                    return new RcsFileTransferCreationParams(in);
+                }
+
+                @Override
+                public RcsFileTransferCreationParams[] newArray(int size) {
+                    return new RcsFileTransferCreationParams[size];
+                }
+            };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(mRcsFileTransferSessionId);
+        dest.writeParcelable(mContentUri, flags);
+        dest.writeString(mContentMimeType);
+        dest.writeLong(mFileSize);
+        dest.writeLong(mTransferOffset);
+        dest.writeInt(mWidth);
+        dest.writeInt(mHeight);
+        dest.writeLong(mMediaDuration);
+        dest.writeParcelable(mPreviewUri, flags);
+        dest.writeString(mPreviewMimeType);
+        dest.writeInt(mFileTransferStatus);
+    }
+}
diff --git a/telephony/java/android/telephony/ims/RcsFileTransferPart.aidl b/telephony/java/android/telephony/ims/RcsFileTransferPart.aidl
deleted file mode 100644
index eaf3128..0000000
--- a/telephony/java/android/telephony/ims/RcsFileTransferPart.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- *
- * Copyright 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.telephony.ims;
-
-parcelable RcsFileTransferPart;
diff --git a/telephony/java/android/telephony/ims/RcsFileTransferPart.java b/telephony/java/android/telephony/ims/RcsFileTransferPart.java
index 39c58dd..1ce7999 100644
--- a/telephony/java/android/telephony/ims/RcsFileTransferPart.java
+++ b/telephony/java/android/telephony/ims/RcsFileTransferPart.java
@@ -15,34 +15,346 @@
  */
 package android.telephony.ims;
 
-import android.os.Parcel;
+import android.annotation.IntDef;
+import android.annotation.Nullable;
+import android.annotation.WorkerThread;
+import android.net.Uri;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 
 /**
- * A part of a composite {@link RcsMessage} that holds a file transfer.
- * @hide - TODO(sahinc) make this public
+ * A part of a composite {@link RcsMessage} that holds a file transfer. Please see Section 7
+ * (File Transfer) - GSMA RCC.71 (RCS Universal Profile Service Definition Document)
+ *
+ * @hide - TODO: make public
  */
-public class RcsFileTransferPart extends RcsPart {
-    public static final Creator<RcsFileTransferPart> CREATOR = new Creator<RcsFileTransferPart>() {
-        @Override
-        public RcsFileTransferPart createFromParcel(Parcel in) {
-            return new RcsFileTransferPart(in);
-        }
+public class RcsFileTransferPart {
+    /**
+     * The status to indicate that this {@link RcsFileTransferPart} is not set yet.
+     */
+    public static final int NOT_SET = 0;
 
-        @Override
-        public RcsFileTransferPart[] newArray(int size) {
-            return new RcsFileTransferPart[size];
-        }
-    };
+    /**
+     * The status to indicate that this {@link RcsFileTransferPart} is a draft and is not in the
+     * process of sending yet.
+     */
+    public static final int DRAFT = 1;
 
-    protected RcsFileTransferPart(Parcel in) {
+    /**
+     * The status to indicate that this {@link RcsFileTransferPart} is actively being sent right
+     * now.
+     */
+    public static final int SENDING = 2;
+
+    /**
+     * The status to indicate that this {@link RcsFileTransferPart} was being sent, but the user has
+     * paused the sending process.
+     */
+    public static final int SENDING_PAUSED = 3;
+
+    /**
+     * The status to indicate that this {@link RcsFileTransferPart} was attempted, but failed to
+     * send.
+     */
+    public static final int SENDING_FAILED = 4;
+
+    /**
+     * The status to indicate that this {@link RcsFileTransferPart} is permanently cancelled to
+     * send.
+     */
+    public static final int SENDING_CANCELLED = 5;
+
+    /**
+     * The status to indicate that this {@link RcsFileTransferPart} is actively being downloaded
+     * right now.
+     */
+    public static final int DOWNLOADING = 6;
+
+    /**
+     * The status to indicate that this {@link RcsFileTransferPart} was being downloaded, but the
+     * user paused the downloading process.
+     */
+    public static final int DOWNLOADING_PAUSED = 7;
+
+    /**
+     * The status to indicate that this {@link RcsFileTransferPart} was attempted, but failed to
+     * download.
+     */
+    public static final int DOWNLOADING_FAILED = 8;
+
+    /**
+     * The status to indicate that this {@link RcsFileTransferPart} is permanently cancelled to
+     * download.
+     */
+    public static final int DOWNLOADING_CANCELLED = 9;
+
+    /**
+     * The status to indicate that this {@link RcsFileTransferPart} was successfully sent or
+     * received.
+     */
+    public static final int SUCCEEDED = 10;
+
+    @IntDef({
+            DRAFT, SENDING, SENDING_PAUSED, SENDING_FAILED, SENDING_CANCELLED, DOWNLOADING,
+            DOWNLOADING_PAUSED, DOWNLOADING_FAILED, DOWNLOADING_CANCELLED, SUCCEEDED
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface RcsFileTransferStatus {
     }
 
-    @Override
-    public int describeContents() {
-        return 0;
+    private int mId;
+
+    /**
+     * @hide
+     */
+    RcsFileTransferPart(int id) {
+        mId = id;
     }
 
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
+    /**
+     * @hide
+     */
+    public void setId(int id) {
+        mId = id;
+    }
+
+    /**
+     * @hide
+     */
+    public int getId() {
+        return mId;
+    }
+
+    /**
+     * Sets the RCS file transfer session ID for this file transfer and persists into storage.
+     *
+     * @param sessionId The session ID to be used for this file transfer.
+     * @throws RcsMessageStoreException if the value could not be persisted into storage
+     */
+    @WorkerThread
+    public void setFileTransferSessionId(String sessionId) throws RcsMessageStoreException {
+        RcsControllerCall.callWithNoReturn(iRcs -> iRcs.setFileTransferSessionId(mId, sessionId));
+    }
+
+    /**
+     * @return Returns the file transfer session ID.
+     * @throws RcsMessageStoreException if the value could not be read from the storage
+     */
+    @WorkerThread
+    public String getFileTransferSessionId() throws RcsMessageStoreException {
+        return RcsControllerCall.call(iRcs -> iRcs.getFileTransferSessionId(mId));
+    }
+
+    /**
+     * Sets the content URI for this file transfer and persists into storage. The file transfer
+     * should be reachable using this URI.
+     *
+     * @param contentUri The URI for this file transfer.
+     * @throws RcsMessageStoreException if the value could not be persisted into storage
+     */
+    @WorkerThread
+    public void setContentUri(Uri contentUri) throws RcsMessageStoreException {
+        RcsControllerCall.callWithNoReturn(iRcs -> iRcs.setFileTransferContentUri(mId, contentUri));
+    }
+
+    /**
+     * @return Returns the URI for this file transfer
+     * @throws RcsMessageStoreException if the value could not be read from the storage
+     */
+    @Nullable
+    @WorkerThread
+    public Uri getContentUri() throws RcsMessageStoreException {
+        return RcsControllerCall.call(iRcs -> iRcs.getFileTransferContentUri(mId));
+    }
+
+    /**
+     * Sets the MIME type of this file transfer and persists into storage. Whether this type
+     * actually matches any known or supported types is not checked.
+     *
+     * @param contentMimeType The type of this file transfer.
+     * @throws RcsMessageStoreException if the value could not be persisted into storage
+     */
+    @WorkerThread
+    public void setContentMimeType(String contentMimeType) throws RcsMessageStoreException {
+        RcsControllerCall.callWithNoReturn(
+                iRcs -> iRcs.setFileTransferContentType(mId, contentMimeType));
+    }
+
+    /**
+     * @return Returns the content type of this file transfer
+     * @throws RcsMessageStoreException if the value could not be read from the storage
+     */
+    @WorkerThread
+    @Nullable
+    public String getContentMimeType() throws RcsMessageStoreException {
+        return RcsControllerCall.call(iRcs -> iRcs.getFileTransferContentType(mId));
+    }
+
+    /**
+     * Sets the content length (i.e. file size) for this file transfer and persists into storage.
+     *
+     * @param contentLength The content length of this file transfer
+     * @throws RcsMessageStoreException if the value could not be persisted into storage
+     */
+    @WorkerThread
+    public void setFileSize(long contentLength) throws RcsMessageStoreException {
+        RcsControllerCall.callWithNoReturn(
+                iRcs -> iRcs.setFileTransferFileSize(mId, contentLength));
+    }
+
+    /**
+     * @return Returns the content length (i.e. file size) for this file transfer.
+     * @throws RcsMessageStoreException if the value could not be read from the storage
+     */
+    @WorkerThread
+    public long getFileSize() throws RcsMessageStoreException {
+        return RcsControllerCall.call(iRcs -> iRcs.getFileTransferFileSize(mId));
+    }
+
+    /**
+     * Sets the transfer offset for this file transfer and persists into storage. The file transfer
+     * offset is defined as how many bytes have been successfully transferred to the receiver of
+     * this file transfer.
+     *
+     * @param transferOffset The transfer offset for this file transfer.
+     * @throws RcsMessageStoreException if the value could not be persisted into storage
+     */
+    @WorkerThread
+    public void setTransferOffset(long transferOffset) throws RcsMessageStoreException {
+        RcsControllerCall.callWithNoReturn(
+                iRcs -> iRcs.setFileTransferTransferOffset(mId, transferOffset));
+    }
+
+    /**
+     * @return Returns the number of bytes that have successfully transferred.
+     * @throws RcsMessageStoreException if the value could not be read from the storage
+     */
+    @WorkerThread
+    public long getTransferOffset() throws RcsMessageStoreException {
+        return RcsControllerCall.call(iRcs -> iRcs.getFileTransferTransferOffset(mId));
+    }
+
+    /**
+     * Sets the status for this file transfer and persists into storage.
+     *
+     * @param status The status of this file transfer.
+     * @throws RcsMessageStoreException if the value could not be persisted into storage
+     */
+    @WorkerThread
+    public void setFileTransferStatus(@RcsFileTransferStatus int status)
+            throws RcsMessageStoreException {
+        RcsControllerCall.callWithNoReturn(iRcs -> iRcs.setFileTransferStatus(mId, status));
+    }
+
+    /**
+     * @return Returns the status of this file transfer.
+     * @throws RcsMessageStoreException if the value could not be read from the storage
+     */
+    @WorkerThread
+    public @RcsFileTransferStatus int getFileTransferStatus() throws RcsMessageStoreException {
+        return RcsControllerCall.call(iRcs -> iRcs.getFileTransferStatus(mId));
+    }
+
+    /**
+     * @return Returns the width of this multi-media message part in pixels.
+     * @throws RcsMessageStoreException if the value could not be read from the storage
+     */
+    @WorkerThread
+    public int getWidth() throws RcsMessageStoreException {
+        return RcsControllerCall.call(iRcs -> iRcs.getFileTransferWidth(mId));
+    }
+
+    /**
+     * Sets the width of this RCS multi-media message part and persists into storage.
+     *
+     * @param width The width value in pixels
+     * @throws RcsMessageStoreException if the value could not be persisted into storage
+     */
+    @WorkerThread
+    public void setWidth(int width) throws RcsMessageStoreException {
+        RcsControllerCall.callWithNoReturn(iRcs -> iRcs.setFileTransferWidth(mId, width));
+    }
+
+    /**
+     * @return Returns the height of this multi-media message part in pixels.
+     * @throws RcsMessageStoreException if the value could not be read from the storage
+     */
+    @WorkerThread
+    public int getHeight() throws RcsMessageStoreException {
+        return RcsControllerCall.call(iRcs -> iRcs.getFileTransferHeight(mId));
+    }
+
+    /**
+     * Sets the height of this RCS multi-media message part and persists into storage.
+     *
+     * @param height The height value in pixels
+     * @throws RcsMessageStoreException if the value could not be persisted into storage
+     */
+    @WorkerThread
+    public void setHeight(int height) throws RcsMessageStoreException {
+        RcsControllerCall.callWithNoReturn(iRcs -> iRcs.setFileTransferHeight(mId, height));
+    }
+
+    /**
+     * @return Returns the length of this multi-media file (e.g. video or audio) in milliseconds.
+     * @throws RcsMessageStoreException if the value could not be read from the storage
+     */
+    @WorkerThread
+    public long getLength() throws RcsMessageStoreException {
+        return RcsControllerCall.call(iRcs -> iRcs.getFileTransferLength(mId));
+    }
+
+    /**
+     * Sets the length of this multi-media file (e.g. video or audio) and persists into storage.
+     *
+     * @param length The length of the file in milliseconds.
+     * @throws RcsMessageStoreException if the value could not be persisted into storage
+     */
+    @WorkerThread
+    public void setLength(long length) throws RcsMessageStoreException {
+        RcsControllerCall.callWithNoReturn(iRcs -> iRcs.setFileTransferLength(mId, length));
+    }
+
+    /**
+     * @return Returns the URI for the preview of this multi-media file (e.g. an image thumbnail for
+     * a video)
+     * @throws RcsMessageStoreException if the value could not be read from the storage
+     */
+    @WorkerThread
+    public Uri getPreviewUri() throws RcsMessageStoreException {
+        return RcsControllerCall.call(iRcs -> iRcs.getFileTransferPreviewUri(mId));
+    }
+
+    /**
+     * Sets the URI for the preview of this multi-media file and persists into storage.
+     *
+     * @param previewUri The URI to access to the preview file.
+     * @throws RcsMessageStoreException if the value could not be persisted into storage
+     */
+    @WorkerThread
+    public void setPreviewUri(Uri previewUri) throws RcsMessageStoreException {
+        RcsControllerCall.callWithNoReturn(iRcs -> iRcs.setFileTransferPreviewUri(mId, previewUri));
+    }
+
+    /**
+     * @return Returns the MIME type of this multi-media file's preview.
+     * @throws RcsMessageStoreException if the value could not be read from the storage
+     */
+    @WorkerThread
+    public String getPreviewMimeType() throws RcsMessageStoreException {
+        return RcsControllerCall.call(iRcs -> iRcs.getFileTransferPreviewType(mId));
+    }
+
+    /**
+     * Sets the MIME type for this multi-media file's preview and persists into storage.
+     *
+     * @param previewMimeType The MIME type for the preview
+     * @throws RcsMessageStoreException if the value could not be persisted into storage
+     */
+    @WorkerThread
+    public void setPreviewMimeType(String previewMimeType) throws RcsMessageStoreException {
+        RcsControllerCall.callWithNoReturn(
+                iRcs -> iRcs.setFileTransferPreviewType(mId, previewMimeType));
     }
 }
diff --git a/telephony/java/android/telephony/ims/RcsGroupThread.aidl b/telephony/java/android/telephony/ims/RcsGroupThread.aidl
deleted file mode 100644
index c4ce529..0000000
--- a/telephony/java/android/telephony/ims/RcsGroupThread.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- *
- * Copyright 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.telephony.ims;
-
-parcelable RcsGroupThread;
diff --git a/telephony/java/android/telephony/ims/RcsGroupThread.java b/telephony/java/android/telephony/ims/RcsGroupThread.java
index d954b2d..2c42494 100644
--- a/telephony/java/android/telephony/ims/RcsGroupThread.java
+++ b/telephony/java/android/telephony/ims/RcsGroupThread.java
@@ -15,38 +15,191 @@
  */
 package android.telephony.ims;
 
-import android.os.Parcel;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.WorkerThread;
+import android.net.Uri;
+
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
 
 /**
  * RcsGroupThread represents a single RCS conversation thread where {@link RcsParticipant}s can join
- * or leave.
- * @hide - TODO(sahinc) make this public
+ * or leave. Please see Section 6 (Group Chat) - GSMA RCC.71 (RCS Universal Profile Service
+ * Definition Document)
+ *
+ * @hide - TODO: make public
  */
 public class RcsGroupThread extends RcsThread {
-    public static final Creator<RcsGroupThread> CREATOR = new Creator<RcsGroupThread>() {
-        @Override
-        public RcsGroupThread createFromParcel(Parcel in) {
-            return new RcsGroupThread(in);
-        }
-
-        @Override
-        public RcsGroupThread[] newArray(int size) {
-            return new RcsGroupThread[size];
-        }
-    };
-
-    protected RcsGroupThread(Parcel in) {
-        super(in);
+    /**
+     * Public constructor only for RcsMessageStoreController to initialize new threads.
+     *
+     * @hide
+     */
+    public RcsGroupThread(int threadId) {
+        super(threadId);
     }
 
+    /**
+     * @return Returns {@code true} as this is always a group thread
+     */
     @Override
-    public int describeContents() {
-        return 0;
+    public boolean isGroup() {
+        return true;
     }
 
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeInt(RCS_GROUP_TYPE);
-        super.writeToParcel(dest, flags);
+    /**
+     * @return Returns the given name of this {@link RcsGroupThread}. Please see US6-2 - GSMA RCC.71
+     * (RCS Universal Profile Service Definition Document)
+     * @throws RcsMessageStoreException if the value could not be read from the storage
+     */
+    @Nullable
+    @WorkerThread
+    public String getGroupName() throws RcsMessageStoreException {
+        return RcsControllerCall.call(iRcs -> iRcs.getGroupThreadName(mThreadId));
+    }
+
+    /**
+     * Sets the name of this {@link RcsGroupThread} and saves it into storage. Please see US6-2 -
+     * GSMA RCC.71 (RCS Universal Profile Service Definition Document)
+     *
+     * @throws RcsMessageStoreException if the value could not be persisted into storage
+     */
+    @WorkerThread
+    public void setGroupName(String groupName) throws RcsMessageStoreException {
+        RcsControllerCall.callWithNoReturn(iRcs -> iRcs.setGroupThreadName(mThreadId, groupName));
+    }
+
+    /**
+     * @return Returns a URI that points to the group's icon {@link RcsGroupThread}. Please see
+     * US6-2 - GSMA RCC.71 (RCS Universal Profile Service Definition Document)
+     * @throws RcsMessageStoreException if the value could not be read from the storage
+     */
+    @Nullable
+    public Uri getGroupIcon() throws RcsMessageStoreException {
+        return RcsControllerCall.call(iRcs -> iRcs.getGroupThreadIcon(mThreadId));
+    }
+
+    /**
+     * Sets the icon for this {@link RcsGroupThread} and saves it into storage. Please see US6-2 -
+     * GSMA RCC.71 (RCS Universal Profile Service Definition Document)
+     *
+     * @throws RcsMessageStoreException if the value could not be persisted into storage
+     */
+    @WorkerThread
+    public void setGroupIcon(@Nullable Uri groupIcon) throws RcsMessageStoreException {
+        RcsControllerCall.callWithNoReturn(iRcs -> iRcs.setGroupThreadIcon(mThreadId, groupIcon));
+    }
+
+    /**
+     * @return Returns the owner of this thread or {@code null} if there doesn't exist an owner
+     * @throws RcsMessageStoreException if the value could not be read from the storage
+     */
+    @Nullable
+    @WorkerThread
+    public RcsParticipant getOwner() throws RcsMessageStoreException {
+        return new RcsParticipant(RcsControllerCall.call(
+                iRcs -> iRcs.getGroupThreadOwner(mThreadId)));
+    }
+
+    /**
+     * Sets the owner of this {@link RcsGroupThread} and saves it into storage. This is intended to
+     * be used for selecting a new owner for a group thread if the owner leaves the thread. The
+     * owner needs to be in the list of existing participants.
+     *
+     * @param participant The new owner of the thread. {@code null} values are allowed.
+     * @throws RcsMessageStoreException if the operation could not be persisted into storage
+     */
+    @WorkerThread
+    public void setOwner(@Nullable RcsParticipant participant) throws RcsMessageStoreException {
+        RcsControllerCall.callWithNoReturn(
+                iRcs -> iRcs.setGroupThreadOwner(mThreadId, participant.getId()));
+    }
+
+    /**
+     * Adds a new {@link RcsParticipant} to this group thread and persists into storage. If the user
+     * is actively participating in this {@link RcsGroupThread}, an {@link RcsParticipant} on behalf
+     * of them should be added.
+     *
+     * @param participant The new participant to be added to the thread.
+     * @throws RcsMessageStoreException if the operation could not be persisted into storage
+     */
+    @WorkerThread
+    public void addParticipant(@NonNull RcsParticipant participant)
+            throws RcsMessageStoreException {
+        if (participant == null) {
+            return;
+        }
+
+        RcsControllerCall.callWithNoReturn(
+                iRcs -> iRcs.addParticipantToGroupThread(mThreadId, participant.getId()));
+    }
+
+    /**
+     * Removes an {@link RcsParticipant} from this group thread and persists into storage. If the
+     * removed participant was the owner of this group, the owner will become null.
+     *
+     * @throws RcsMessageStoreException if the operation could not be persisted into storage
+     */
+    @WorkerThread
+    public void removeParticipant(@NonNull RcsParticipant participant)
+            throws RcsMessageStoreException {
+        if (participant == null) {
+            return;
+        }
+
+        RcsControllerCall.callWithNoReturn(
+                iRcs -> iRcs.removeParticipantFromGroupThread(mThreadId, participant.getId()));
+    }
+
+    /**
+     * Returns the set of {@link RcsParticipant}s that contribute to this group thread. The
+     * returned set does not support modifications, please use
+     * {@link RcsGroupThread#addParticipant(RcsParticipant)}
+     * and {@link RcsGroupThread#removeParticipant(RcsParticipant)} instead.
+     *
+     * @return the immutable set of {@link RcsParticipant} in this group thread.
+     * @throws RcsMessageStoreException if the values could not be read from the storage
+     */
+    @WorkerThread
+    @NonNull
+    public Set<RcsParticipant> getParticipants() throws RcsMessageStoreException {
+        RcsParticipantQueryParams queryParameters =
+                new RcsParticipantQueryParams.Builder().setThread(this).build();
+
+        RcsParticipantQueryResult queryResult = RcsControllerCall.call(
+                iRcs -> iRcs.getParticipants(queryParameters));
+
+        List<RcsParticipant> participantList = queryResult.getParticipants();
+        Set<RcsParticipant> participantSet = new LinkedHashSet<>(participantList);
+        return Collections.unmodifiableSet(participantSet);
+    }
+
+    /**
+     * Returns the conference URI for this {@link RcsGroupThread}. Please see 4.4.5.2 - GSMA RCC.53
+     * (RCS Device API 1.6 Specification
+     *
+     * @throws RcsMessageStoreException if the value could not be read from the storage
+     */
+    @Nullable
+    @WorkerThread
+    public Uri getConferenceUri() throws RcsMessageStoreException {
+        return RcsControllerCall.call(iRcs -> iRcs.getGroupThreadConferenceUri(mThreadId));
+    }
+
+    /**
+     * Sets the conference URI for this {@link RcsGroupThread} and persists into storage. Please see
+     * 4.4.5.2 - GSMA RCC.53 (RCS Device API 1.6 Specification
+     *
+     * @param conferenceUri The URI as String to be used as the conference URI.
+     * @throws RcsMessageStoreException if the value could not be persisted into storage
+     */
+    @Nullable
+    @WorkerThread
+    public void setConferenceUri(Uri conferenceUri) throws RcsMessageStoreException {
+        RcsControllerCall.callWithNoReturn(
+                iRcs -> iRcs.setGroupThreadConferenceUri(mThreadId, conferenceUri));
     }
 }
diff --git a/telephony/java/android/telephony/ims/RcsThreadEvent.aidl b/telephony/java/android/telephony/ims/RcsGroupThreadEvent.aidl
similarity index 95%
rename from telephony/java/android/telephony/ims/RcsThreadEvent.aidl
rename to telephony/java/android/telephony/ims/RcsGroupThreadEvent.aidl
index 4a40d89..77a2372 100644
--- a/telephony/java/android/telephony/ims/RcsThreadEvent.aidl
+++ b/telephony/java/android/telephony/ims/RcsGroupThreadEvent.aidl
@@ -1,5 +1,4 @@
 /*
- *
  * Copyright 2019, The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,4 +16,4 @@
 
 package android.telephony.ims;
 
-parcelable RcsThreadEvent;
+parcelable RcsGroupThreadEvent;
diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadEvent.java b/telephony/java/android/telephony/ims/RcsGroupThreadEvent.java
new file mode 100644
index 0000000..bc61877
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsGroupThreadEvent.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2018 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.telephony.ims;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+
+/**
+ * An event that happened on an {@link RcsGroupThread}.
+ *
+ * @hide - TODO: make public
+ */
+public abstract class RcsGroupThreadEvent extends RcsEvent {
+    private final int mRcsGroupThreadId;
+    private final int mOriginatingParticipantId;
+
+    RcsGroupThreadEvent(long timestamp, int rcsGroupThreadId,
+            int originatingParticipantId) {
+        super(timestamp);
+        mRcsGroupThreadId = rcsGroupThreadId;
+        mOriginatingParticipantId = originatingParticipantId;
+    }
+
+    /**
+     * @return Returns the {@link RcsGroupThread} that this event happened on.
+     */
+    @NonNull
+    public RcsGroupThread getRcsGroupThread() {
+        return new RcsGroupThread(mRcsGroupThreadId);
+    }
+
+    /**
+     * @return Returns the {@link RcsParticipant} that performed the event.
+     */
+    @NonNull
+    public RcsParticipant getOriginatingParticipant() {
+        return new RcsParticipant(mOriginatingParticipantId);
+    }
+
+    /**
+     * @hide
+     */
+    RcsGroupThreadEvent(Parcel in) {
+        super(in);
+        mRcsGroupThreadId = in.readInt();
+        mOriginatingParticipantId = in.readInt();
+    }
+
+    /**
+     * @hide
+     */
+    public void writeToParcel(Parcel dest, int flags) {
+        super.writeToParcel(dest, flags);
+        dest.writeInt(mRcsGroupThreadId);
+        dest.writeInt(mOriginatingParticipantId);
+    }
+}
diff --git a/telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl b/telephony/java/android/telephony/ims/RcsGroupThreadIconChangedEvent.aidl
similarity index 93%
copy from telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl
copy to telephony/java/android/telephony/ims/RcsGroupThreadIconChangedEvent.aidl
index 82d985d..daea792 100644
--- a/telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl
+++ b/telephony/java/android/telephony/ims/RcsGroupThreadIconChangedEvent.aidl
@@ -1,5 +1,4 @@
 /*
- *
  * Copyright 2019, The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -17,4 +16,4 @@
 
 package android.telephony.ims;
 
-parcelable RcsThreadIconChangedEvent;
+parcelable RcsGroupThreadIconChangedEvent;
diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadIconChangedEvent.java b/telephony/java/android/telephony/ims/RcsGroupThreadIconChangedEvent.java
new file mode 100644
index 0000000..74af973
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsGroupThreadIconChangedEvent.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2018 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.telephony.ims;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * An event that indicates an {@link RcsGroupThread}'s icon was changed. Please see R6-2-5 - GSMA
+ * RCC.71 (RCS Universal Profile Service Definition Document)
+ *
+ * @hide - TODO: make public
+ */
+public final class RcsGroupThreadIconChangedEvent extends RcsGroupThreadEvent implements
+        Parcelable {
+    private final Uri mNewIcon;
+
+    /**
+     * Creates a new {@link RcsGroupThreadIconChangedEvent}. This event is not persisted into
+     * storage until {@link RcsMessageStore#persistRcsEvent(RcsEvent)} is called.
+     *
+     * @param timestamp The timestamp of when this event happened, in milliseconds passed after
+     *                  midnight, January 1st, 1970 UTC
+     * @param rcsGroupThread The {@link RcsGroupThread} that this event happened on
+     * @param originatingParticipant The {@link RcsParticipant} that changed the
+     *                               {@link RcsGroupThread}'s icon.
+     * @param newIcon {@link Uri} to the new icon of this {@link RcsGroupThread}
+     * @see RcsMessageStore#persistRcsEvent(RcsEvent)
+     */
+    public RcsGroupThreadIconChangedEvent(long timestamp, @NonNull RcsGroupThread rcsGroupThread,
+            @NonNull RcsParticipant originatingParticipant, @Nullable Uri newIcon) {
+        super(timestamp, rcsGroupThread.getThreadId(), originatingParticipant.getId());
+        mNewIcon = newIcon;
+    }
+
+    /**
+     * @hide - internal constructor for queries
+     */
+    public RcsGroupThreadIconChangedEvent(long timestamp, int rcsGroupThreadId,
+            int originatingParticipantId, @Nullable Uri newIcon) {
+        super(timestamp, rcsGroupThreadId, originatingParticipantId);
+        mNewIcon = newIcon;
+    }
+
+    /**
+     * @return Returns the {@link Uri} to the icon of the {@link RcsGroupThread} after this
+     * {@link RcsGroupThreadIconChangedEvent} occured.
+     */
+    @Nullable
+    public Uri getNewIcon() {
+        return mNewIcon;
+    }
+
+    /**
+     * Persists the event to the data store.
+     *
+     * @hide - not meant for public use.
+     */
+    @Override
+    public void persist() throws RcsMessageStoreException {
+        // TODO ensure failure throws
+        RcsControllerCall.call(iRcs -> iRcs.createGroupThreadIconChangedEvent(
+                getTimestamp(), getRcsGroupThread().getThreadId(),
+                getOriginatingParticipant().getId(), mNewIcon));
+    }
+
+    public static final Creator<RcsGroupThreadIconChangedEvent> CREATOR =
+            new Creator<RcsGroupThreadIconChangedEvent>() {
+                @Override
+                public RcsGroupThreadIconChangedEvent createFromParcel(Parcel in) {
+                    return new RcsGroupThreadIconChangedEvent(in);
+                }
+
+                @Override
+                public RcsGroupThreadIconChangedEvent[] newArray(int size) {
+                    return new RcsGroupThreadIconChangedEvent[size];
+                }
+            };
+
+    private RcsGroupThreadIconChangedEvent(Parcel in) {
+        super(in);
+        mNewIcon = in.readParcelable(Uri.class.getClassLoader());
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        super.writeToParcel(dest, flags);
+        dest.writeParcelable(mNewIcon, flags);
+    }
+}
diff --git a/telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl b/telephony/java/android/telephony/ims/RcsGroupThreadNameChangedEvent.aidl
similarity index 93%
copy from telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl
copy to telephony/java/android/telephony/ims/RcsGroupThreadNameChangedEvent.aidl
index 82d985d..3ed9bd1 100644
--- a/telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl
+++ b/telephony/java/android/telephony/ims/RcsGroupThreadNameChangedEvent.aidl
@@ -17,4 +17,4 @@
 
 package android.telephony.ims;
 
-parcelable RcsThreadIconChangedEvent;
+parcelable RcsGroupThreadNameChangedEvent;
diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadNameChangedEvent.java b/telephony/java/android/telephony/ims/RcsGroupThreadNameChangedEvent.java
new file mode 100644
index 0000000..06f4d5b
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsGroupThreadNameChangedEvent.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2018 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.telephony.ims;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * An event that indicates an {@link RcsGroupThread}'s name was changed. Please see R6-2-5 - GSMA
+ * RCC.71 (RCS Universal Profile Service Definition Document)
+ *
+ * @hide - TODO: make public
+ */
+public final class RcsGroupThreadNameChangedEvent extends RcsGroupThreadEvent implements
+        Parcelable {
+    private final String mNewName;
+
+    /**
+     * Creates a new {@link RcsGroupThreadNameChangedEvent}. This event is not persisted into
+     * storage until {@link RcsMessageStore#persistRcsEvent(RcsEvent)} is called.
+     *
+     * @param timestamp The timestamp of when this event happened, in milliseconds passed after
+     *                  midnight, January 1st, 1970 UTC
+     * @param rcsGroupThread The {@link RcsGroupThread} that this event happened on
+     * @param originatingParticipant The {@link RcsParticipant} that changed the
+     *                               {@link RcsGroupThread}'s icon.
+     * @param newName The new name of the {@link RcsGroupThread}
+     * @see RcsMessageStore#persistRcsEvent(RcsEvent)
+     */
+    public RcsGroupThreadNameChangedEvent(long timestamp, @NonNull RcsGroupThread rcsGroupThread,
+            @NonNull RcsParticipant originatingParticipant, @Nullable String newName) {
+        super(timestamp, rcsGroupThread.getThreadId(), originatingParticipant.getId());
+        mNewName = newName;
+    }
+
+    /**
+     * @hide - internal constructor for queries
+     */
+    public RcsGroupThreadNameChangedEvent(long timestamp, int rcsGroupThreadId,
+            int originatingParticipantId, @Nullable String newName) {
+        super(timestamp, rcsGroupThreadId, originatingParticipantId);
+        mNewName = newName;
+    }
+
+    /**
+     * @return Returns the name of this {@link RcsGroupThread} after this
+     * {@link RcsGroupThreadNameChangedEvent} happened.
+     */
+    @Nullable
+    public String getNewName() {
+        return mNewName;
+    }
+
+    /**
+     * Persists the event to the data store.
+     *
+     * @hide - not meant for public use.
+     */
+    @Override
+    public void persist() throws RcsMessageStoreException {
+        RcsControllerCall.call(iRcs -> iRcs.createGroupThreadNameChangedEvent(
+                getTimestamp(), getRcsGroupThread().getThreadId(),
+                getOriginatingParticipant().getId(), mNewName));
+    }
+
+    public static final Creator<RcsGroupThreadNameChangedEvent> CREATOR =
+            new Creator<RcsGroupThreadNameChangedEvent>() {
+                @Override
+                public RcsGroupThreadNameChangedEvent createFromParcel(Parcel in) {
+                    return new RcsGroupThreadNameChangedEvent(in);
+                }
+
+                @Override
+                public RcsGroupThreadNameChangedEvent[] newArray(int size) {
+                    return new RcsGroupThreadNameChangedEvent[size];
+                }
+            };
+
+    private RcsGroupThreadNameChangedEvent(Parcel in) {
+        super(in);
+        mNewName = in.readString();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        super.writeToParcel(dest, flags);
+        dest.writeString(mNewName);
+    }
+}
diff --git a/telephony/java/android/telephony/ims/RcsMessage.aidl b/telephony/java/android/telephony/ims/RcsGroupThreadParticipantJoinedEvent.aidl
similarity index 92%
copy from telephony/java/android/telephony/ims/RcsMessage.aidl
copy to telephony/java/android/telephony/ims/RcsGroupThreadParticipantJoinedEvent.aidl
index b32cd12..420abff 100644
--- a/telephony/java/android/telephony/ims/RcsMessage.aidl
+++ b/telephony/java/android/telephony/ims/RcsGroupThreadParticipantJoinedEvent.aidl
@@ -17,4 +17,4 @@
 
 package android.telephony.ims;
 
-parcelable RcsMessage;
+parcelable RcsGroupThreadParticipantJoinedEvent;
diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadParticipantJoinedEvent.java b/telephony/java/android/telephony/ims/RcsGroupThreadParticipantJoinedEvent.java
new file mode 100644
index 0000000..4932707
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsGroupThreadParticipantJoinedEvent.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2018 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.telephony.ims;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * An event that indicates an RCS participant has joined an {@link RcsThread}. Please see US6-3 -
+ * GSMA RCC.71 (RCS Universal Profile Service Definition Document)
+ *
+ * @hide - TODO: make public
+ */
+public final class RcsGroupThreadParticipantJoinedEvent extends RcsGroupThreadEvent implements
+        Parcelable {
+    private final int mJoinedParticipantId;
+
+    /**
+     * Creates a new {@link RcsGroupThreadParticipantJoinedEvent}. This event is not persisted into
+     * storage until {@link RcsMessageStore#persistRcsEvent(RcsEvent)} is called.
+     *
+     * @param timestamp The timestamp of when this event happened, in milliseconds passed after
+     *                  midnight, January 1st, 1970 UTC
+     * @param rcsGroupThread The {@link RcsGroupThread} that this event happened on
+     * @param originatingParticipant The {@link RcsParticipant} that added or invited the new
+     *                               {@link RcsParticipant} into the {@link RcsGroupThread}
+     * @param joinedParticipant The new {@link RcsParticipant} that joined the
+     *                          {@link RcsGroupThread}
+     * @see RcsMessageStore#persistRcsEvent(RcsEvent)
+     */
+    public RcsGroupThreadParticipantJoinedEvent(long timestamp,
+            @NonNull RcsGroupThread rcsGroupThread, @NonNull RcsParticipant originatingParticipant,
+            @NonNull RcsParticipant joinedParticipant) {
+        super(timestamp, rcsGroupThread.getThreadId(), originatingParticipant.getId());
+        mJoinedParticipantId = joinedParticipant.getId();
+    }
+
+    /**
+     * @hide - internal constructor for queries
+     */
+    public RcsGroupThreadParticipantJoinedEvent(long timestamp, int rcsGroupThreadId,
+            int originatingParticipantId, int joinedParticipantId) {
+        super(timestamp, rcsGroupThreadId, originatingParticipantId);
+        mJoinedParticipantId = joinedParticipantId;
+    }
+
+    /**
+     * @return Returns the {@link RcsParticipant} that joined the associated {@link RcsGroupThread}
+     */
+    public RcsParticipant getJoinedParticipant() {
+        return new RcsParticipant(mJoinedParticipantId);
+    }
+
+    /**
+     * Persists the event to the data store.
+     *
+     * @hide - not meant for public use.
+     */
+    @Override
+    public void persist() throws RcsMessageStoreException {
+        RcsControllerCall.call(
+                iRcs -> iRcs.createGroupThreadParticipantJoinedEvent(getTimestamp(),
+                        getRcsGroupThread().getThreadId(), getOriginatingParticipant().getId(),
+                        getJoinedParticipant().getId()));
+    }
+
+    public static final Creator<RcsGroupThreadParticipantJoinedEvent> CREATOR =
+            new Creator<RcsGroupThreadParticipantJoinedEvent>() {
+                @Override
+                public RcsGroupThreadParticipantJoinedEvent createFromParcel(Parcel in) {
+                    return new RcsGroupThreadParticipantJoinedEvent(in);
+                }
+
+                @Override
+                public RcsGroupThreadParticipantJoinedEvent[] newArray(int size) {
+                    return new RcsGroupThreadParticipantJoinedEvent[size];
+                }
+            };
+
+    private RcsGroupThreadParticipantJoinedEvent(Parcel in) {
+        super(in);
+        mJoinedParticipantId = in.readInt();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        super.writeToParcel(dest, flags);
+        dest.writeInt(mJoinedParticipantId);
+    }
+}
diff --git a/telephony/java/android/telephony/ims/RcsMessage.aidl b/telephony/java/android/telephony/ims/RcsGroupThreadParticipantLeftEvent.aidl
similarity index 92%
rename from telephony/java/android/telephony/ims/RcsMessage.aidl
rename to telephony/java/android/telephony/ims/RcsGroupThreadParticipantLeftEvent.aidl
index b32cd12..ff139ac 100644
--- a/telephony/java/android/telephony/ims/RcsMessage.aidl
+++ b/telephony/java/android/telephony/ims/RcsGroupThreadParticipantLeftEvent.aidl
@@ -17,4 +17,4 @@
 
 package android.telephony.ims;
 
-parcelable RcsMessage;
+parcelable RcsGroupThreadParticipantLeftEvent;
diff --git a/telephony/java/android/telephony/ims/RcsGroupThreadParticipantLeftEvent.java b/telephony/java/android/telephony/ims/RcsGroupThreadParticipantLeftEvent.java
new file mode 100644
index 0000000..970a046
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsGroupThreadParticipantLeftEvent.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2018 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.telephony.ims;
+
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * An event that indicates an RCS participant has left an {@link RcsThread}. Please see US6-23 -
+ * GSMA RCC.71 (RCS Universal Profile Service Definition Document)
+ *
+ * @hide - TODO: make public
+ */
+public final class RcsGroupThreadParticipantLeftEvent extends RcsGroupThreadEvent implements
+        Parcelable {
+    private final int mLeavingParticipantId;
+
+    /**
+     * Creates a new {@link RcsGroupThreadParticipantLeftEvent}. his event is not persisted into
+     * storage until {@link RcsMessageStore#persistRcsEvent(RcsEvent)} is called.
+     *
+     * @param timestamp The timestamp of when this event happened, in milliseconds passed after
+     *                  midnight, January 1st, 1970 UTC
+     * @param rcsGroupThread The {@link RcsGroupThread} that this event happened on
+     * @param originatingParticipant The {@link RcsParticipant} that removed the
+     *                               {@link RcsParticipant} from the {@link RcsGroupThread}. It is
+     *                               possible that originatingParticipant and leavingParticipant are
+     *                               the same (i.e. {@link RcsParticipant} left the group
+     *                               themselves)
+     * @param leavingParticipant The {@link RcsParticipant} that left the {@link RcsGroupThread}
+     * @see RcsMessageStore#persistRcsEvent(RcsEvent)
+     */
+    public RcsGroupThreadParticipantLeftEvent(long timestamp,
+            @NonNull RcsGroupThread rcsGroupThread, @NonNull RcsParticipant originatingParticipant,
+            @NonNull RcsParticipant leavingParticipant) {
+        super(timestamp, rcsGroupThread.getThreadId(), originatingParticipant.getId());
+        mLeavingParticipantId = leavingParticipant.getId();
+    }
+
+    /**
+     * @hide - internal constructor for queries
+     */
+    public RcsGroupThreadParticipantLeftEvent(long timestamp, int rcsGroupThreadId,
+            int originatingParticipantId, int leavingParticipantId) {
+        super(timestamp, rcsGroupThreadId, originatingParticipantId);
+        mLeavingParticipantId = leavingParticipantId;
+    }
+
+    /**
+     * @return Returns the {@link RcsParticipant} that left the associated {@link RcsGroupThread}
+     * after this {@link RcsGroupThreadParticipantLeftEvent} happened.
+     */
+    @NonNull
+    public RcsParticipant getLeavingParticipantId() {
+        return new RcsParticipant(mLeavingParticipantId);
+    }
+
+    @Override
+    public void persist() throws RcsMessageStoreException {
+        RcsControllerCall.call(
+                iRcs -> iRcs.createGroupThreadParticipantJoinedEvent(getTimestamp(),
+                        getRcsGroupThread().getThreadId(), getOriginatingParticipant().getId(),
+                        getLeavingParticipantId().getId()));
+    }
+
+    public static final Creator<RcsGroupThreadParticipantLeftEvent> CREATOR =
+            new Creator<RcsGroupThreadParticipantLeftEvent>() {
+                @Override
+                public RcsGroupThreadParticipantLeftEvent createFromParcel(Parcel in) {
+                    return new RcsGroupThreadParticipantLeftEvent(in);
+                }
+
+                @Override
+                public RcsGroupThreadParticipantLeftEvent[] newArray(int size) {
+                    return new RcsGroupThreadParticipantLeftEvent[size];
+                }
+            };
+
+    private RcsGroupThreadParticipantLeftEvent(Parcel in) {
+        super(in);
+        mLeavingParticipantId = in.readInt();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        super.writeToParcel(dest, flags);
+        dest.writeInt(mLeavingParticipantId);
+    }
+}
diff --git a/telephony/java/android/telephony/ims/RcsIncomingMessage.aidl b/telephony/java/android/telephony/ims/RcsIncomingMessage.aidl
deleted file mode 100644
index 6552a82..0000000
--- a/telephony/java/android/telephony/ims/RcsIncomingMessage.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- *
- * Copyright 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.telephony.ims;
-
-parcelable RcsIncomingMessage;
diff --git a/telephony/java/android/telephony/ims/RcsIncomingMessage.java b/telephony/java/android/telephony/ims/RcsIncomingMessage.java
index f39e06d..f3b7815 100644
--- a/telephony/java/android/telephony/ims/RcsIncomingMessage.java
+++ b/telephony/java/android/telephony/ims/RcsIncomingMessage.java
@@ -15,34 +15,82 @@
  */
 package android.telephony.ims;
 
-import android.os.Parcel;
+import android.annotation.WorkerThread;
 
 /**
  * This is a single instance of a message received over RCS.
- * @hide - TODO(sahinc) make this public
+ *
+ * @hide - TODO: make public
  */
 public class RcsIncomingMessage extends RcsMessage {
-    public static final Creator<RcsIncomingMessage> CREATOR = new Creator<RcsIncomingMessage>() {
-        @Override
-        public RcsIncomingMessage createFromParcel(Parcel in) {
-            return new RcsIncomingMessage(in);
-        }
-
-        @Override
-        public RcsIncomingMessage[] newArray(int size) {
-            return new RcsIncomingMessage[size];
-        }
-    };
-
-    protected RcsIncomingMessage(Parcel in) {
+    /**
+     * @hide
+     */
+    RcsIncomingMessage(int id) {
+        super(id);
     }
 
-    @Override
-    public int describeContents() {
-        return 0;
+    /**
+     * Sets the timestamp of arrival for this message and persists into storage. The timestamp is
+     * defined as milliseconds passed after midnight, January 1, 1970 UTC
+     *
+     * @param arrivalTimestamp The timestamp to set to.
+     * @throws RcsMessageStoreException if the value could not be persisted into storage
+     */
+    @WorkerThread
+    public void setArrivalTimestamp(long arrivalTimestamp) throws RcsMessageStoreException {
+        RcsControllerCall.callWithNoReturn(
+                iRcs -> iRcs.setMessageArrivalTimestamp(mId, true, arrivalTimestamp));
     }
 
+    /**
+     * @return Returns the timestamp of arrival for this message. The timestamp is defined as
+     * milliseconds passed after midnight, January 1, 1970 UTC
+     * @throws RcsMessageStoreException if the value could not be read from the storage
+     */
+    @WorkerThread
+    public long getArrivalTimestamp() throws RcsMessageStoreException {
+        return RcsControllerCall.call(iRcs -> iRcs.getMessageArrivalTimestamp(mId, true));
+    }
+
+    /**
+     * Sets the timestamp of when the user saw this message and persists into storage. The timestamp
+     * is defined as milliseconds passed after midnight, January 1, 1970 UTC
+     *
+     * @param notifiedTimestamp The timestamp to set to.
+     * @throws RcsMessageStoreException if the value could not be persisted into storage
+     */
+    @WorkerThread
+    public void setSeenTimestamp(long notifiedTimestamp) throws RcsMessageStoreException {
+        RcsControllerCall.callWithNoReturn(
+                iRcs -> iRcs.setMessageSeenTimestamp(mId, true, notifiedTimestamp));
+    }
+
+    /**
+     * @return Returns the timestamp of when the user saw this message. The timestamp is defined as
+     * milliseconds passed after midnight, January 1, 1970 UTC
+     * @throws RcsMessageStoreException if the value could not be read from the storage
+     */
+    @WorkerThread
+    public long getSeenTimestamp() throws RcsMessageStoreException {
+        return RcsControllerCall.call(iRcs -> iRcs.getMessageSeenTimestamp(mId, true));
+    }
+
+    /**
+     * @return Returns the sender of this incoming message.
+     * @throws RcsMessageStoreException if the value could not be read from the storage
+     */
+    @WorkerThread
+    public RcsParticipant getSenderParticipant() throws RcsMessageStoreException {
+        return new RcsParticipant(
+                RcsControllerCall.call(iRcs -> iRcs.getSenderParticipant(mId)));
+    }
+
+    /**
+     * @return Returns {@code true} as this is an incoming message
+     */
     @Override
-    public void writeToParcel(Parcel dest, int flags) {
+    public boolean isIncoming() {
+        return true;
     }
 }
diff --git a/telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl b/telephony/java/android/telephony/ims/RcsIncomingMessageCreationParams.aidl
similarity index 93%
copy from telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl
copy to telephony/java/android/telephony/ims/RcsIncomingMessageCreationParams.aidl
index 82d985d..1f1d4f6 100644
--- a/telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl
+++ b/telephony/java/android/telephony/ims/RcsIncomingMessageCreationParams.aidl
@@ -17,4 +17,4 @@
 
 package android.telephony.ims;
 
-parcelable RcsThreadIconChangedEvent;
+parcelable RcsIncomingMessageCreationParams;
diff --git a/telephony/java/android/telephony/ims/RcsIncomingMessageCreationParams.java b/telephony/java/android/telephony/ims/RcsIncomingMessageCreationParams.java
new file mode 100644
index 0000000..64b2339
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsIncomingMessageCreationParams.java
@@ -0,0 +1,180 @@
+/*
+ * 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.telephony.ims;
+
+import android.annotation.CheckResult;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * {@link RcsIncomingMessageCreationParams} is a collection of parameters that should be passed
+ * into {@link RcsThread#addIncomingMessage(RcsIncomingMessageCreationParams)} to generate an
+ * {@link RcsIncomingMessage} on that {@link RcsThread}
+ *
+ * @hide - TODO: make public
+ */
+public final class RcsIncomingMessageCreationParams extends RcsMessageCreationParams implements
+        Parcelable {
+    // The arrival timestamp for the RcsIncomingMessage to be created
+    private final long mArrivalTimestamp;
+    // The seen timestamp for the RcsIncomingMessage to be created
+    private final long mSeenTimestamp;
+    // The participant that sent this incoming message
+    private final int mSenderParticipantId;
+
+    /**
+     * Builder to help create an {@link RcsIncomingMessageCreationParams}
+     *
+     * @see RcsThread#addIncomingMessage(RcsIncomingMessageCreationParams)
+     */
+    public static class Builder extends RcsMessageCreationParams.Builder {
+        private RcsParticipant mSenderParticipant;
+        private long mArrivalTimestamp;
+        private long mSeenTimestamp;
+
+        /**
+         * Creates a {@link Builder} to create an instance of
+         * {@link RcsIncomingMessageCreationParams}
+         *
+         * @param originationTimestamp The timestamp of {@link RcsMessage} creation. The origination
+         *                             timestamp value in milliseconds passed after midnight,
+         *                             January 1, 1970 UTC
+         * @param arrivalTimestamp The timestamp of arrival, defined as milliseconds passed after
+         *                         midnight, January 1, 1970 UTC
+         * @param subscriptionId The subscription ID that was used to send or receive this
+         *                       {@link RcsMessage}
+         */
+        public Builder(long originationTimestamp, long arrivalTimestamp, int subscriptionId) {
+            super(originationTimestamp, subscriptionId);
+            mArrivalTimestamp = arrivalTimestamp;
+        }
+
+        /**
+         * Sets the {@link RcsParticipant} that send this {@link RcsIncomingMessage}
+         *
+         * @param senderParticipant The {@link RcsParticipant} that sent this
+         * {@link RcsIncomingMessage}
+         * @return The same instance of {@link Builder} to chain methods.
+         */
+        @CheckResult
+        public Builder setSenderParticipant(RcsParticipant senderParticipant) {
+            mSenderParticipant = senderParticipant;
+            return this;
+        }
+
+        /**
+         * Sets the time of the arrival of this {@link RcsIncomingMessage}
+
+         * @return The same instance of {@link Builder} to chain methods.
+         * @see RcsIncomingMessage#setArrivalTimestamp(long)
+         */
+        @CheckResult
+        public Builder setArrivalTimestamp(long arrivalTimestamp) {
+            mArrivalTimestamp = arrivalTimestamp;
+            return this;
+        }
+
+        /**
+         * Sets the time of the when this user saw the {@link RcsIncomingMessage}
+         * @param seenTimestamp The seen timestamp , defined as milliseconds passed after midnight,
+         *                      January 1, 1970 UTC
+         * @return The same instance of {@link Builder} to chain methods.
+         * @see RcsIncomingMessage#setSeenTimestamp(long)
+         */
+        @CheckResult
+        public Builder setSeenTimestamp(long seenTimestamp) {
+            mSeenTimestamp = seenTimestamp;
+            return this;
+        }
+
+        /**
+         * Creates parameters for creating a new incoming message.
+         * @return A new instance of {@link RcsIncomingMessageCreationParams} to create a new
+         * {@link RcsIncomingMessage}
+         */
+        public RcsIncomingMessageCreationParams build() {
+            return new RcsIncomingMessageCreationParams(this);
+        }
+    }
+
+    private RcsIncomingMessageCreationParams(Builder builder) {
+        super(builder);
+        mArrivalTimestamp = builder.mArrivalTimestamp;
+        mSeenTimestamp = builder.mSeenTimestamp;
+        mSenderParticipantId = builder.mSenderParticipant.getId();
+    }
+
+    private RcsIncomingMessageCreationParams(Parcel in) {
+        super(in);
+        mArrivalTimestamp = in.readLong();
+        mSeenTimestamp = in.readLong();
+        mSenderParticipantId = in.readInt();
+    }
+
+    /**
+     * @return Returns the arrival timestamp for the {@link RcsIncomingMessage} to be created.
+     * Timestamp is defined as milliseconds passed after midnight, January 1, 1970 UTC
+     */
+    public long getArrivalTimestamp() {
+        return mArrivalTimestamp;
+    }
+
+    /**
+     * @return Returns the seen timestamp for the {@link RcsIncomingMessage} to be created.
+     * Timestamp is defined as milliseconds passed after midnight, January 1, 1970 UTC
+     */
+    public long getSeenTimestamp() {
+        return mSeenTimestamp;
+    }
+
+    /**
+     * Helper getter for {@link com.android.internal.telephony.ims.RcsMessageStoreController} to
+     * create {@link RcsIncomingMessage}s
+     *
+     * Since the API doesn't expose any ID's to API users, this should be hidden.
+     * @hide
+     */
+    public int getSenderParticipantId() {
+        return mSenderParticipantId;
+    }
+
+    public static final Creator<RcsIncomingMessageCreationParams> CREATOR =
+            new Creator<RcsIncomingMessageCreationParams>() {
+                @Override
+                public RcsIncomingMessageCreationParams createFromParcel(Parcel in) {
+                    return new RcsIncomingMessageCreationParams(in);
+                }
+
+                @Override
+                public RcsIncomingMessageCreationParams[] newArray(int size) {
+                    return new RcsIncomingMessageCreationParams[size];
+                }
+            };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        super.writeToParcel(dest);
+        dest.writeLong(mArrivalTimestamp);
+        dest.writeLong(mSeenTimestamp);
+        dest.writeInt(mSenderParticipantId);
+    }
+}
diff --git a/telephony/java/android/telephony/ims/RcsLocationPart.aidl b/telephony/java/android/telephony/ims/RcsLocationPart.aidl
deleted file mode 100644
index 4fe5ca9..0000000
--- a/telephony/java/android/telephony/ims/RcsLocationPart.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- *
- * Copyright 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.telephony.ims;
-
-parcelable RcsLocationPart;
diff --git a/telephony/java/android/telephony/ims/RcsLocationPart.java b/telephony/java/android/telephony/ims/RcsLocationPart.java
deleted file mode 100644
index 19be4ce..0000000
--- a/telephony/java/android/telephony/ims/RcsLocationPart.java
+++ /dev/null
@@ -1,48 +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 android.telephony.ims;
-
-import android.os.Parcel;
-
-/**
- * A part of a composite {@link RcsMessage} that holds a location
- * @hide - TODO(sahinc) make this public
- */
-public class RcsLocationPart extends RcsPart {
-    public static final Creator<RcsLocationPart> CREATOR = new Creator<RcsLocationPart>() {
-        @Override
-        public RcsLocationPart createFromParcel(Parcel in) {
-            return new RcsLocationPart(in);
-        }
-
-        @Override
-        public RcsLocationPart[] newArray(int size) {
-            return new RcsLocationPart[size];
-        }
-    };
-
-    protected RcsLocationPart(Parcel in) {
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-    }
-}
diff --git a/telephony/java/android/telephony/ims/RcsManager.aidl b/telephony/java/android/telephony/ims/RcsManager.aidl
deleted file mode 100644
index 63bc71c..0000000
--- a/telephony/java/android/telephony/ims/RcsManager.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- *
- * Copyright 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.telephony.ims;
-
-parcelable RcsManager;
diff --git a/telephony/java/android/telephony/ims/RcsManager.java b/telephony/java/android/telephony/ims/RcsManager.java
index df108c8..90bd044 100644
--- a/telephony/java/android/telephony/ims/RcsManager.java
+++ b/telephony/java/android/telephony/ims/RcsManager.java
@@ -20,15 +20,23 @@
 
 /**
  * The manager class for RCS related utilities.
- * @hide
+ *
+ * @hide - TODO: make public
  */
 @SystemService(Context.TELEPHONY_RCS_SERVICE)
 public class RcsManager {
 
+    /**
+     * @hide
+     */
+    public RcsManager() {
+        // empty constructor
+    }
+
     private static final RcsMessageStore sRcsMessageStoreInstance = new RcsMessageStore();
 
     /**
-     * Returns an instance of RcsMessageStore.
+     * Returns an instance of {@link RcsMessageStore}
      */
     public RcsMessageStore getRcsMessageStore() {
         return sRcsMessageStoreInstance;
diff --git a/telephony/java/android/telephony/ims/RcsMessage.java b/telephony/java/android/telephony/ims/RcsMessage.java
index d46685c..1700941 100644
--- a/telephony/java/android/telephony/ims/RcsMessage.java
+++ b/telephony/java/android/telephony/ims/RcsMessage.java
@@ -15,11 +15,317 @@
  */
 package android.telephony.ims;
 
-import android.os.Parcelable;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.WorkerThread;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
 
 /**
  * This is a single instance of a message sent or received over RCS.
- * @hide - TODO(sahinc) make this public
+ *
+ * @hide - TODO: make public
  */
-public abstract class RcsMessage implements Parcelable {
+public abstract class RcsMessage {
+    /**
+     * The value to indicate that this {@link RcsMessage} does not have any location information.
+     */
+    public static final double LOCATION_NOT_SET = Double.MIN_VALUE;
+
+    /**
+     * The status to indicate that this {@link RcsMessage}s status is not set yet.
+     */
+    public static final int NOT_SET = 0;
+
+    /**
+     * The status to indicate that this {@link RcsMessage} is a draft and is not in the process of
+     * sending yet.
+     */
+    public static final int DRAFT = 1;
+
+    /**
+     * The status to indicate that this {@link RcsMessage} was successfully sent.
+     */
+    public static final int QUEUED = 2;
+
+    /**
+     * The status to indicate that this {@link RcsMessage} is actively being sent.
+     */
+    public static final int SENDING = 3;
+
+    /**
+     * The status to indicate that this {@link RcsMessage} was successfully sent.
+     */
+    public static final int SENT = 4;
+
+    /**
+     * The status to indicate that this {@link RcsMessage} failed to send in an attempt before, and
+     * now being retried.
+     */
+    public static final int RETRYING = 5;
+
+    /**
+     * The status to indicate that this {@link RcsMessage} has permanently failed to send.
+     */
+    public static final int FAILED = 6;
+
+    /**
+     * The status to indicate that this {@link RcsMessage} was successfully received.
+     */
+    public static final int RECEIVED = 7;
+
+    /**
+     * The status to indicate that this {@link RcsMessage} was seen.
+     */
+    public static final int SEEN = 9;
+
+    /**
+     * @hide
+     */
+    protected final int mId;
+
+    @IntDef({
+            DRAFT, QUEUED, SENDING, SENT, RETRYING, FAILED, RECEIVED, SEEN
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface RcsMessageStatus {
+    }
+
+    RcsMessage(int id) {
+        mId = id;
+    }
+
+    /**
+     * Returns the row Id from the common message.
+     *
+     * @hide
+     */
+    public int getId() {
+        return mId;
+    }
+
+    /**
+     * @return Returns the subscription ID that this {@link RcsMessage} was sent from, or delivered
+     * to.
+     * @throws RcsMessageStoreException if the value could not be read from the storage
+     * @see android.telephony.SubscriptionInfo#getSubscriptionId
+     */
+    public int getSubscriptionId() throws RcsMessageStoreException {
+        return RcsControllerCall.call(iRcs -> iRcs.getMessageSubId(mId, isIncoming()));
+    }
+
+    /**
+     * Sets the subscription ID that this {@link RcsMessage} was sent from, or delivered to and
+     * persists it into storage.
+     *
+     * @param subId The subscription ID to persists into storage.
+     * @throws RcsMessageStoreException if the value could not be persisted into storage
+     * @see android.telephony.SubscriptionInfo#getSubscriptionId
+     */
+    @WorkerThread
+    public void setSubscriptionId(int subId) throws RcsMessageStoreException {
+        RcsControllerCall.callWithNoReturn(iRcs -> iRcs.setMessageSubId(mId, isIncoming(), subId));
+    }
+
+    /**
+     * Sets the status of this message and persists it into storage. Please see
+     * {@link RcsFileTransferPart#setFileTransferStatus(int)} to set statuses around file transfers.
+     *
+     * @throws RcsMessageStoreException if the value could not be persisted into storage
+     */
+    @WorkerThread
+    public void setStatus(@RcsMessageStatus int rcsMessageStatus) throws RcsMessageStoreException {
+        RcsControllerCall.callWithNoReturn(
+                iRcs -> iRcs.setMessageStatus(mId, isIncoming(), rcsMessageStatus));
+    }
+
+    /**
+     * @return Returns the status of this message. Please see
+     * {@link RcsFileTransferPart#setFileTransferStatus(int)} to set statuses around file transfers.
+     * @throws RcsMessageStoreException if the value could not be read from the storage
+     */
+    @WorkerThread
+    public @RcsMessageStatus int getStatus() throws RcsMessageStoreException {
+        return RcsControllerCall.call(iRcs -> iRcs.getMessageStatus(mId, isIncoming()));
+    }
+
+    /**
+     * Sets the origination timestamp of this message and persists it into storage. Origination is
+     * defined as when the sender tapped the send button.
+     *
+     * @param timestamp The origination timestamp value in milliseconds passed after midnight,
+     *                  January 1, 1970 UTC
+     * @throws RcsMessageStoreException if the value could not be persisted into storage
+     */
+    @WorkerThread
+    public void setOriginationTimestamp(long timestamp) throws RcsMessageStoreException {
+        RcsControllerCall.callWithNoReturn(
+                iRcs -> iRcs.setMessageOriginationTimestamp(mId, isIncoming(), timestamp));
+    }
+
+    /**
+     * @return Returns the origination timestamp of this message in milliseconds passed after
+     * midnight, January 1, 1970 UTC. Origination is defined as when the sender tapped the send
+     * button.
+     * @throws RcsMessageStoreException if the value could not be read from the storage
+     */
+    @WorkerThread
+    public long getOriginationTimestamp() throws RcsMessageStoreException {
+        return RcsControllerCall.call(
+                iRcs -> iRcs.getMessageOriginationTimestamp(mId, isIncoming()));
+    }
+
+    /**
+     * Sets the globally unique RCS message identifier for this message and persists it into
+     * storage. This function does not confirm that this message id is unique. Please see 4.4.5.2
+     * - GSMA RCC.53 (RCS Device API 1.6 Specification
+     *
+     * @param rcsMessageGlobalId The globally RCS message identifier
+     * @throws RcsMessageStoreException if the value could not be persisted into storage
+     */
+    @WorkerThread
+    public void setRcsMessageId(String rcsMessageGlobalId) throws RcsMessageStoreException {
+        RcsControllerCall.callWithNoReturn(
+                iRcs -> iRcs.setGlobalMessageIdForMessage(mId, isIncoming(), rcsMessageGlobalId));
+    }
+
+    /**
+     * @return Returns the globally unique RCS message identifier for this message. Please see
+     * 4.4.5.2 - GSMA RCC.53 (RCS Device API 1.6 Specification
+     * @throws RcsMessageStoreException if the value could not be read from the storage
+     */
+    @WorkerThread
+    public String getRcsMessageId() throws RcsMessageStoreException {
+        return RcsControllerCall.call(iRcs -> iRcs.getGlobalMessageIdForMessage(mId, isIncoming()));
+    }
+
+    /**
+     * @return Returns the user visible text included in this message.
+     * @throws RcsMessageStoreException if the value could not be read from the storage
+     */
+    @WorkerThread
+    public String getText() throws RcsMessageStoreException {
+        return RcsControllerCall.call(iRcs -> iRcs.getTextForMessage(mId, isIncoming()));
+    }
+
+    /**
+     * Sets the user visible text for this message and persists in storage.
+     *
+     * @param text The text this message now has
+     * @throws RcsMessageStoreException if the value could not be persisted into storage
+     */
+    @WorkerThread
+    public void setText(String text) throws RcsMessageStoreException {
+        RcsControllerCall.callWithNoReturn(iRcs -> iRcs.setTextForMessage(mId, isIncoming(), text));
+    }
+
+    /**
+     * @return Returns the associated latitude for this message, or
+     * {@link RcsMessage#LOCATION_NOT_SET} if it does not contain a location.
+     *
+     * @throws RcsMessageStoreException if the value could not be read from the storage
+     */
+    @WorkerThread
+    public double getLatitude() throws RcsMessageStoreException {
+        return RcsControllerCall.call(iRcs -> iRcs.getLatitudeForMessage(mId, isIncoming()));
+    }
+
+    /**
+     * Sets the latitude for this message and persists in storage.
+     *
+     * @param latitude The latitude for this location message.
+     * @throws RcsMessageStoreException if the value could not be persisted into storage
+     */
+    @WorkerThread
+    public void setLatitude(double latitude) throws RcsMessageStoreException {
+        RcsControllerCall.callWithNoReturn(
+                iRcs -> iRcs.setLatitudeForMessage(mId, isIncoming(), latitude));
+    }
+
+    /**
+     * @return Returns the associated longitude for this message, or
+     * {@link RcsMessage#LOCATION_NOT_SET} if it does not contain a location.
+     *
+     * @throws RcsMessageStoreException if the value could not be read from the storage
+     */
+    @WorkerThread
+    public double getLongitude() throws RcsMessageStoreException {
+        return RcsControllerCall.call(iRcs -> iRcs.getLongitudeForMessage(mId, isIncoming()));
+    }
+
+    /**
+     * Sets the longitude for this message and persists in storage.
+     *
+     * @param longitude The longitude for this location message.
+     * @throws RcsMessageStoreException if the value could not be persisted into storage
+     */
+    @WorkerThread
+    public void setLongitude(double longitude) throws RcsMessageStoreException {
+        RcsControllerCall.callWithNoReturn(
+                iRcs -> iRcs.setLongitudeForMessage(mId, isIncoming(), longitude));
+    }
+
+    /**
+     * Attaches an {@link RcsFileTransferPart} to this message and persists into storage.
+     *
+     * @param fileTransferCreationParameters The parameters to be used to create the
+     *                                       {@link RcsFileTransferPart}
+     * @return A new instance of {@link RcsFileTransferPart}
+     * @throws RcsMessageStoreException if the file transfer could not be persisted into storage.
+     */
+    @NonNull
+    @WorkerThread
+    public RcsFileTransferPart insertFileTransfer(
+            RcsFileTransferCreationParams fileTransferCreationParameters)
+            throws RcsMessageStoreException {
+        return new RcsFileTransferPart(RcsControllerCall.call(
+                iRcs -> iRcs.storeFileTransfer(mId, isIncoming(), fileTransferCreationParameters)));
+    }
+
+    /**
+     * @return Returns all the {@link RcsFileTransferPart}s associated with this message in an
+     * unmodifiable set.
+     * @throws RcsMessageStoreException if the file transfers could not be read from the storage
+     */
+    @NonNull
+    @WorkerThread
+    public Set<RcsFileTransferPart> getFileTransferParts() throws RcsMessageStoreException {
+        Set<RcsFileTransferPart> fileTransferParts = new HashSet<>();
+
+        int[] fileTransferIds = RcsControllerCall.call(
+                iRcs -> iRcs.getFileTransfersAttachedToMessage(mId, isIncoming()));
+
+        for (int fileTransfer : fileTransferIds) {
+            fileTransferParts.add(new RcsFileTransferPart(fileTransfer));
+        }
+
+        return Collections.unmodifiableSet(fileTransferParts);
+    }
+
+    /**
+     * Removes a {@link RcsFileTransferPart} from this message, and deletes it in storage.
+     *
+     * @param fileTransferPart The part to delete.
+     * @throws RcsMessageStoreException if the file transfer could not be removed from storage
+     */
+    @WorkerThread
+    public void removeFileTransferPart(@NonNull RcsFileTransferPart fileTransferPart)
+            throws RcsMessageStoreException {
+        if (fileTransferPart == null) {
+            return;
+        }
+
+        RcsControllerCall.callWithNoReturn(
+                iRcs -> iRcs.deleteFileTransfer(fileTransferPart.getId()));
+    }
+
+    /**
+     * @return Returns {@code true} if this message was received on this device, {@code false} if it
+     * was sent.
+     */
+    public abstract boolean isIncoming();
 }
diff --git a/telephony/java/android/telephony/ims/RcsMessageCreationParams.java b/telephony/java/android/telephony/ims/RcsMessageCreationParams.java
new file mode 100644
index 0000000..9ac4dcd
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsMessageCreationParams.java
@@ -0,0 +1,242 @@
+/*
+ * 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.telephony.ims;
+
+import static android.telephony.ims.RcsMessage.LOCATION_NOT_SET;
+
+import android.annotation.CheckResult;
+import android.annotation.Nullable;
+import android.os.Parcel;
+
+/**
+ * The collection of parameters to be passed into
+ * {@link RcsThread#addIncomingMessage(RcsIncomingMessageCreationParams)} and
+ * {@link RcsThread#addOutgoingMessage(RcsOutgoingMessageCreationParams)} to create and persist
+ * {@link RcsMessage}s on an {@link RcsThread}
+ *
+ * @hide - TODO: make public
+ */
+public class RcsMessageCreationParams {
+    // The globally unique id of the RcsMessage to be created.
+    private final String mRcsMessageGlobalId;
+
+    // The subscription that this message was/will be received/sent from.
+    private final int mSubId;
+    // The sending/receiving status of the message
+    private final @RcsMessage.RcsMessageStatus int mMessageStatus;
+    // The timestamp of message creation
+    private final long mOriginationTimestamp;
+    // The user visible content of the message
+    private final String mText;
+    // The latitude of the message if this is a location message
+    private final double mLatitude;
+    // The longitude of the message if this is a location message
+    private final double mLongitude;
+
+    /**
+     * @return Returns the globally unique RCS Message ID for the {@link RcsMessage} to be created.
+     * Please see 4.4.5.2 - GSMA RCC.53 (RCS Device API 1.6 Specification
+     */
+    @Nullable
+    public String getRcsMessageGlobalId() {
+        return mRcsMessageGlobalId;
+    }
+
+    /**
+     * @return Returns the subscription ID that was used to send or receive the {@link RcsMessage}
+     * to be created.
+     */
+    public int getSubId() {
+        return mSubId;
+    }
+
+    /**
+     * @return Returns the status for the {@link RcsMessage} to be created.
+     * @see RcsMessage.RcsMessageStatus
+     */
+    public int getMessageStatus() {
+        return mMessageStatus;
+    }
+
+    /**
+     * @return Returns the origination timestamp of the {@link RcsMessage} to be created in
+     * milliseconds passed after midnight, January 1, 1970 UTC. Origination is defined as when
+     * the sender tapped the send button.
+     */
+    public long getOriginationTimestamp() {
+        return mOriginationTimestamp;
+    }
+
+    /**
+     * @return Returns the user visible text contained in the {@link RcsMessage} to be created
+     */
+    @Nullable
+    public String getText() {
+        return mText;
+    }
+
+    /**
+     * @return Returns the latitude of the {@link RcsMessage} to be created, or
+     * {@link RcsMessage#LOCATION_NOT_SET} if the message does not contain a location.
+     */
+    public double getLatitude() {
+        return mLatitude;
+    }
+
+    /**
+     * @return Returns the longitude of the {@link RcsMessage} to be created, or
+     * {@link RcsMessage#LOCATION_NOT_SET} if the message does not contain a location.
+     */
+    public double getLongitude() {
+        return mLongitude;
+    }
+
+    /**
+     * The base builder for creating {@link RcsMessage}s on {@link RcsThread}s.
+     *
+     * @see RcsIncomingMessageCreationParams
+     */
+    public static class Builder {
+        private String mRcsMessageGlobalId;
+        private int mSubId;
+        private @RcsMessage.RcsMessageStatus int mMessageStatus;
+        private long mOriginationTimestamp;
+        private String mText;
+        private double mLatitude = LOCATION_NOT_SET;
+        private double mLongitude = LOCATION_NOT_SET;
+
+        /**
+         * @hide
+         */
+        public Builder(long originationTimestamp, int subscriptionId) {
+            mOriginationTimestamp = originationTimestamp;
+            mSubId = subscriptionId;
+        }
+
+        /**
+         * Sets the status of the {@link RcsMessage} to be built.
+         *
+         * @param rcsMessageStatus The status to be set
+         * @return The same instance of {@link Builder} to chain methods
+         * @see RcsMessage#setStatus(int)
+         */
+        @CheckResult
+        public Builder setStatus(@RcsMessage.RcsMessageStatus int rcsMessageStatus) {
+            mMessageStatus = rcsMessageStatus;
+            return this;
+        }
+
+        /**
+         * Sets the globally unique RCS message identifier for the {@link RcsMessage} to be built.
+         * This function does not confirm that this message id is unique. Please see 4.4.5.2 - GSMA
+         * RCC.53 (RCS Device API 1.6 Specification)
+         *
+         * @param rcsMessageId The ID to be set
+         * @return The same instance of {@link Builder} to chain methods
+         * @see RcsMessage#setRcsMessageId(String)
+         */
+        @CheckResult
+        public Builder setRcsMessageId(String rcsMessageId) {
+            mRcsMessageGlobalId = rcsMessageId;
+            return this;
+        }
+
+        /**
+         * Sets the text of the {@link RcsMessage} to be built.
+         *
+         * @param text The user visible text of the message
+         * @return The same instance of {@link Builder} to chain methods
+         * @see RcsMessage#setText(String)
+         */
+        @CheckResult
+        public Builder setText(String text) {
+            mText = text;
+            return this;
+        }
+
+        /**
+         * Sets the latitude of the {@link RcsMessage} to be built. Please see US5-24 - GSMA RCC.71
+         * (RCS Universal Profile Service Definition Document)
+         *
+         * @param latitude The latitude of the location information associated with this message.
+         * @return The same instance of {@link Builder} to chain methods
+         * @see RcsMessage#setLatitude(double)
+         */
+        @CheckResult
+        public Builder setLatitude(double latitude) {
+            mLatitude = latitude;
+            return this;
+        }
+
+        /**
+         * Sets the longitude of the {@link RcsMessage} to be built. Please see US5-24 - GSMA RCC.71
+         * (RCS Universal Profile Service Definition Document)
+         *
+         * @param longitude The longitude of the location information associated with this message.
+         * @return The same instance of {@link Builder} to chain methods
+         * @see RcsMessage#setLongitude(double)
+         */
+        @CheckResult
+        public Builder setLongitude(double longitude) {
+            mLongitude = longitude;
+            return this;
+        }
+
+        /**
+         * @return Builds and returns a newly created {@link RcsMessageCreationParams}
+         */
+        public RcsMessageCreationParams build() {
+            return new RcsMessageCreationParams(this);
+        }
+    }
+
+    protected RcsMessageCreationParams(Builder builder) {
+        mRcsMessageGlobalId = builder.mRcsMessageGlobalId;
+        mSubId = builder.mSubId;
+        mMessageStatus = builder.mMessageStatus;
+        mOriginationTimestamp = builder.mOriginationTimestamp;
+        mText = builder.mText;
+        mLatitude = builder.mLatitude;
+        mLongitude = builder.mLongitude;
+    }
+
+    /**
+     * @hide
+     */
+    RcsMessageCreationParams(Parcel in) {
+        mRcsMessageGlobalId = in.readString();
+        mSubId = in.readInt();
+        mMessageStatus = in.readInt();
+        mOriginationTimestamp = in.readLong();
+        mText = in.readString();
+        mLatitude = in.readDouble();
+        mLongitude = in.readDouble();
+    }
+
+    /**
+     * @hide
+     */
+    public void writeToParcel(Parcel dest) {
+        dest.writeString(mRcsMessageGlobalId);
+        dest.writeInt(mSubId);
+        dest.writeInt(mMessageStatus);
+        dest.writeLong(mOriginationTimestamp);
+        dest.writeString(mText);
+        dest.writeDouble(mLatitude);
+        dest.writeDouble(mLongitude);
+    }
+}
diff --git a/telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl b/telephony/java/android/telephony/ims/RcsMessageQueryParams.aidl
similarity index 94%
rename from telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl
rename to telephony/java/android/telephony/ims/RcsMessageQueryParams.aidl
index 82d985d..e9cbd9c 100644
--- a/telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl
+++ b/telephony/java/android/telephony/ims/RcsMessageQueryParams.aidl
@@ -17,4 +17,4 @@
 
 package android.telephony.ims;
 
-parcelable RcsThreadIconChangedEvent;
+parcelable RcsMessageQueryParams;
diff --git a/telephony/java/android/telephony/ims/RcsMessageQueryParams.java b/telephony/java/android/telephony/ims/RcsMessageQueryParams.java
new file mode 100644
index 0000000..fae0d97
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsMessageQueryParams.java
@@ -0,0 +1,361 @@
+/*
+ * 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.telephony.ims;
+
+import android.annotation.CheckResult;
+import android.annotation.IntDef;
+import android.annotation.IntRange;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.security.InvalidParameterException;
+
+/**
+ * The parameters to pass into
+ * {@link RcsMessageStore#getRcsMessages(RcsMessageQueryParams)} in order to select a
+ * subset of {@link RcsMessage}s present in the message store.
+ *
+ * @hide - TODO: make public
+ */
+public final class RcsMessageQueryParams implements Parcelable {
+    /**
+     * @hide - not meant for public use
+     */
+    public static final int THREAD_ID_NOT_SET = -1;
+
+    /**
+     * Flag to be used with {@link Builder#setSortProperty(int)} to denote that the results should
+     * be sorted in the same order of {@link RcsMessage}s that got persisted into storage for faster
+     * results.
+     */
+    public static final int SORT_BY_CREATION_ORDER = 0;
+
+    /**
+     * Flag to be used with {@link Builder#setSortProperty(int)} to denote that the results should
+     * be sorted according to the timestamp of {@link RcsMessage#getOriginationTimestamp()}
+     */
+    public static final int SORT_BY_TIMESTAMP = 1;
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({SORT_BY_CREATION_ORDER, SORT_BY_TIMESTAMP})
+    public @interface SortingProperty {
+    }
+
+    /**
+     * Bitmask flag to be used with {@link Builder#setMessageType(int)} to make
+     * {@link RcsMessageStore#getRcsMessages(RcsMessageQueryParams)} return
+     * {@link RcsIncomingMessage}s.
+     */
+    public static final int MESSAGE_TYPE_INCOMING = 0x0001;
+
+    /**
+     * Bitmask flag to be used with {@link Builder#setMessageType(int)} to make
+     * {@link RcsMessageStore#getRcsMessages(RcsMessageQueryParams)} return
+     * {@link RcsOutgoingMessage}s.
+     */
+    public static final int MESSAGE_TYPE_OUTGOING = 0x0002;
+
+    /**
+     * Bitmask flag to be used with {@link Builder#setFileTransferPresence(int)} to make
+     * {@link RcsMessageStore#getRcsMessages(RcsMessageQueryParams)} return {@link RcsMessage}s
+     * that have an {@link RcsFileTransferPart} attached.
+     */
+    public static final int MESSAGES_WITH_FILE_TRANSFERS = 0x0004;
+
+    /**
+     * Bitmask flag to be used with {@link Builder#setFileTransferPresence(int)} to make
+     * {@link RcsMessageStore#getRcsMessages(RcsMessageQueryParams)} return {@link RcsMessage}s
+     * that don't have an {@link RcsFileTransferPart} attached.
+     */
+    public static final int MESSAGES_WITHOUT_FILE_TRANSFERS = 0x0008;
+
+    /**
+     * @hide - not meant for public use
+     */
+    public static final String MESSAGE_QUERY_PARAMETERS_KEY = "message_query_parameters";
+
+    // Whether the result should be filtered against incoming or outgoing messages
+    private int mMessageType;
+    // Whether the result should have file transfer messages attached or not
+    private int mFileTransferPresence;
+    // The SQL "Like" clause to filter messages
+    private String mMessageLike;
+    // The property the messages should be sorted against
+    private @SortingProperty int mSortingProperty;
+    // Whether the messages should be sorted in ascending order
+    private boolean mIsAscending;
+    // The number of results that should be returned with this query
+    private int mLimit;
+    // The thread that the results should be limited to
+    private int mThreadId;
+
+    RcsMessageQueryParams(int messageType, int fileTransferPresence, String messageLike,
+            int threadId, @SortingProperty int sortingProperty, boolean isAscending, int limit) {
+        mMessageType = messageType;
+        mFileTransferPresence = fileTransferPresence;
+        mMessageLike = messageLike;
+        mSortingProperty = sortingProperty;
+        mIsAscending = isAscending;
+        mLimit = limit;
+        mThreadId = threadId;
+    }
+
+    /**
+     * @return Returns the type of {@link RcsMessage}s that this {@link RcsMessageQueryParams}
+     * is set to query for.
+     */
+    public int getMessageType() {
+        return mMessageType;
+    }
+
+    /**
+     * @return Returns whether the result query should return {@link RcsMessage}s with
+     * {@link RcsFileTransferPart}s or not
+     */
+    public int getFileTransferPresence() {
+        return mFileTransferPresence;
+    }
+
+    /**
+     * @return Returns the SQL-inspired "LIKE" clause that will be used to match {@link RcsMessage}s
+     */
+    public String getMessageLike() {
+        return mMessageLike;
+    }
+
+    /**
+     * @return Returns the number of {@link RcsThread}s to be returned from the query. A value of
+     * 0 means there is no set limit.
+     */
+    public int getLimit() {
+        return mLimit;
+    }
+
+    /**
+     * @return Returns the property that will be used to sort the result against.
+     * @see SortingProperty
+     */
+    public @SortingProperty int getSortingProperty() {
+        return mSortingProperty;
+    }
+
+    /**
+     * @return Returns {@code true} if the result set will be sorted in ascending order,
+     * {@code false} if it will be sorted in descending order.
+     */
+    public boolean getSortDirection() {
+        return mIsAscending;
+    }
+
+    /**
+     * This is used in {@link com.android.internal.telephony.ims.RcsMessageStoreController} to get
+     * the thread that the result query should be limited to.
+     *
+     * As we do not expose any sort of integer ID's to public usage, this should be hidden.
+     *
+     * @hide - not meant for public use
+     */
+    public int getThreadId() {
+        return mThreadId;
+    }
+
+    /**
+     * A helper class to build the {@link RcsMessageQueryParams}.
+     */
+    public static class Builder {
+        private @SortingProperty int mSortingProperty;
+        private int mMessageType;
+        private int mFileTransferPresence;
+        private String mMessageLike;
+        private boolean mIsAscending;
+        private int mLimit = 100;
+        private int mThreadId = THREAD_ID_NOT_SET;
+
+        /**
+         * Creates a new builder for {@link RcsMessageQueryParams} to be used in
+         * {@link RcsMessageStore#getRcsMessages(RcsMessageQueryParams)}
+         *
+         */
+        public Builder() {
+            // empty implementation
+        }
+
+        /**
+         * Desired number of threads to be returned from the query. Passing in 0 will return all
+         * existing threads at once. The limit defaults to 100.
+         *
+         * @param limit The number to limit the query result to.
+         * @return The same instance of the builder to chain parameters.
+         * @throws InvalidParameterException If the given limit is negative.
+         */
+        @CheckResult
+        public Builder setResultLimit(@IntRange(from = 0) int limit)
+                throws InvalidParameterException {
+            if (limit < 0) {
+                throw new InvalidParameterException("The query limit must be non-negative");
+            }
+
+            mLimit = limit;
+            return this;
+        }
+
+        /**
+         * Sets the type of messages to be returned from the query.
+         *
+         * @param messageType The type of message to be returned.
+         * @return The same instance of the builder to chain parameters.
+         * @see RcsMessageQueryParams#MESSAGE_TYPE_INCOMING
+         * @see RcsMessageQueryParams#MESSAGE_TYPE_OUTGOING
+         */
+        @CheckResult
+        public Builder setMessageType(int messageType) {
+            mMessageType = messageType;
+            return this;
+        }
+
+        /**
+         * Sets whether file transfer messages should be included in the query result or not.
+         *
+         * @param fileTransferPresence Whether file transfers should be included in the result
+         * @return The same instance of the builder to chain parameters.
+         * @see RcsMessageQueryParams#MESSAGES_WITH_FILE_TRANSFERS
+         * @see RcsMessageQueryParams#MESSAGES_WITHOUT_FILE_TRANSFERS
+         */
+        @CheckResult
+        public Builder setFileTransferPresence(int fileTransferPresence) {
+            mFileTransferPresence = fileTransferPresence;
+            return this;
+        }
+
+        /**
+         * Sets an SQL-inspired "like" clause to match with messages. Using a percent sign ('%')
+         * wildcard matches any sequence of zero or more characters. Using an underscore ('_')
+         * wildcard matches any single character. Not using any wildcards would only perform a
+         * string match. The input string is case-insensitive.
+         *
+         * The input "Wh%" would match messages "who", "where" and "what", while the input "Wh_"
+         * would only match "who"
+         *
+         * @param messageLike The "like" clause for matching {@link RcsMessage}s.
+         * @return The same instance of the builder to chain parameters.
+         */
+        @CheckResult
+        public Builder setMessageLike(String messageLike) {
+            mMessageLike = messageLike;
+            return this;
+        }
+
+        /**
+         * Sets the property where the results should be sorted against. Defaults to
+         * {@link RcsMessageQueryParams.SortingProperty#SORT_BY_CREATION_ORDER}
+         *
+         * @param sortingProperty against which property the results should be sorted
+         * @return The same instance of the builder to chain parameters.
+         */
+        @CheckResult
+        public Builder setSortProperty(@SortingProperty int sortingProperty) {
+            mSortingProperty = sortingProperty;
+            return this;
+        }
+
+        /**
+         * Sets whether the results should be sorted ascending or descending
+         *
+         * @param isAscending whether the results should be sorted ascending
+         * @return The same instance of the builder to chain parameters.
+         */
+        @CheckResult
+        public Builder setSortDirection(boolean isAscending) {
+            mIsAscending = isAscending;
+            return this;
+        }
+
+        /**
+         * Limits the results to the given thread.
+         *
+         * @param thread the {@link RcsThread} that results should be limited to. If set to
+         *               {@code null}, messages on all threads will be queried
+         * @return The same instance of the builder to chain parameters.
+         */
+        @CheckResult
+        public Builder setThread(@Nullable RcsThread thread) {
+            if (thread == null) {
+                mThreadId = THREAD_ID_NOT_SET;
+            } else {
+                mThreadId = thread.getThreadId();
+            }
+            return this;
+        }
+
+        /**
+         * Builds the {@link RcsMessageQueryParams} to use in
+         * {@link RcsMessageStore#getRcsMessages(RcsMessageQueryParams)}
+         *
+         * @return An instance of {@link RcsMessageQueryParams} to use with the message
+         * query.
+         */
+        public RcsMessageQueryParams build() {
+            return new RcsMessageQueryParams(mMessageType, mFileTransferPresence, mMessageLike,
+                    mThreadId, mSortingProperty, mIsAscending, mLimit);
+        }
+    }
+
+    /**
+     * Parcelable boilerplate below.
+     */
+    private RcsMessageQueryParams(Parcel in) {
+        mMessageType = in.readInt();
+        mFileTransferPresence = in.readInt();
+        mMessageLike = in.readString();
+        mSortingProperty = in.readInt();
+        mIsAscending = in.readBoolean();
+        mLimit = in.readInt();
+        mThreadId = in.readInt();
+    }
+
+    public static final Creator<RcsMessageQueryParams> CREATOR =
+            new Creator<RcsMessageQueryParams>() {
+                @Override
+                public RcsMessageQueryParams createFromParcel(Parcel in) {
+                    return new RcsMessageQueryParams(in);
+                }
+
+                @Override
+                public RcsMessageQueryParams[] newArray(int size) {
+                    return new RcsMessageQueryParams[size];
+                }
+            };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mMessageType);
+        dest.writeInt(mFileTransferPresence);
+        dest.writeString(mMessageLike);
+        dest.writeInt(mSortingProperty);
+        dest.writeBoolean(mIsAscending);
+        dest.writeInt(mLimit);
+        dest.writeInt(mThreadId);
+    }
+}
diff --git a/telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl b/telephony/java/android/telephony/ims/RcsMessageQueryResult.aidl
similarity index 94%
copy from telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl
copy to telephony/java/android/telephony/ims/RcsMessageQueryResult.aidl
index 82d985d..a73ba50 100644
--- a/telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl
+++ b/telephony/java/android/telephony/ims/RcsMessageQueryResult.aidl
@@ -17,4 +17,4 @@
 
 package android.telephony.ims;
 
-parcelable RcsThreadIconChangedEvent;
+parcelable RcsMessageQueryResult;
diff --git a/telephony/java/android/telephony/ims/RcsMessageQueryResult.java b/telephony/java/android/telephony/ims/RcsMessageQueryResult.java
new file mode 100644
index 0000000..5adab76
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsMessageQueryResult.java
@@ -0,0 +1,115 @@
+/*
+ * 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.telephony.ims;
+
+import static android.provider.Telephony.RcsColumns.RcsUnifiedMessageColumns.MESSAGE_TYPE_INCOMING;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import com.android.ims.RcsTypeIdPair;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * The result of a {@link RcsMessageStore#getRcsMessages(RcsMessageQueryParams)}
+ * call. This class allows getting the token for querying the next batch of messages in order to
+ * prevent handling large amounts of data at once.
+ *
+ * @hide - TODO: make public
+ */
+public final class RcsMessageQueryResult implements Parcelable {
+    // The token to continue the query to get the next batch of results
+    private RcsQueryContinuationToken mContinuationToken;
+    // The message type and message ID pairs for all the messages in this query result
+    private List<RcsTypeIdPair> mMessageTypeIdPairs;
+
+    /**
+     * Internal constructor for {@link com.android.internal.telephony.ims.RcsMessageStoreController}
+     * to create query results
+     *
+     * @hide
+     */
+    public RcsMessageQueryResult(
+            RcsQueryContinuationToken continuationToken,
+            List<RcsTypeIdPair> messageTypeIdPairs) {
+        mContinuationToken = continuationToken;
+        mMessageTypeIdPairs = messageTypeIdPairs;
+    }
+
+    /**
+     * Returns a token to call
+     * {@link RcsMessageStore#getRcsMessages(RcsQueryContinuationToken)}
+     * to get the next batch of {@link RcsMessage}s.
+     */
+    @Nullable
+    public RcsQueryContinuationToken getContinuationToken() {
+        return mContinuationToken;
+    }
+
+    /**
+     * Returns all the {@link RcsMessage}s in the current query result. Call {@link
+     * RcsMessageStore#getRcsMessages(RcsQueryContinuationToken)} to get the next batch
+     * of {@link RcsMessage}s.
+     */
+    @NonNull
+    public List<RcsMessage> getMessages() {
+        List<RcsMessage> messages = new ArrayList<>();
+        for (RcsTypeIdPair typeIdPair : mMessageTypeIdPairs) {
+            if (typeIdPair.getType() == MESSAGE_TYPE_INCOMING) {
+                messages.add(new RcsIncomingMessage(typeIdPair.getId()));
+            } else {
+                messages.add(new RcsOutgoingMessage(typeIdPair.getId()));
+            }
+        }
+
+        return messages;
+    }
+
+    private RcsMessageQueryResult(Parcel in) {
+        mContinuationToken = in.readParcelable(
+                RcsQueryContinuationToken.class.getClassLoader());
+        in.readTypedList(mMessageTypeIdPairs, RcsTypeIdPair.CREATOR);
+    }
+
+    public static final Creator<RcsMessageQueryResult> CREATOR =
+            new Creator<RcsMessageQueryResult>() {
+                @Override
+                public RcsMessageQueryResult createFromParcel(Parcel in) {
+                    return new RcsMessageQueryResult(in);
+                }
+
+                @Override
+                public RcsMessageQueryResult[] newArray(int size) {
+                    return new RcsMessageQueryResult[size];
+                }
+            };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeParcelable(mContinuationToken, flags);
+        dest.writeTypedList(mMessageTypeIdPairs);
+    }
+}
diff --git a/telephony/java/android/telephony/ims/Rcs1To1Thread.aidl b/telephony/java/android/telephony/ims/RcsMessageSnippet.aidl
similarity index 95%
rename from telephony/java/android/telephony/ims/Rcs1To1Thread.aidl
rename to telephony/java/android/telephony/ims/RcsMessageSnippet.aidl
index 9fdc41d..99b8eb7 100644
--- a/telephony/java/android/telephony/ims/Rcs1To1Thread.aidl
+++ b/telephony/java/android/telephony/ims/RcsMessageSnippet.aidl
@@ -17,4 +17,4 @@
 
 package android.telephony.ims;
 
-parcelable Rcs1To1Thread;
+parcelable RcsMessageSnippet;
diff --git a/telephony/java/android/telephony/ims/RcsMessageSnippet.java b/telephony/java/android/telephony/ims/RcsMessageSnippet.java
new file mode 100644
index 0000000..565bb99
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsMessageSnippet.java
@@ -0,0 +1,98 @@
+/*
+ * 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.telephony.ims;
+
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.telephony.ims.RcsMessage.RcsMessageStatus;
+
+/**
+ * An immutable summary of the latest {@link RcsMessage} on an {@link RcsThread}
+ *
+ * @hide - TODO: make public
+ */
+public final class RcsMessageSnippet implements Parcelable {
+    private final String mText;
+    private final @RcsMessageStatus int mStatus;
+    private final long mTimestamp;
+
+    /**
+     * @hide
+     */
+    public RcsMessageSnippet(String text, @RcsMessageStatus int status, long timestamp) {
+        mText = text;
+        mStatus = status;
+        mTimestamp = timestamp;
+    }
+
+    /**
+     * @return Returns the text of the {@link RcsMessage} with highest origination timestamp value
+     * (i.e. latest) in this thread
+     */
+    @Nullable
+    public String getSnippetText() {
+        return mText;
+    }
+
+    /**
+     * @return Returns the status of the {@link RcsMessage} with highest origination timestamp value
+     * (i.e. latest) in this thread
+     */
+    public @RcsMessageStatus int getSnippetStatus() {
+        return mStatus;
+    }
+
+    /**
+     * @return Returns the timestamp of the {@link RcsMessage} with highest origination timestamp
+     * value (i.e. latest) in this thread
+     */
+    public long getSnippetTimestamp() {
+        return mTimestamp;
+    }
+
+    private RcsMessageSnippet(Parcel in) {
+        mText = in.readString();
+        mStatus = in.readInt();
+        mTimestamp = in.readLong();
+    }
+
+    public static final Creator<RcsMessageSnippet> CREATOR =
+            new Creator<RcsMessageSnippet>() {
+                @Override
+                public RcsMessageSnippet createFromParcel(Parcel in) {
+                    return new RcsMessageSnippet(in);
+                }
+
+                @Override
+                public RcsMessageSnippet[] newArray(int size) {
+                    return new RcsMessageSnippet[size];
+                }
+            };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(mText);
+        dest.writeInt(mStatus);
+        dest.writeLong(mTimestamp);
+    }
+}
diff --git a/telephony/java/android/telephony/ims/RcsMessageStore.java b/telephony/java/android/telephony/ims/RcsMessageStore.java
index 1bf6ffd..eca5ed5 100644
--- a/telephony/java/android/telephony/ims/RcsMessageStore.java
+++ b/telephony/java/android/telephony/ims/RcsMessageStore.java
@@ -16,106 +16,223 @@
 
 package android.telephony.ims;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.WorkerThread;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.telephony.Rlog;
-import android.telephony.ims.aidl.IRcs;
+import android.net.Uri;
+
+import java.util.List;
 
 /**
  * RcsMessageStore is the application interface to RcsProvider and provides access methods to
  * RCS related database tables.
- * @hide - TODO make this public
+ *
+ * @hide - TODO: make public
  */
 public class RcsMessageStore {
-    static final String TAG = "RcsMessageStore";
-
     /**
      * Returns the first chunk of existing {@link RcsThread}s in the common storage.
+     *
      * @param queryParameters Parameters to specify to return a subset of all RcsThreads.
      *                        Passing a value of null will return all threads.
+     * @throws RcsMessageStoreException if the query could not be completed on the storage
      */
     @WorkerThread
-    public RcsThreadQueryResult getRcsThreads(@Nullable RcsThreadQueryParameters queryParameters) {
-        try {
-            IRcs iRcs = IRcs.Stub.asInterface(ServiceManager.getService("ircs"));
-            if (iRcs != null) {
-                return iRcs.getRcsThreads(queryParameters);
-            }
-        } catch (RemoteException re) {
-            Rlog.e(TAG, "RcsMessageStore: Exception happened during getRcsThreads", re);
-        }
-
-        return null;
+    @NonNull
+    public RcsThreadQueryResult getRcsThreads(@Nullable RcsThreadQueryParams queryParameters)
+            throws RcsMessageStoreException {
+        return RcsControllerCall.call(iRcs -> iRcs.getRcsThreads(queryParameters));
     }
 
     /**
      * Returns the next chunk of {@link RcsThread}s in the common storage.
+     *
      * @param continuationToken A token to continue the query to get the next chunk. This is
-     *                          obtained through {@link RcsThreadQueryResult#nextChunkToken}.
+     *                          obtained through {@link RcsThreadQueryResult#getContinuationToken}.
+     * @throws RcsMessageStoreException if the query could not be completed on the storage
      */
     @WorkerThread
-    public RcsThreadQueryResult getRcsThreads(RcsThreadQueryContinuationToken continuationToken) {
-        try {
-            IRcs iRcs = IRcs.Stub.asInterface(ServiceManager.getService("ircs"));
-            if (iRcs != null) {
-                return iRcs.getRcsThreadsWithToken(continuationToken);
-            }
-        } catch (RemoteException re) {
-            Rlog.e(TAG, "RcsMessageStore: Exception happened during getRcsThreads", re);
-        }
+    @NonNull
+    public RcsThreadQueryResult getRcsThreads(@NonNull RcsQueryContinuationToken continuationToken)
+            throws RcsMessageStoreException {
+        return RcsControllerCall.call(iRcs -> iRcs.getRcsThreadsWithToken(continuationToken));
+    }
 
-        return null;
+    /**
+     * Returns the first chunk of existing {@link RcsParticipant}s in the common storage.
+     *
+     * @param queryParameters Parameters to specify to return a subset of all RcsParticipants.
+     *                        Passing a value of null will return all participants.
+     * @throws RcsMessageStoreException if the query could not be completed on the storage
+     */
+    @WorkerThread
+    @NonNull
+    public RcsParticipantQueryResult getRcsParticipants(
+            @Nullable RcsParticipantQueryParams queryParameters)
+            throws RcsMessageStoreException {
+        return RcsControllerCall.call(iRcs -> iRcs.getParticipants(queryParameters));
+    }
+
+    /**
+     * Returns the next chunk of {@link RcsParticipant}s in the common storage.
+     *
+     * @param continuationToken A token to continue the query to get the next chunk. This is
+     *                          obtained through
+     *                          {@link RcsParticipantQueryResult#getContinuationToken}
+     * @throws RcsMessageStoreException if the query could not be completed on the storage
+     */
+    @WorkerThread
+    @NonNull
+    public RcsParticipantQueryResult getRcsParticipants(
+            @NonNull RcsQueryContinuationToken continuationToken)
+            throws RcsMessageStoreException {
+        return RcsControllerCall.call(iRcs -> iRcs.getParticipantsWithToken(continuationToken));
+    }
+
+    /**
+     * Returns the first chunk of existing {@link RcsMessage}s in the common storage.
+     *
+     * @param queryParameters Parameters to specify to return a subset of all RcsMessages.
+     *                        Passing a value of null will return all messages.
+     * @throws RcsMessageStoreException if the query could not be completed on the storage
+     */
+    @WorkerThread
+    @NonNull
+    public RcsMessageQueryResult getRcsMessages(
+            @Nullable RcsMessageQueryParams queryParameters) throws RcsMessageStoreException {
+        return RcsControllerCall.call(iRcs -> iRcs.getMessages(queryParameters));
+    }
+
+    /**
+     * Returns the next chunk of {@link RcsMessage}s in the common storage.
+     *
+     * @param continuationToken A token to continue the query to get the next chunk. This is
+     *                          obtained through {@link RcsMessageQueryResult#getContinuationToken}
+     * @throws RcsMessageStoreException if the query could not be completed on the storage
+     */
+    @WorkerThread
+    @NonNull
+    public RcsMessageQueryResult getRcsMessages(
+            @NonNull RcsQueryContinuationToken continuationToken) throws RcsMessageStoreException {
+        return RcsControllerCall.call(iRcs -> iRcs.getMessagesWithToken(continuationToken));
+    }
+
+    /**
+     * Returns the first chunk of existing {@link RcsEvent}s in the common storage.
+     *
+     * @param queryParameters Parameters to specify to return a subset of all RcsEvents.
+     *                        Passing a value of null will return all events.
+     * @throws RcsMessageStoreException if the query could not be completed on the storage
+     */
+    @WorkerThread
+    @NonNull
+    public RcsEventQueryResult getRcsEvents(
+            @Nullable RcsEventQueryParams queryParameters) throws RcsMessageStoreException {
+        return RcsControllerCall.call(iRcs -> iRcs.getEvents(queryParameters));
+    }
+
+    /**
+     * Returns the next chunk of {@link RcsEvent}s in the common storage.
+     *
+     * @param continuationToken A token to continue the query to get the next chunk. This is
+     *                          obtained through {@link RcsEventQueryResult#getContinuationToken}.
+     * @throws RcsMessageStoreException if the query could not be completed on the storage
+     */
+    @WorkerThread
+    @NonNull
+    public RcsEventQueryResult getRcsEvents(
+            @NonNull RcsQueryContinuationToken continuationToken) throws RcsMessageStoreException {
+        return RcsControllerCall.call(iRcs -> iRcs.getEventsWithToken(continuationToken));
+    }
+
+    /**
+     * Persists an {@link RcsEvent} to common storage.
+     *
+     * @param persistableEvent The {@link RcsEvent} to persist into storage.
+     * @throws RcsMessageStoreException if the query could not be completed on the storage
+     *
+     * @see RcsGroupThreadNameChangedEvent
+     * @see RcsGroupThreadIconChangedEvent
+     * @see RcsGroupThreadParticipantJoinedEvent
+     * @see RcsGroupThreadParticipantLeftEvent
+     * @see RcsParticipantAliasChangedEvent
+     */
+    @WorkerThread
+    @NonNull
+    public void persistRcsEvent(RcsEvent persistableEvent) throws RcsMessageStoreException {
+        persistableEvent.persist();
     }
 
     /**
      * Creates a new 1 to 1 thread with the given participant and persists it in the storage.
+     *
+     * @param recipient The {@link RcsParticipant} that will receive the messages in this thread.
+     * @return The newly created {@link Rcs1To1Thread}
+     * @throws RcsMessageStoreException if the thread could not be persisted in the storage
      */
     @WorkerThread
-    public Rcs1To1Thread createRcs1To1Thread(RcsParticipant recipient) {
-        try {
-            IRcs iRcs = IRcs.Stub.asInterface(ServiceManager.getService("ircs"));
-            if (iRcs != null) {
-                return iRcs.createRcs1To1Thread(recipient);
-            }
-        } catch (RemoteException re) {
-            Rlog.e(TAG, "RcsMessageStore: Exception happened during createRcs1To1Thread", re);
-        }
-
-        return null;
+    @NonNull
+    public Rcs1To1Thread createRcs1To1Thread(@NonNull RcsParticipant recipient)
+            throws RcsMessageStoreException {
+        return new Rcs1To1Thread(
+                RcsControllerCall.call(iRcs -> iRcs.createRcs1To1Thread(recipient.getId())));
     }
 
     /**
-     * Delete the {@link RcsThread} identified by the given threadId.
-     * @param threadId threadId of the thread to be deleted.
+     * Creates a new group thread with the given participants and persists it in the storage.
+     *
+     * @throws RcsMessageStoreException if the thread could not be persisted in the storage
      */
     @WorkerThread
-    public void deleteThread(int threadId) {
-        try {
-            IRcs iRcs = IRcs.Stub.asInterface(ServiceManager.getService("ircs"));
-            if (iRcs != null) {
-                iRcs.deleteThread(threadId);
+    @NonNull
+    public RcsGroupThread createGroupThread(@Nullable List<RcsParticipant> recipients,
+            @Nullable String groupName, @Nullable Uri groupIcon) throws RcsMessageStoreException {
+        int[] recipientIds = null;
+        if (recipients != null) {
+            recipientIds = new int[recipients.size()];
+
+            for (int i = 0; i < recipients.size(); i++) {
+                recipientIds[i] = recipients.get(i).getId();
             }
-        } catch (RemoteException re) {
-            Rlog.e(TAG, "RcsMessageStore: Exception happened during deleteThread", re);
+        }
+
+        int[] finalRecipientIds = recipientIds;
+        return new RcsGroupThread(RcsControllerCall.call(
+                iRcs -> iRcs.createGroupThread(finalRecipientIds, groupName, groupIcon)));
+    }
+
+    /**
+     * Delete the given {@link RcsThread} from the storage.
+     *
+     * @param thread The thread to be deleted.
+     * @throws RcsMessageStoreException if the thread could not be deleted from the storage
+     */
+    @WorkerThread
+    public void deleteThread(@NonNull RcsThread thread) throws RcsMessageStoreException {
+        if (thread == null) {
+            return;
+        }
+
+        boolean isDeleteSucceeded = RcsControllerCall.call(
+                iRcs -> iRcs.deleteThread(thread.getThreadId(), thread.getThreadType()));
+
+        if (!isDeleteSucceeded) {
+            throw new RcsMessageStoreException("Could not delete RcsThread");
         }
     }
 
     /**
      * Creates a new participant and persists it in the storage.
+     *
      * @param canonicalAddress The defining address (e.g. phone number) of the participant.
+     * @param alias            The RCS alias for the participant.
+     * @throws RcsMessageStoreException if the participant could not be created on the storage
      */
-    public RcsParticipant createRcsParticipant(String canonicalAddress) {
-        try {
-            IRcs iRcs = IRcs.Stub.asInterface(ServiceManager.getService("ircs"));
-            if (iRcs != null) {
-                return iRcs.createRcsParticipant(canonicalAddress);
-            }
-        } catch (RemoteException re) {
-            Rlog.e(TAG, "RcsMessageStore: Exception happened during createRcsParticipant", re);
-        }
-
-        return null;
+    @WorkerThread
+    @NonNull
+    public RcsParticipant createRcsParticipant(String canonicalAddress, @Nullable String alias)
+            throws RcsMessageStoreException {
+        return new RcsParticipant(
+                RcsControllerCall.call(iRcs -> iRcs.createRcsParticipant(canonicalAddress, alias)));
     }
 }
diff --git a/telephony/java/android/telephony/ims/RcsMessageStoreException.java b/telephony/java/android/telephony/ims/RcsMessageStoreException.java
new file mode 100644
index 0000000..7c00749
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsMessageStoreException.java
@@ -0,0 +1,35 @@
+/*
+ * 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.telephony.ims;
+
+/**
+ * An exception that happened on {@link RcsMessageStore} or one of the derived storage classes in
+ * {@link android.telephony.ims}
+ *
+ * @hide - TODO: make public
+ */
+public class RcsMessageStoreException extends Exception {
+
+    /**
+     * Constructs an {@link RcsMessageStoreException} with the specified detail message.
+     * @param message The detail message
+     * @see Throwable#getMessage()
+     */
+    public RcsMessageStoreException(String message) {
+        super(message);
+    }
+}
diff --git a/telephony/java/android/telephony/ims/RcsMultiMediaPart.java b/telephony/java/android/telephony/ims/RcsMultiMediaPart.java
deleted file mode 100644
index d295fba..0000000
--- a/telephony/java/android/telephony/ims/RcsMultiMediaPart.java
+++ /dev/null
@@ -1,50 +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 android.telephony.ims;
-
-import android.os.Parcel;
-
-/**
- * A part of a composite {@link RcsMessage} that holds a media that is rendered on the screen
- * (i.e. image, video etc)
- * @hide - TODO(sahinc) make this public
- */
-public class RcsMultiMediaPart extends RcsFileTransferPart {
-    public static final Creator<RcsMultiMediaPart> CREATOR = new Creator<RcsMultiMediaPart>() {
-        @Override
-        public RcsMultiMediaPart createFromParcel(Parcel in) {
-            return new RcsMultiMediaPart(in);
-        }
-
-        @Override
-        public RcsMultiMediaPart[] newArray(int size) {
-            return new RcsMultiMediaPart[size];
-        }
-    };
-
-    protected RcsMultiMediaPart(Parcel in) {
-        super(in);
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-    }
-}
diff --git a/telephony/java/android/telephony/ims/RcsMultimediaPart.aidl b/telephony/java/android/telephony/ims/RcsMultimediaPart.aidl
deleted file mode 100644
index 5992d95..0000000
--- a/telephony/java/android/telephony/ims/RcsMultimediaPart.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- *
- * Copyright 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.telephony.ims;
-
-parcelable RcsMultimediaPart;
diff --git a/telephony/java/android/telephony/ims/RcsOutgoingMessage.aidl b/telephony/java/android/telephony/ims/RcsOutgoingMessage.aidl
deleted file mode 100644
index 6e0c80f..0000000
--- a/telephony/java/android/telephony/ims/RcsOutgoingMessage.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- *
- * Copyright 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.telephony.ims;
-
-parcelable RcsOutgoingMessage;
diff --git a/telephony/java/android/telephony/ims/RcsOutgoingMessage.java b/telephony/java/android/telephony/ims/RcsOutgoingMessage.java
index bfb1611..dfcdee4 100644
--- a/telephony/java/android/telephony/ims/RcsOutgoingMessage.java
+++ b/telephony/java/android/telephony/ims/RcsOutgoingMessage.java
@@ -15,34 +15,53 @@
  */
 package android.telephony.ims;
 
-import android.os.Parcel;
+import android.annotation.NonNull;
+import android.annotation.WorkerThread;
+
+import java.util.ArrayList;
+import java.util.List;
 
 /**
  * This is a single instance of a message sent over RCS.
- * @hide - TODO(sahinc) make this public
+ *
+ * @hide - TODO: make public
  */
 public class RcsOutgoingMessage extends RcsMessage {
-    public static final Creator<RcsOutgoingMessage> CREATOR = new Creator<RcsOutgoingMessage>() {
-        @Override
-        public RcsOutgoingMessage createFromParcel(Parcel in) {
-            return new RcsOutgoingMessage(in);
-        }
-
-        @Override
-        public RcsOutgoingMessage[] newArray(int size) {
-            return new RcsOutgoingMessage[size];
-        }
-    };
-
-    protected RcsOutgoingMessage(Parcel in) {
+    RcsOutgoingMessage(int id) {
+        super(id);
     }
 
-    @Override
-    public int describeContents() {
-        return 0;
+    /**
+     * @return Returns the {@link RcsOutgoingMessageDelivery}s associated with this message. Please
+     * note that the deliveries returned for the {@link RcsOutgoingMessage} may not always match the
+     * {@link RcsParticipant}s on the {@link RcsGroupThread} as the group recipients may have
+     * changed.
+     * @throws RcsMessageStoreException if the outgoing deliveries could not be read from storage.
+     */
+    @NonNull
+    @WorkerThread
+    public List<RcsOutgoingMessageDelivery> getOutgoingDeliveries()
+            throws RcsMessageStoreException {
+        int[] deliveryParticipants;
+        List<RcsOutgoingMessageDelivery> messageDeliveries = new ArrayList<>();
+
+        deliveryParticipants = RcsControllerCall.call(
+                iRcs -> iRcs.getMessageRecipients(mId));
+
+        if (deliveryParticipants != null) {
+            for (Integer deliveryParticipant : deliveryParticipants) {
+                messageDeliveries.add(new RcsOutgoingMessageDelivery(deliveryParticipant, mId));
+            }
+        }
+
+        return messageDeliveries;
     }
 
+    /**
+     * @return Returns {@code false} as this is not an incoming message.
+     */
     @Override
-    public void writeToParcel(Parcel dest, int flags) {
+    public boolean isIncoming() {
+        return false;
     }
 }
diff --git a/telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl b/telephony/java/android/telephony/ims/RcsOutgoingMessageCreationParams.aidl
similarity index 93%
copy from telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl
copy to telephony/java/android/telephony/ims/RcsOutgoingMessageCreationParams.aidl
index 82d985d..0c38d9f 100644
--- a/telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl
+++ b/telephony/java/android/telephony/ims/RcsOutgoingMessageCreationParams.aidl
@@ -17,4 +17,4 @@
 
 package android.telephony.ims;
 
-parcelable RcsThreadIconChangedEvent;
+parcelable RcsOutgoingMessageCreationParams;
diff --git a/telephony/java/android/telephony/ims/RcsOutgoingMessageCreationParams.java b/telephony/java/android/telephony/ims/RcsOutgoingMessageCreationParams.java
new file mode 100644
index 0000000..ca466e8
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsOutgoingMessageCreationParams.java
@@ -0,0 +1,89 @@
+/*
+ * 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.telephony.ims;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * {@link RcsOutgoingMessageCreationParams} is a collection of parameters that should be passed
+ * into {@link RcsThread#addOutgoingMessage(RcsOutgoingMessageCreationParams)} to generate an
+ * {@link RcsOutgoingMessage} on that {@link RcsThread}
+ *
+ * @hide - TODO: make public
+ */
+public final class RcsOutgoingMessageCreationParams extends RcsMessageCreationParams
+        implements Parcelable {
+    /**
+     * A builder to instantiate and persist an {@link RcsOutgoingMessage}
+     */
+    public static class Builder extends RcsMessageCreationParams.Builder {
+
+        /**
+         * Creates a new {@link Builder} to create an instance of
+         * {@link RcsOutgoingMessageCreationParams}.
+         *
+         * @param originationTimestamp The timestamp of {@link RcsMessage} creation. The origination
+         *                             timestamp value in milliseconds passed after midnight,
+         *                             January 1, 1970 UTC
+         * @param subscriptionId The subscription ID that was used to send or receive this
+         *                       {@link RcsMessage}
+         * @see android.telephony.SubscriptionInfo#getSubscriptionId()
+         */
+        public Builder(long originationTimestamp, int subscriptionId) {
+            super(originationTimestamp, subscriptionId);
+        }
+
+        /**
+         * Creates configuration parameters for a new message.
+         */
+        public RcsOutgoingMessageCreationParams build() {
+            return new RcsOutgoingMessageCreationParams(this);
+        }
+    }
+
+    private RcsOutgoingMessageCreationParams(Builder builder) {
+        super(builder);
+    }
+
+    private RcsOutgoingMessageCreationParams(Parcel in) {
+        super(in);
+    }
+
+    public static final Creator<RcsOutgoingMessageCreationParams> CREATOR =
+            new Creator<RcsOutgoingMessageCreationParams>() {
+                @Override
+                public RcsOutgoingMessageCreationParams createFromParcel(Parcel in) {
+                    return new RcsOutgoingMessageCreationParams(in);
+                }
+
+                @Override
+                public RcsOutgoingMessageCreationParams[] newArray(int size) {
+                    return new RcsOutgoingMessageCreationParams[size];
+                }
+            };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        super.writeToParcel(dest);
+    }
+}
diff --git a/telephony/java/android/telephony/ims/RcsOutgoingMessageDelivery.java b/telephony/java/android/telephony/ims/RcsOutgoingMessageDelivery.java
new file mode 100644
index 0000000..5a3062a
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsOutgoingMessageDelivery.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2018 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.telephony.ims;
+
+import android.annotation.NonNull;
+import android.annotation.WorkerThread;
+
+/**
+ * This class holds the delivery information of an {@link RcsOutgoingMessage} for each
+ * {@link RcsParticipant} that the message was intended for.
+ *
+ * @hide - TODO: make public
+ */
+public class RcsOutgoingMessageDelivery {
+    // The participant that this delivery is intended for
+    private final int mRecipientId;
+    // The message this delivery is associated with
+    private final int mRcsOutgoingMessageId;
+
+    /**
+     * Constructor to be used with RcsOutgoingMessage.getDelivery()
+     *
+     * @hide
+     */
+    RcsOutgoingMessageDelivery(int recipientId, int messageId) {
+        mRecipientId = recipientId;
+        mRcsOutgoingMessageId = messageId;
+    }
+
+    /**
+     * Sets the delivery time of this outgoing delivery and persists into storage.
+     *
+     * @param deliveredTimestamp The timestamp to set to delivery. It is defined as milliseconds
+     *                           passed after midnight, January 1, 1970 UTC
+     * @throws RcsMessageStoreException if the value could not be persisted into storage
+     */
+    @WorkerThread
+    public void setDeliveredTimestamp(long deliveredTimestamp) throws RcsMessageStoreException {
+        RcsControllerCall.callWithNoReturn(iRcs -> iRcs.setOutgoingDeliveryDeliveredTimestamp(
+                mRcsOutgoingMessageId, mRecipientId, deliveredTimestamp));
+    }
+
+    /**
+     * @return Returns the delivered timestamp of the associated message to the associated
+     * participant. Timestamp is defined as milliseconds passed after midnight, January 1, 1970 UTC.
+     * Returns 0 if the {@link RcsOutgoingMessage} is not delivered yet.
+     * @throws RcsMessageStoreException if the value could not be read from the storage
+     */
+    @WorkerThread
+    public long getDeliveredTimestamp() throws RcsMessageStoreException {
+        return RcsControllerCall.call(iRcs -> iRcs.getOutgoingDeliveryDeliveredTimestamp(
+                mRcsOutgoingMessageId, mRecipientId));
+    }
+
+    /**
+     * Sets the seen time of this outgoing delivery and persists into storage.
+     *
+     * @param seenTimestamp The timestamp to set to delivery. It is defined as milliseconds
+     *                      passed after midnight, January 1, 1970 UTC
+     * @throws RcsMessageStoreException if the value could not be persisted into storage
+     */
+    @WorkerThread
+    public void setSeenTimestamp(long seenTimestamp) throws RcsMessageStoreException {
+        RcsControllerCall.callWithNoReturn(iRcs -> iRcs.setOutgoingDeliverySeenTimestamp(
+                mRcsOutgoingMessageId, mRecipientId, seenTimestamp));
+    }
+
+    /**
+     * @return Returns the seen timestamp of the associated message by the associated
+     * participant. Timestamp is defined as milliseconds passed after midnight, January 1, 1970 UTC.
+     * Returns 0 if the {@link RcsOutgoingMessage} is not seen yet.
+     * @throws RcsMessageStoreException if the value could not be read from the storage
+     */
+    @WorkerThread
+    public long getSeenTimestamp() throws RcsMessageStoreException {
+        return RcsControllerCall.call(
+                iRcs -> iRcs.getOutgoingDeliverySeenTimestamp(mRcsOutgoingMessageId, mRecipientId));
+    }
+
+    /**
+     * Sets the status of this outgoing delivery and persists into storage.
+     *
+     * @param status The status of the associated {@link RcsMessage}s delivery to the associated
+     *               {@link RcsParticipant}
+     * @throws RcsMessageStoreException if the value could not be persisted into storage
+     */
+    @WorkerThread
+    public void setStatus(@RcsMessage.RcsMessageStatus int status) throws RcsMessageStoreException {
+        RcsControllerCall.callWithNoReturn(iRcs -> iRcs.setOutgoingDeliveryStatus(
+                mRcsOutgoingMessageId, mRecipientId, status));
+    }
+
+    /**
+     * @return Returns the status of this outgoing delivery.
+     * @throws RcsMessageStoreException if the value could not be read from the storage
+     */
+    @WorkerThread
+    public @RcsMessage.RcsMessageStatus int getStatus() throws RcsMessageStoreException {
+        return RcsControllerCall.call(
+                iRcs -> iRcs.getOutgoingDeliveryStatus(mRcsOutgoingMessageId, mRecipientId));
+    }
+
+    /**
+     * @return Returns the recipient associated with this delivery.
+     */
+    @NonNull
+    public RcsParticipant getRecipient() {
+        return new RcsParticipant(mRecipientId);
+    }
+
+    /**
+     * @return Returns the {@link RcsOutgoingMessage} associated with this delivery.
+     */
+    @NonNull
+    public RcsOutgoingMessage getMessage() {
+        return new RcsOutgoingMessage(mRcsOutgoingMessageId);
+    }
+}
diff --git a/telephony/java/android/telephony/ims/RcsPart.java b/telephony/java/android/telephony/ims/RcsPart.java
deleted file mode 100644
index da50173..0000000
--- a/telephony/java/android/telephony/ims/RcsPart.java
+++ /dev/null
@@ -1,25 +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 android.telephony.ims;
-
-import android.os.Parcelable;
-
-/**
- * A part of a composite {@link RcsMessage}.
- * @hide - TODO(sahinc) make this public
- */
-public abstract class RcsPart implements Parcelable {
-}
diff --git a/telephony/java/android/telephony/ims/RcsParticipant.aidl b/telephony/java/android/telephony/ims/RcsParticipant.aidl
deleted file mode 100644
index 1c44363..0000000
--- a/telephony/java/android/telephony/ims/RcsParticipant.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- *
- * Copyright 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.telephony.ims;
-
-parcelable RcsParticipant;
diff --git a/telephony/java/android/telephony/ims/RcsParticipant.java b/telephony/java/android/telephony/ims/RcsParticipant.java
index f678ec7..37b827b 100644
--- a/telephony/java/android/telephony/ims/RcsParticipant.java
+++ b/telephony/java/android/telephony/ims/RcsParticipant.java
@@ -15,33 +15,17 @@
  */
 package android.telephony.ims;
 
-import static android.telephony.ims.RcsMessageStore.TAG;
-
-import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.WorkerThread;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.telephony.Rlog;
-import android.telephony.ims.aidl.IRcs;
-import android.text.TextUtils;
-
-import com.android.internal.util.Preconditions;
 
 /**
  * RcsParticipant is an RCS capable contact that can participate in {@link RcsThread}s.
- * @hide - TODO(sahinc) make this public
+ *
+ * @hide - TODO: make public
  */
-public class RcsParticipant implements Parcelable {
+public class RcsParticipant {
     // The row ID of this participant in the database
     private int mId;
-    // The phone number of this participant
-    private String mCanonicalAddress;
-    // The RCS alias of this participant. This is different than the name of the contact in the
-    // Contacts app - i.e. RCS protocol allows users to define aliases for themselves that doesn't
-    // require other users to add them as contacts and give them a name.
-    private String mAlias;
 
     /**
      * Constructor for {@link com.android.internal.telephony.ims.RcsMessageStoreController}
@@ -49,68 +33,87 @@
      *
      * @hide
      */
-    public RcsParticipant(int id, @NonNull String canonicalAddress) {
+    public RcsParticipant(int id) {
         mId = id;
-        mCanonicalAddress = canonicalAddress;
     }
 
     /**
-     * @return Returns the canonical address (i.e. normalized phone number) for this participant
+     * @return Returns the canonical address (i.e. normalized phone number) for this
+     * {@link RcsParticipant}
+     * @throws RcsMessageStoreException if the value could not be read from the storage
      */
-    public String getCanonicalAddress() {
-        return mCanonicalAddress;
+    @Nullable
+    @WorkerThread
+    public String getCanonicalAddress() throws RcsMessageStoreException {
+        return RcsControllerCall.call(iRcs -> iRcs.getRcsParticipantCanonicalAddress(mId));
     }
 
     /**
-     * Sets the canonical address for this participant and updates it in storage.
-     * @param canonicalAddress the canonical address to update to.
+     * @return Returns the alias for this {@link RcsParticipant}. Alias is usually the real name of
+     * the person themselves. Please see US5-15 - GSMA RCC.71 (RCS Universal Profile Service
+     * Definition Document)
+     * @throws RcsMessageStoreException if the value could not be read from the storage
+     */
+    @Nullable
+    @WorkerThread
+    public String getAlias() throws RcsMessageStoreException {
+        return RcsControllerCall.call(iRcs -> iRcs.getRcsParticipantAlias(mId));
+    }
+
+    /**
+     * Sets the alias for this {@link RcsParticipant} and persists it in storage. Alias is usually
+     * the real name of the person themselves. Please see US5-15 - GSMA RCC.71 (RCS Universal
+     * Profile Service Definition Document)
+     *
+     * @param alias The alias to set to.
+     * @throws RcsMessageStoreException if the value could not be persisted into storage
      */
     @WorkerThread
-    public void setCanonicalAddress(@NonNull String canonicalAddress) {
-        Preconditions.checkNotNull(canonicalAddress);
-        if (canonicalAddress.equals(mCanonicalAddress)) {
-            return;
-        }
-
-        mCanonicalAddress = canonicalAddress;
-
-        try {
-            IRcs iRcs = IRcs.Stub.asInterface(ServiceManager.getService("ircs"));
-            if (iRcs != null) {
-                iRcs.updateRcsParticipantCanonicalAddress(mId, mCanonicalAddress);
-            }
-        } catch (RemoteException re) {
-            Rlog.e(TAG, "RcsParticipant: Exception happened during setCanonicalAddress", re);
-        }
+    public void setAlias(String alias) throws RcsMessageStoreException {
+        RcsControllerCall.callWithNoReturn(iRcs -> iRcs.setRcsParticipantAlias(mId, alias));
     }
 
     /**
-     * @return Returns the alias for this participant. Alias is usually the real name of the person
-     * themselves.
+     * @return Returns the contact ID for this {@link RcsParticipant}. Contact ID is a unique ID for
+     * an {@link RcsParticipant} that is RCS provisioned. Please see 4.4.5 - GSMA RCC.53 (RCS Device
+     * API 1.6 Specification)
+     * @throws RcsMessageStoreException if the value could not be read from the storage
      */
-    public String getAlias() {
-        return mAlias;
+    @Nullable
+    @WorkerThread
+    public String getContactId() throws RcsMessageStoreException {
+        return RcsControllerCall.call(iRcs -> iRcs.getRcsParticipantContactId(mId));
     }
 
     /**
-     * Sets the alias for this participant and persists it in storage. Alias is usually the real
-     * name of the person themselves.
+     * Sets the contact ID for this {@link RcsParticipant}. Contact ID is a unique ID for
+     * an {@link RcsParticipant} that is RCS provisioned. Please see 4.4.5 - GSMA RCC.53 (RCS Device
+     * API 1.6 Specification)
+     *
+     * @param contactId The contact ID to set to.
+     * @throws RcsMessageStoreException if the value could not be persisted into storage
      */
     @WorkerThread
-    public void setAlias(String alias) {
-        if (TextUtils.equals(mAlias, alias)) {
-            return;
-        }
-        mAlias = alias;
+    public void setContactId(String contactId) throws RcsMessageStoreException {
+        RcsControllerCall.callWithNoReturn(iRcs -> iRcs.setRcsParticipantContactId(mId, contactId));
+    }
 
-        try {
-            IRcs iRcs = IRcs.Stub.asInterface(ServiceManager.getService("ircs"));
-            if (iRcs != null) {
-                iRcs.updateRcsParticipantAlias(mId, mAlias);
-            }
-        } catch (RemoteException re) {
-            Rlog.e(TAG, "RcsParticipant: Exception happened during setCanonicalAddress", re);
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
         }
+        if (!(obj instanceof RcsParticipant)) {
+            return false;
+        }
+        RcsParticipant other = (RcsParticipant) obj;
+
+        return mId == other.mId;
+    }
+
+    @Override
+    public int hashCode() {
+        return mId;
     }
 
     /**
@@ -121,34 +124,4 @@
     public int getId() {
         return mId;
     }
-
-    public static final Creator<RcsParticipant> CREATOR = new Creator<RcsParticipant>() {
-        @Override
-        public RcsParticipant createFromParcel(Parcel in) {
-            return new RcsParticipant(in);
-        }
-
-        @Override
-        public RcsParticipant[] newArray(int size) {
-            return new RcsParticipant[size];
-        }
-    };
-
-    protected RcsParticipant(Parcel in) {
-        mId = in.readInt();
-        mCanonicalAddress = in.readString();
-        mAlias = in.readString();
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeInt(mId);
-        dest.writeString(mCanonicalAddress);
-        dest.writeString(mAlias);
-    }
 }
diff --git a/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEvent.java b/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEvent.java
index b9ca5a8..aa278b3 100644
--- a/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEvent.java
+++ b/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEvent.java
@@ -15,27 +15,94 @@
  */
 package android.telephony.ims;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.os.Parcel;
+import android.os.Parcelable;
 
 /**
- * An event that indicates an {@link RcsParticipant}'s alias was changed.
- * @hide - TODO(sahinc) make this public
+ * An event that indicates an {@link RcsParticipant}'s alias was changed. Please see US18-2 - GSMA
+ * RCC.71 (RCS Universal Profile Service Definition Document)
+ *
+ * @hide - TODO: make public
  */
-public class RcsParticipantAliasChangedEvent extends RcsParticipantEvent {
+public final class RcsParticipantAliasChangedEvent extends RcsEvent implements Parcelable {
+    // The ID of the participant that changed their alias
+    private final int mParticipantId;
+    // The new alias of the above participant
+    private final String mNewAlias;
+
+    /**
+     * Creates a new {@link RcsParticipantAliasChangedEvent}. This event is not persisted into
+     * storage until {@link RcsMessageStore#persistRcsEvent(RcsEvent)} is called.
+     *
+     * @param timestamp The timestamp of when this event happened, in milliseconds passed after
+     *                  midnight, January 1st, 1970 UTC
+     * @param participant The {@link RcsParticipant} that got their alias changed
+     * @param newAlias The new alias the {@link RcsParticipant} has.
+     * @see RcsMessageStore#persistRcsEvent(RcsEvent)
+     */
+    public RcsParticipantAliasChangedEvent(long timestamp, @NonNull RcsParticipant participant,
+            @Nullable String newAlias) {
+        super(timestamp);
+        mParticipantId = participant.getId();
+        mNewAlias = newAlias;
+    }
+
+    /**
+     * @hide - internal constructor for queries
+     */
+    public RcsParticipantAliasChangedEvent(long timestamp, int participantId,
+            @Nullable String newAlias) {
+        super(timestamp);
+        mParticipantId = participantId;
+        mNewAlias = newAlias;
+    }
+
+    /**
+     * @return Returns the {@link RcsParticipant} whose alias was changed.
+     */
+    @NonNull
+    public RcsParticipant getParticipantId() {
+        return new RcsParticipant(mParticipantId);
+    }
+
+    /**
+     * @return Returns the alias of the associated {@link RcsParticipant} after this event happened
+     */
+    @Nullable
+    public String getNewAlias() {
+        return mNewAlias;
+    }
+
+    /**
+     * Persists the event to the data store.
+     *
+     * @hide - not meant for public use.
+     */
+    @Override
+    public void persist() throws RcsMessageStoreException {
+        RcsControllerCall.call(iRcs -> iRcs.createParticipantAliasChangedEvent(
+                getTimestamp(), getParticipantId().getId(), getNewAlias()));
+    }
+
     public static final Creator<RcsParticipantAliasChangedEvent> CREATOR =
             new Creator<RcsParticipantAliasChangedEvent>() {
-        @Override
-        public RcsParticipantAliasChangedEvent createFromParcel(Parcel in) {
-            return new RcsParticipantAliasChangedEvent(in);
-        }
+                @Override
+                public RcsParticipantAliasChangedEvent createFromParcel(Parcel in) {
+                    return new RcsParticipantAliasChangedEvent(in);
+                }
 
-        @Override
-        public RcsParticipantAliasChangedEvent[] newArray(int size) {
-            return new RcsParticipantAliasChangedEvent[size];
-        }
-    };
+                @Override
+                public RcsParticipantAliasChangedEvent[] newArray(int size) {
+                    return new RcsParticipantAliasChangedEvent[size];
+                }
+            };
 
-    protected RcsParticipantAliasChangedEvent(Parcel in) {
+    private RcsParticipantAliasChangedEvent(Parcel in) {
+        super(in);
+        mNewAlias = in.readString();
+        mParticipantId = in.readInt();
     }
 
     @Override
@@ -45,5 +112,8 @@
 
     @Override
     public void writeToParcel(Parcel dest, int flags) {
+        super.writeToParcel(dest, flags);
+        dest.writeString(mNewAlias);
+        dest.writeInt(mParticipantId);
     }
 }
diff --git a/telephony/java/android/telephony/ims/RcsParticipantEvent.aidl b/telephony/java/android/telephony/ims/RcsParticipantEvent.aidl
deleted file mode 100644
index c0a7789..0000000
--- a/telephony/java/android/telephony/ims/RcsParticipantEvent.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- *
- * Copyright 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.telephony.ims;
-
-parcelable RcsParticipantEvent;
diff --git a/telephony/java/android/telephony/ims/RcsParticipantEvent.java b/telephony/java/android/telephony/ims/RcsParticipantEvent.java
deleted file mode 100644
index 371b8b7..0000000
--- a/telephony/java/android/telephony/ims/RcsParticipantEvent.java
+++ /dev/null
@@ -1,25 +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 android.telephony.ims;
-
-import android.os.Parcelable;
-
-/**
- * An event that is associated with an {@link RcsParticipant}
- * @hide - TODO(sahinc) make this public
- */
-public abstract class RcsParticipantEvent implements Parcelable {
-}
diff --git a/telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl b/telephony/java/android/telephony/ims/RcsParticipantQueryParams.aidl
similarity index 94%
copy from telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl
copy to telephony/java/android/telephony/ims/RcsParticipantQueryParams.aidl
index 82d985d..b7c0f93 100644
--- a/telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl
+++ b/telephony/java/android/telephony/ims/RcsParticipantQueryParams.aidl
@@ -17,4 +17,4 @@
 
 package android.telephony.ims;
 
-parcelable RcsThreadIconChangedEvent;
+parcelable RcsParticipantQueryParams;
diff --git a/telephony/java/android/telephony/ims/RcsParticipantQueryParams.java b/telephony/java/android/telephony/ims/RcsParticipantQueryParams.java
new file mode 100644
index 0000000..57c67fa
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsParticipantQueryParams.java
@@ -0,0 +1,310 @@
+/*
+ * 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.telephony.ims;
+
+import android.annotation.CheckResult;
+import android.annotation.IntDef;
+import android.annotation.IntRange;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.security.InvalidParameterException;
+
+/**
+ * The parameters to pass into
+ * {@link RcsMessageStore#getRcsParticipants(RcsParticipantQueryParams)} in order to select a
+ * subset of {@link RcsThread}s present in the message store.
+ *
+ * @hide - TODO: make public
+ */
+public final class RcsParticipantQueryParams implements Parcelable {
+    /**
+     * Flag to set with {@link Builder#setSortProperty(int)} to sort the results in the order of
+     * creation time for faster query results
+     */
+    public static final int SORT_BY_CREATION_ORDER = 0;
+
+    /**
+     * Flag to set with {@link Builder#setSortProperty(int)} to sort depending on the
+     * {@link RcsParticipant} aliases
+     */
+    public static final int SORT_BY_ALIAS = 1;
+
+    /**
+     * Flag to set with {@link Builder#setSortProperty(int)} to sort depending on the
+     * {@link RcsParticipant} canonical addresses
+     */
+    public static final int SORT_BY_CANONICAL_ADDRESS = 2;
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({SORT_BY_CREATION_ORDER, SORT_BY_ALIAS, SORT_BY_CANONICAL_ADDRESS})
+    public @interface SortingProperty {
+    }
+
+    // The SQL "like" statement to filter against participant aliases
+    private String mAliasLike;
+    // The SQL "like" statement to filter against canonical addresses
+    private String mCanonicalAddressLike;
+    // The property to sort the result against
+    private @SortingProperty int mSortingProperty;
+    // Whether to sort the result in ascending order
+    private boolean mIsAscending;
+    // The number of results to be returned from the query
+    private int mLimit;
+    // Used to limit the results to participants of a single thread
+    private int mThreadId;
+
+    /**
+     * @hide
+     */
+    public static final String PARTICIPANT_QUERY_PARAMETERS_KEY = "participant_query_parameters";
+
+    RcsParticipantQueryParams(int rcsThreadId, String aliasLike, String canonicalAddressLike,
+            @SortingProperty int sortingProperty, boolean isAscending,
+            int limit) {
+        mThreadId = rcsThreadId;
+        mAliasLike = aliasLike;
+        mCanonicalAddressLike = canonicalAddressLike;
+        mSortingProperty = sortingProperty;
+        mIsAscending = isAscending;
+        mLimit = limit;
+    }
+
+    /**
+     * This is used in {@link com.android.internal.telephony.ims.RcsMessageStoreController} to get
+     * the thread that the result query should be limited to.
+     *
+     * As we do not expose any sort of integer ID's to public usage, this should be hidden.
+     *
+     * @hide - not meant for public use
+     */
+    public int getThreadId() {
+        return mThreadId;
+    }
+
+    /**
+     * @return Returns the SQL-inspired "LIKE" clause that will be used to match
+     * {@link RcsParticipant}s with respect to their aliases
+     *
+     * @see RcsParticipant#getAlias()
+     */
+    public String getAliasLike() {
+        return mAliasLike;
+    }
+
+    /**
+     * @return Returns the SQL-inspired "LIKE" clause that will be used to match
+     * {@link RcsParticipant}s with respect to their canonical addresses.
+     *
+     * @see RcsParticipant#getCanonicalAddress()
+     */
+    public String getCanonicalAddressLike() {
+        return mCanonicalAddressLike;
+    }
+
+    /**
+     * @return Returns the number of {@link RcsParticipant}s to be returned from the query. A value
+     * of 0 means there is no set limit.
+     */
+    public int getLimit() {
+        return mLimit;
+    }
+
+    /**
+     * @return Returns the property that will be used to sort the result against.
+     * @see SortingProperty
+     */
+    public int getSortingProperty() {
+        return mSortingProperty;
+    }
+
+    /**
+     * @return Returns {@code true} if the result set will be sorted in ascending order,
+     * {@code false} if it will be sorted in descending order.
+     */
+    public boolean getSortDirection() {
+        return mIsAscending;
+    }
+
+    /**
+     * A helper class to build the {@link RcsParticipantQueryParams}.
+     */
+    public static class Builder {
+        private String mAliasLike;
+        private String mCanonicalAddressLike;
+        private @SortingProperty int mSortingProperty;
+        private boolean mIsAscending;
+        private int mLimit = 100;
+        private int mThreadId;
+
+        /**
+         * Creates a new builder for {@link RcsParticipantQueryParams} to be used in
+         * {@link RcsMessageStore#getRcsParticipants(RcsParticipantQueryParams)}
+         */
+        public Builder() {
+            // empty implementation
+        }
+
+        /**
+         * Limits the resulting {@link RcsParticipant}s to only the given {@link RcsThread}
+         *
+         * @param rcsThread The thread that the participants should be searched in.
+         * @return The same {@link Builder} to chain methods.
+         */
+        @CheckResult
+        public Builder setThread(RcsThread rcsThread) {
+            mThreadId = rcsThread.getThreadId();
+            return this;
+        }
+
+        /**
+         * Sets an SQL-inspired "like" clause to match with participant aliases. Using a percent
+         * sign ('%') wildcard matches any sequence of zero or more characters. Using an underscore
+         * ('_') wildcard matches any single character. Not using any wildcards would only perform a
+         * string match.The input string is case-insensitive.
+         *
+         * The input "An%e" would match {@link RcsParticipant}s with names Anne, Annie, Antonie,
+         * while the input "An_e" would only match Anne.
+         *
+         * @param likeClause The like clause to use for matching {@link RcsParticipant} aliases.
+         * @return The same {@link Builder} to chain methods
+         */
+        @CheckResult
+        public Builder setAliasLike(String likeClause) {
+            mAliasLike = likeClause;
+            return this;
+        }
+
+        /**
+         * Sets an SQL-inspired "like" clause to match with participant addresses. Using a percent
+         * sign ('%') wildcard matches any sequence of zero or more characters. Using an underscore
+         * ('_') wildcard matches any single character. Not using any wildcards would only perform a
+         * string match. The input string is case-insensitive.
+         *
+         * The input "+999%111" would match {@link RcsParticipant}s with addresses like "+9995111"
+         * or "+99955555111", while the input "+999_111" would only match "+9995111".
+         *
+         * @param likeClause The like clause to use for matching {@link RcsParticipant} canonical
+         *                   addresses.
+         * @return The same {@link Builder} to chain methods
+         */
+        @CheckResult
+        public Builder setCanonicalAddressLike(String likeClause) {
+            mCanonicalAddressLike = likeClause;
+            return this;
+        }
+
+        /**
+         * Desired number of threads to be returned from the query. Passing in 0 will return all
+         * existing threads at once. The limit defaults to 100.
+         *
+         * @param limit The number to limit the query result to.
+         * @return The same instance of the builder to chain parameters.
+         * @throws InvalidParameterException If the given limit is negative.
+         */
+        @CheckResult
+        public Builder setResultLimit(@IntRange(from = 0) int limit)
+                throws InvalidParameterException {
+            if (limit < 0) {
+                throw new InvalidParameterException("The query limit must be non-negative");
+            }
+
+            mLimit = limit;
+            return this;
+        }
+
+        /**
+         * Sets the property where the results should be sorted against. Defaults to
+         * {@link RcsParticipantQueryParams.SortingProperty#SORT_BY_CREATION_ORDER}
+         *
+         * @param sortingProperty against which property the results should be sorted
+         * @return The same instance of the builder to chain parameters.
+         */
+        @CheckResult
+        public Builder setSortProperty(@SortingProperty int sortingProperty) {
+            mSortingProperty = sortingProperty;
+            return this;
+        }
+
+        /**
+         * Sets whether the results should be sorted ascending or descending
+         *
+         * @param isAscending whether the results should be sorted ascending
+         * @return The same instance of the builder to chain parameters.
+         */
+        @CheckResult
+        public Builder setSortDirection(boolean isAscending) {
+            mIsAscending = isAscending;
+            return this;
+        }
+
+        /**
+         * Builds the {@link RcsParticipantQueryParams} to use in
+         * {@link RcsMessageStore#getRcsParticipants(RcsParticipantQueryParams)}
+         *
+         * @return An instance of {@link RcsParticipantQueryParams} to use with the participant
+         * query.
+         */
+        public RcsParticipantQueryParams build() {
+            return new RcsParticipantQueryParams(mThreadId, mAliasLike, mCanonicalAddressLike,
+                    mSortingProperty, mIsAscending, mLimit);
+        }
+    }
+
+    /**
+     * Parcelable boilerplate below.
+     */
+    private RcsParticipantQueryParams(Parcel in) {
+        mAliasLike = in.readString();
+        mCanonicalAddressLike = in.readString();
+        mSortingProperty = in.readInt();
+        mIsAscending = in.readByte() == 1;
+        mLimit = in.readInt();
+        mThreadId = in.readInt();
+    }
+
+    public static final Creator<RcsParticipantQueryParams> CREATOR =
+            new Creator<RcsParticipantQueryParams>() {
+                @Override
+                public RcsParticipantQueryParams createFromParcel(Parcel in) {
+                    return new RcsParticipantQueryParams(in);
+                }
+
+                @Override
+                public RcsParticipantQueryParams[] newArray(int size) {
+                    return new RcsParticipantQueryParams[size];
+                }
+            };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeString(mAliasLike);
+        dest.writeString(mCanonicalAddressLike);
+        dest.writeInt(mSortingProperty);
+        dest.writeByte((byte) (mIsAscending ? 1 : 0));
+        dest.writeInt(mLimit);
+        dest.writeInt(mThreadId);
+    }
+
+}
diff --git a/telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl b/telephony/java/android/telephony/ims/RcsParticipantQueryResult.aidl
similarity index 94%
copy from telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl
copy to telephony/java/android/telephony/ims/RcsParticipantQueryResult.aidl
index 82d985d..db5c00c 100644
--- a/telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl
+++ b/telephony/java/android/telephony/ims/RcsParticipantQueryResult.aidl
@@ -17,4 +17,4 @@
 
 package android.telephony.ims;
 
-parcelable RcsThreadIconChangedEvent;
+parcelable RcsParticipantQueryResult;
diff --git a/telephony/java/android/telephony/ims/RcsParticipantQueryResult.java b/telephony/java/android/telephony/ims/RcsParticipantQueryResult.java
new file mode 100644
index 0000000..4eae39d
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsParticipantQueryResult.java
@@ -0,0 +1,105 @@
+/*
+ * 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.telephony.ims;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * The result of a {@link RcsMessageStore#getRcsParticipants(RcsParticipantQueryParams)}
+ * call. This class allows getting the token for querying the next batch of participants in order to
+ * prevent handling large amounts of data at once.
+ *
+ * @hide - TODO: make public
+ */
+public final class RcsParticipantQueryResult implements Parcelable {
+    // A token for the caller to continue their query for the next batch of results
+    private RcsQueryContinuationToken mContinuationToken;
+    // The list of participant IDs returned with this query
+    private List<Integer> mParticipants;
+
+    /**
+     * Internal constructor for {@link com.android.internal.telephony.ims.RcsMessageStoreController}
+     * to create query results
+     *
+     * @hide
+     */
+    public RcsParticipantQueryResult(
+            RcsQueryContinuationToken continuationToken,
+            List<Integer> participants) {
+        mContinuationToken = continuationToken;
+        mParticipants = participants;
+    }
+
+    /**
+     * Returns a token to call
+     * {@link RcsMessageStore#getRcsParticipants(RcsQueryContinuationToken)}
+     * to get the next batch of {@link RcsParticipant}s.
+     */
+    @Nullable
+    public RcsQueryContinuationToken getContinuationToken() {
+        return mContinuationToken;
+    }
+
+    /**
+     * Returns all the {@link RcsParticipant}s in the current query result. Call {@link
+     * RcsMessageStore#getRcsParticipants(RcsQueryContinuationToken)} to get the next
+     * batch of {@link RcsParticipant}s.
+     */
+    @NonNull
+    public List<RcsParticipant> getParticipants() {
+        List<RcsParticipant> participantList = new ArrayList<>();
+        for (Integer participantId : mParticipants) {
+            participantList.add(new RcsParticipant(participantId));
+        }
+
+        return participantList;
+    }
+
+    private RcsParticipantQueryResult(Parcel in) {
+        mContinuationToken = in.readParcelable(
+                RcsQueryContinuationToken.class.getClassLoader());
+    }
+
+    public static final Creator<RcsParticipantQueryResult> CREATOR =
+            new Creator<RcsParticipantQueryResult>() {
+                @Override
+                public RcsParticipantQueryResult createFromParcel(Parcel in) {
+                    return new RcsParticipantQueryResult(in);
+                }
+
+                @Override
+                public RcsParticipantQueryResult[] newArray(int size) {
+                    return new RcsParticipantQueryResult[size];
+                }
+            };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeParcelable(mContinuationToken, flags);
+    }
+}
diff --git a/telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl b/telephony/java/android/telephony/ims/RcsQueryContinuationToken.aidl
similarity index 94%
copy from telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl
copy to telephony/java/android/telephony/ims/RcsQueryContinuationToken.aidl
index 82d985d..319379a 100644
--- a/telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl
+++ b/telephony/java/android/telephony/ims/RcsQueryContinuationToken.aidl
@@ -17,4 +17,4 @@
 
 package android.telephony.ims;
 
-parcelable RcsThreadIconChangedEvent;
+parcelable RcsQueryContinuationToken;
diff --git a/telephony/java/android/telephony/ims/RcsQueryContinuationToken.java b/telephony/java/android/telephony/ims/RcsQueryContinuationToken.java
new file mode 100644
index 0000000..c1ff396
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsQueryContinuationToken.java
@@ -0,0 +1,157 @@
+/*
+ * 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.telephony.ims;
+
+import android.annotation.IntDef;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * A token for enabling continuation queries. Instances are acquired through
+ * {@code getContinuationToken} on result objects after initial query is done.
+ *
+ * @see RcsEventQueryResult#getContinuationToken()
+ * @see RcsMessageQueryResult#getContinuationToken()
+ * @see RcsParticipantQueryResult#getContinuationToken()
+ * @see RcsThreadQueryResult#getContinuationToken()
+ *
+ * @hide - TODO: make public
+ */
+public final class RcsQueryContinuationToken implements Parcelable {
+    /**
+     * Denotes that this {@link RcsQueryContinuationToken} token is meant to allow continuing
+     * {@link RcsEvent} queries
+     */
+    public static final int EVENT_QUERY_CONTINUATION_TOKEN_TYPE = 0;
+
+    /**
+     * Denotes that this {@link RcsQueryContinuationToken} token is meant to allow continuing
+     * {@link RcsMessage} queries
+     */
+    public static final int MESSAGE_QUERY_CONTINUATION_TOKEN_TYPE = 1;
+
+    /**
+     * Denotes that this {@link RcsQueryContinuationToken} token is meant to allow continuing
+     * {@link RcsParticipant} queries
+     */
+    public static final int PARTICIPANT_QUERY_CONTINUATION_TOKEN_TYPE = 2;
+
+    /**
+     * Denotes that this {@link RcsQueryContinuationToken} token is meant to allow continuing
+     * {@link RcsThread} queries
+     */
+    public static final int THREAD_QUERY_CONTINUATION_TOKEN_TYPE = 3;
+
+    /**
+     * @hide - not meant for public use
+     */
+    public static final String QUERY_CONTINUATION_TOKEN = "query_continuation_token";
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({EVENT_QUERY_CONTINUATION_TOKEN_TYPE, MESSAGE_QUERY_CONTINUATION_TOKEN_TYPE,
+        PARTICIPANT_QUERY_CONTINUATION_TOKEN_TYPE, THREAD_QUERY_CONTINUATION_TOKEN_TYPE})
+    public @interface ContinuationTokenType {}
+
+    // The type of query this token should allow to continue
+    private @ContinuationTokenType int mQueryType;
+    // The raw query string for the initial query
+    private final String mRawQuery;
+    // The number of results that is returned with each query
+    private final int mLimit;
+    // The offset value that this query should start the query from
+    private int mOffset;
+
+    /**
+     * @hide
+     */
+    public RcsQueryContinuationToken(@ContinuationTokenType int queryType, String rawQuery,
+            int limit, int offset) {
+        mQueryType = queryType;
+        mRawQuery = rawQuery;
+        mLimit = limit;
+        mOffset = offset;
+    }
+
+    /**
+     * Returns the original raw query used on {@link com.android.providers.telephony.RcsProvider}
+     * @hide
+     */
+    public String getRawQuery() {
+        return mRawQuery;
+    }
+
+    /**
+     * Returns which index this continuation query should start from
+     * @hide
+     */
+    public int getOffset() {
+        return mOffset;
+    }
+
+    /**
+     * Increments the offset by the amount of result rows returned with the continuation query for
+     * the next query.
+     * @hide
+     */
+    public void incrementOffset() {
+        mOffset += mLimit;
+    }
+
+    /**
+     * Returns the type of query that this {@link RcsQueryContinuationToken} is intended to be used
+     * to continue.
+     */
+    public @ContinuationTokenType int getQueryType() {
+        return mQueryType;
+    }
+
+    private RcsQueryContinuationToken(Parcel in) {
+        mQueryType = in.readInt();
+        mRawQuery = in.readString();
+        mLimit = in.readInt();
+        mOffset = in.readInt();
+    }
+
+    public static final Creator<RcsQueryContinuationToken> CREATOR =
+            new Creator<RcsQueryContinuationToken>() {
+                @Override
+                public RcsQueryContinuationToken createFromParcel(Parcel in) {
+                    return new RcsQueryContinuationToken(in);
+                }
+
+                @Override
+                public RcsQueryContinuationToken[] newArray(int size) {
+                    return new RcsQueryContinuationToken[size];
+                }
+            };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mQueryType);
+        dest.writeString(mRawQuery);
+        dest.writeInt(mLimit);
+        dest.writeInt(mOffset);
+    }
+}
diff --git a/telephony/java/android/telephony/ims/RcsTextPart.aidl b/telephony/java/android/telephony/ims/RcsTextPart.aidl
deleted file mode 100644
index 4f9fe1f..0000000
--- a/telephony/java/android/telephony/ims/RcsTextPart.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- *
- * Copyright 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.telephony.ims;
-
-parcelable RcsTextPart;
diff --git a/telephony/java/android/telephony/ims/RcsTextPart.java b/telephony/java/android/telephony/ims/RcsTextPart.java
deleted file mode 100644
index 2a72df1..0000000
--- a/telephony/java/android/telephony/ims/RcsTextPart.java
+++ /dev/null
@@ -1,48 +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 android.telephony.ims;
-
-import android.os.Parcel;
-
-/**
- * A part of a composite {@link RcsMessage} that holds a string
- * @hide - TODO(sahinc) make this public
- */
-public class RcsTextPart extends RcsPart {
-    public static final Creator<RcsTextPart> CREATOR = new Creator<RcsTextPart>() {
-        @Override
-        public RcsTextPart createFromParcel(Parcel in) {
-            return new RcsTextPart(in);
-        }
-
-        @Override
-        public RcsTextPart[] newArray(int size) {
-            return new RcsTextPart[size];
-        }
-    };
-
-    protected RcsTextPart(Parcel in) {
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-    }
-}
diff --git a/telephony/java/android/telephony/ims/RcsThread.aidl b/telephony/java/android/telephony/ims/RcsThread.aidl
deleted file mode 100644
index d9cf6db..0000000
--- a/telephony/java/android/telephony/ims/RcsThread.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- *
- * Copyright 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.telephony;
-
-parcelable RcsThread;
\ No newline at end of file
diff --git a/telephony/java/android/telephony/ims/RcsThread.java b/telephony/java/android/telephony/ims/RcsThread.java
index c0a0d94..8865586 100644
--- a/telephony/java/android/telephony/ims/RcsThread.java
+++ b/telephony/java/android/telephony/ims/RcsThread.java
@@ -16,60 +16,120 @@
 
 package android.telephony.ims;
 
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.util.Log;
+import static android.provider.Telephony.RcsColumns.RcsUnifiedThreadColumns.THREAD_TYPE_1_TO_1;
+import static android.provider.Telephony.RcsColumns.RcsUnifiedThreadColumns.THREAD_TYPE_GROUP;
+
+import android.annotation.NonNull;
+import android.annotation.WorkerThread;
+
+import com.android.internal.annotations.VisibleForTesting;
 
 /**
  * RcsThread represents a single RCS conversation thread. It holds messages that were sent and
  * received and events that occurred on that thread.
- * @hide - TODO(sahinc) make this public
+ *
+ * @hide - TODO: make public
  */
-public abstract class RcsThread implements Parcelable {
-    // Since this is an abstract class that gets parcelled, the sub-classes need to write these
-    // magic values into the parcel so that we know which type to unparcel into.
-    protected static final int RCS_1_TO_1_TYPE = 998;
-    protected static final int RCS_GROUP_TYPE = 999;
-
+public abstract class RcsThread {
+    /**
+     * The rcs_participant_thread_id that represents this thread in the database
+     * @hide
+     */
     protected int mThreadId;
 
+    /**
+     * @hide
+     */
     protected RcsThread(int threadId) {
         mThreadId = threadId;
     }
 
-    protected RcsThread(Parcel in) {
-        mThreadId = in.readInt();
+    /**
+     * @return Returns the summary of the latest message in this {@link RcsThread} packaged in an
+     * {@link RcsMessageSnippet} object
+     */
+    @WorkerThread
+    @NonNull
+    public RcsMessageSnippet getSnippet() throws RcsMessageStoreException {
+        return RcsControllerCall.call(iRcs -> iRcs.getMessageSnippet(mThreadId));
     }
 
-    public static final Creator<RcsThread> CREATOR = new Creator<RcsThread>() {
-        @Override
-        public RcsThread createFromParcel(Parcel in) {
-            int type = in.readInt();
-
-            switch (type) {
-                case RCS_1_TO_1_TYPE:
-                    return new Rcs1To1Thread(in);
-                case RCS_GROUP_TYPE:
-                    return new RcsGroupThread(in);
-                default:
-                    Log.e(RcsMessageStore.TAG, "Cannot unparcel RcsThread, wrong type: " + type);
-            }
-            return null;
-        }
-
-        @Override
-        public RcsThread[] newArray(int size) {
-            return new RcsThread[0];
-        }
-    };
-
-    @Override
-    public int describeContents() {
-        return 0;
+    /**
+     * Adds a new {@link RcsIncomingMessage} to this RcsThread and persists it in storage.
+     *
+     * @throws RcsMessageStoreException if the message could not be persisted into storage.
+     */
+    @WorkerThread
+    @NonNull
+    public RcsIncomingMessage addIncomingMessage(
+            @NonNull RcsIncomingMessageCreationParams rcsIncomingMessageCreationParams)
+            throws RcsMessageStoreException {
+        return new RcsIncomingMessage(RcsControllerCall.call(iRcs -> iRcs.addIncomingMessage(
+                mThreadId, rcsIncomingMessageCreationParams)));
     }
 
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeInt(mThreadId);
+    /**
+     * Adds a new {@link RcsOutgoingMessage} to this RcsThread and persists it in storage.
+     *
+     * @throws RcsMessageStoreException if the message could not be persisted into storage.
+     */
+    @WorkerThread
+    @NonNull
+    public RcsOutgoingMessage addOutgoingMessage(
+            @NonNull RcsOutgoingMessageCreationParams rcsOutgoingMessageCreationParams)
+            throws RcsMessageStoreException {
+        int messageId = RcsControllerCall.call(iRcs -> iRcs.addOutgoingMessage(
+                mThreadId, rcsOutgoingMessageCreationParams));
+
+        return new RcsOutgoingMessage(messageId);
+    }
+
+    /**
+     * Deletes an {@link RcsMessage} from this RcsThread and updates the storage.
+     *
+     * @param rcsMessage The message to delete from the thread
+     * @throws RcsMessageStoreException if the message could not be deleted
+     */
+    @WorkerThread
+    public void deleteMessage(@NonNull RcsMessage rcsMessage) throws RcsMessageStoreException {
+        RcsControllerCall.callWithNoReturn(
+                iRcs -> iRcs.deleteMessage(rcsMessage.getId(), rcsMessage.isIncoming(), mThreadId,
+                        isGroup()));
+    }
+
+    /**
+     * Convenience function for loading all the {@link RcsMessage}s in this {@link RcsThread}. For
+     * a more detailed and paginated query, please use
+     * {@link RcsMessageStore#getRcsMessages(RcsMessageQueryParams)}
+     *
+     * @return Loads the {@link RcsMessage}s in this thread and returns them in an immutable list.
+     * @throws RcsMessageStoreException if the messages could not be read from the storage
+     */
+    @WorkerThread
+    @NonNull
+    public RcsMessageQueryResult getMessages() throws RcsMessageStoreException {
+        RcsMessageQueryParams queryParameters =
+                new RcsMessageQueryParams.Builder().setThread(this).build();
+        return RcsControllerCall.call(iRcs -> iRcs.getMessages(queryParameters));
+    }
+
+    /**
+     * @return Returns whether this is a group thread or not
+     */
+    public abstract boolean isGroup();
+
+    /**
+     * @hide
+     */
+    @VisibleForTesting
+    public int getThreadId() {
+        return mThreadId;
+    }
+
+    /**
+     * @hide
+     */
+    public int getThreadType() {
+        return isGroup() ? THREAD_TYPE_GROUP : THREAD_TYPE_1_TO_1;
     }
 }
diff --git a/telephony/java/android/telephony/ims/RcsThreadEvent.java b/telephony/java/android/telephony/ims/RcsThreadEvent.java
deleted file mode 100644
index e10baab..0000000
--- a/telephony/java/android/telephony/ims/RcsThreadEvent.java
+++ /dev/null
@@ -1,25 +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 android.telephony.ims;
-
-import android.os.Parcelable;
-
-/**
- * An event that happened on an {@link RcsThread}.
- * @hide - TODO(sahinc) make this public
- */
-public abstract class RcsThreadEvent implements Parcelable {
-}
diff --git a/telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.java b/telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.java
deleted file mode 100644
index b308fef..0000000
--- a/telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.java
+++ /dev/null
@@ -1,49 +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 android.telephony.ims;
-
-import android.os.Parcel;
-
-/**
- * An event that indicates an {@link RcsGroupThread}'s icon was changed.
- * @hide - TODO(sahinc) make this public
- */
-public class RcsThreadIconChangedEvent extends RcsThreadEvent {
-    public static final Creator<RcsThreadIconChangedEvent> CREATOR =
-            new Creator<RcsThreadIconChangedEvent>() {
-        @Override
-        public RcsThreadIconChangedEvent createFromParcel(Parcel in) {
-            return new RcsThreadIconChangedEvent(in);
-        }
-
-        @Override
-        public RcsThreadIconChangedEvent[] newArray(int size) {
-            return new RcsThreadIconChangedEvent[size];
-        }
-    };
-
-    protected RcsThreadIconChangedEvent(Parcel in) {
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-    }
-}
diff --git a/telephony/java/android/telephony/ims/RcsThreadNameChangedEvent.aidl b/telephony/java/android/telephony/ims/RcsThreadNameChangedEvent.aidl
deleted file mode 100644
index 54a311d..0000000
--- a/telephony/java/android/telephony/ims/RcsThreadNameChangedEvent.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- *
- * Copyright 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.telephony.ims;
-
-parcelable RcsThreadNameChangedEvent;
diff --git a/telephony/java/android/telephony/ims/RcsThreadNameChangedEvent.java b/telephony/java/android/telephony/ims/RcsThreadNameChangedEvent.java
deleted file mode 100644
index 6f5cfdf..0000000
--- a/telephony/java/android/telephony/ims/RcsThreadNameChangedEvent.java
+++ /dev/null
@@ -1,49 +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 android.telephony.ims;
-
-import android.os.Parcel;
-
-/**
- * An event that indicates an {@link RcsGroupThread}'s name was changed.
- * @hide - TODO(sahinc) make this public
- */
-public class RcsThreadNameChangedEvent extends RcsThreadEvent {
-    public static final Creator<RcsThreadNameChangedEvent> CREATOR =
-            new Creator<RcsThreadNameChangedEvent>() {
-        @Override
-        public RcsThreadNameChangedEvent createFromParcel(Parcel in) {
-            return new RcsThreadNameChangedEvent(in);
-        }
-
-        @Override
-        public RcsThreadNameChangedEvent[] newArray(int size) {
-            return new RcsThreadNameChangedEvent[size];
-        }
-    };
-
-    protected RcsThreadNameChangedEvent(Parcel in) {
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-    }
-}
diff --git a/telephony/java/android/telephony/ims/RcsThreadParticipantJoinedEvent.aidl b/telephony/java/android/telephony/ims/RcsThreadParticipantJoinedEvent.aidl
deleted file mode 100644
index 047a424..0000000
--- a/telephony/java/android/telephony/ims/RcsThreadParticipantJoinedEvent.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- *
- * Copyright 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.telephony.ims;
-
-parcelable RcsThreadParticipantJoinedEvent;
diff --git a/telephony/java/android/telephony/ims/RcsThreadParticipantJoinedEvent.java b/telephony/java/android/telephony/ims/RcsThreadParticipantJoinedEvent.java
deleted file mode 100644
index 5c4073c..0000000
--- a/telephony/java/android/telephony/ims/RcsThreadParticipantJoinedEvent.java
+++ /dev/null
@@ -1,49 +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 android.telephony.ims;
-
-import android.os.Parcel;
-
-/**
- * An event that indicates an RCS participant has joined an {@link RcsGroupThread}.
- * @hide - TODO(sahinc) make this public
- */
-public class RcsThreadParticipantJoinedEvent extends RcsThreadEvent {
-    public static final Creator<RcsThreadParticipantJoinedEvent> CREATOR =
-            new Creator<RcsThreadParticipantJoinedEvent>() {
-        @Override
-        public RcsThreadParticipantJoinedEvent createFromParcel(Parcel in) {
-            return new RcsThreadParticipantJoinedEvent(in);
-        }
-
-        @Override
-        public RcsThreadParticipantJoinedEvent[] newArray(int size) {
-            return new RcsThreadParticipantJoinedEvent[size];
-        }
-    };
-
-    protected RcsThreadParticipantJoinedEvent(Parcel in) {
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-    }
-}
diff --git a/telephony/java/android/telephony/ims/RcsThreadParticipantLeftEvent.aidl b/telephony/java/android/telephony/ims/RcsThreadParticipantLeftEvent.aidl
deleted file mode 100644
index 52f9bbd..0000000
--- a/telephony/java/android/telephony/ims/RcsThreadParticipantLeftEvent.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- *
- * Copyright 2019, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.telephony.ims;
-
-parcelable RcsThreadParticipantLeftEvent;
diff --git a/telephony/java/android/telephony/ims/RcsThreadParticipantLeftEvent.java b/telephony/java/android/telephony/ims/RcsThreadParticipantLeftEvent.java
deleted file mode 100644
index 4bf86b9..0000000
--- a/telephony/java/android/telephony/ims/RcsThreadParticipantLeftEvent.java
+++ /dev/null
@@ -1,49 +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 android.telephony.ims;
-
-import android.os.Parcel;
-
-/**
- * An event that indicates an RCS participant has left an {@link RcsGroupThread}.
- * @hide - TODO(sahinc) make this public
- */
-public class RcsThreadParticipantLeftEvent extends RcsThreadEvent {
-    public static final Creator<RcsThreadParticipantLeftEvent> CREATOR =
-            new Creator<RcsThreadParticipantLeftEvent>() {
-        @Override
-        public RcsThreadParticipantLeftEvent createFromParcel(Parcel in) {
-            return new RcsThreadParticipantLeftEvent(in);
-        }
-
-        @Override
-        public RcsThreadParticipantLeftEvent[] newArray(int size) {
-            return new RcsThreadParticipantLeftEvent[size];
-        }
-    };
-
-    protected RcsThreadParticipantLeftEvent(Parcel in) {
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-    }
-}
diff --git a/telephony/java/android/telephony/ims/RcsThreadQueryContinuationToken.aidl b/telephony/java/android/telephony/ims/RcsThreadQueryContinuationToken.aidl
deleted file mode 100644
index 7bcebfa..0000000
--- a/telephony/java/android/telephony/ims/RcsThreadQueryContinuationToken.aidl
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
-**
-** Copyright 2018, 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.telephony.ims;
-
-parcelable RcsThreadQueryContinuationToken;
diff --git a/telephony/java/android/telephony/ims/RcsThreadQueryContinuationToken.java b/telephony/java/android/telephony/ims/RcsThreadQueryContinuationToken.java
deleted file mode 100644
index 931e93d..0000000
--- a/telephony/java/android/telephony/ims/RcsThreadQueryContinuationToken.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2018 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.telephony.ims;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * A continuation token to provide for {@link RcsMessageStore#getRcsThreads}. Use this token to
- * break large queries into manageable chunks
- * @hide - TODO make this public
- */
-public class RcsThreadQueryContinuationToken implements Parcelable {
-    protected RcsThreadQueryContinuationToken(Parcel in) {
-    }
-
-    public static final Creator<RcsThreadQueryContinuationToken> CREATOR =
-            new Creator<RcsThreadQueryContinuationToken>() {
-                @Override
-                public RcsThreadQueryContinuationToken createFromParcel(Parcel in) {
-                    return new RcsThreadQueryContinuationToken(in);
-                }
-
-                @Override
-                public RcsThreadQueryContinuationToken[] newArray(int size) {
-                    return new RcsThreadQueryContinuationToken[size];
-                }
-            };
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-    }
-}
diff --git a/telephony/java/android/telephony/ims/RcsThreadQueryParameters.java b/telephony/java/android/telephony/ims/RcsThreadQueryParameters.java
deleted file mode 100644
index f2c4ab1..0000000
--- a/telephony/java/android/telephony/ims/RcsThreadQueryParameters.java
+++ /dev/null
@@ -1,225 +0,0 @@
-/*
- * Copyright (C) 2018 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.telephony.ims;
-
-import android.annotation.CheckResult;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-import java.security.InvalidParameterException;
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.Set;
-
-/**
- * The parameters to pass into {@link RcsMessageStore#getRcsThreads(RcsThreadQueryParameters)} in
- * order to select a subset of {@link RcsThread}s present in the message store.
- * @hide TODO - make the Builder and builder() public. The rest should stay internal only.
- */
-public class RcsThreadQueryParameters implements Parcelable {
-    private final boolean mIsGroup;
-    private final Set<RcsParticipant> mRcsParticipants;
-    private final int mLimit;
-    private final boolean mIsAscending;
-
-    RcsThreadQueryParameters(boolean isGroup, Set<RcsParticipant> participants, int limit,
-            boolean isAscending) {
-        mIsGroup = isGroup;
-        mRcsParticipants = participants;
-        mLimit = limit;
-        mIsAscending = isAscending;
-    }
-
-    /**
-     * Returns a new builder to build a query with.
-     * TODO - make public
-     */
-    public static Builder builder() {
-        return new Builder();
-    }
-
-    /**
-     * This is used in {@link com.android.internal.telephony.ims.RcsMessageStoreController} to get
-     * the list of participants.
-     * @hide
-     */
-    public Set<RcsParticipant> getRcsParticipants() {
-        return mRcsParticipants;
-    }
-
-    /**
-     * This is used in {@link com.android.internal.telephony.ims.RcsMessageStoreController} to get
-     * whether group threads should be queried
-     * @hide
-     */
-    public boolean isGroupThread() {
-        return mIsGroup;
-    }
-
-    /**
-     * This is used in {@link com.android.internal.telephony.ims.RcsMessageStoreController} to get
-     * the number of tuples the result query should be limited to.
-     */
-    public int getLimit() {
-        return mLimit;
-    }
-
-    /**
-     * This is used in {@link com.android.internal.telephony.ims.RcsMessageStoreController} to
-     * determine the sort order.
-     */
-    public boolean isAscending() {
-        return mIsAscending;
-    }
-
-    /**
-     * A helper class to build the {@link RcsThreadQueryParameters}.
-     */
-    public static class Builder {
-        private boolean mIsGroupThread;
-        private Set<RcsParticipant> mParticipants;
-        private int mLimit = 100;
-        private boolean mIsAscending;
-
-        /**
-         * Package private constructor for {@link RcsThreadQueryParameters.Builder}. To obtain this,
-         * {@link RcsThreadQueryParameters#builder()} needs to be called.
-         */
-        Builder() {
-            mParticipants = new HashSet<>();
-        }
-
-        /**
-         * Limits the query to only return group threads.
-         * @param isGroupThread Whether to limit the query result to group threads.
-         * @return The same instance of the builder to chain parameters.
-         */
-        @CheckResult
-        public Builder isGroupThread(boolean isGroupThread) {
-            mIsGroupThread = isGroupThread;
-            return this;
-        }
-
-        /**
-         * Limits the query to only return threads that contain the given participant.
-         * @param participant The participant that must be included in all of the returned threads.
-         * @return The same instance of the builder to chain parameters.
-         */
-        @CheckResult
-        public Builder withParticipant(RcsParticipant participant) {
-            mParticipants.add(participant);
-            return this;
-        }
-
-        /**
-         * Limits the query to only return threads that contain the given list of participants.
-         * @param participants An iterable list of participants that must be included in all of the
-         *                     returned threads.
-         * @return The same instance of the builder to chain parameters.
-         */
-        @CheckResult
-        public Builder withParticipants(Iterable<RcsParticipant> participants) {
-            for (RcsParticipant participant : participants) {
-                mParticipants.add(participant);
-            }
-            return this;
-        }
-
-        /**
-         * Desired number of threads to be returned from the query. Passing in 0 will return all
-         * existing threads at once. The limit defaults to 100.
-         * @param limit The number to limit the query result to.
-         * @return The same instance of the builder to chain parameters.
-         * @throws InvalidParameterException If the given limit is negative.
-         */
-        @CheckResult
-        public Builder limitResultsTo(int limit) throws InvalidParameterException {
-            if (limit < 0) {
-                throw new InvalidParameterException("The query limit must be non-negative");
-            }
-
-            mLimit = limit;
-            return this;
-        }
-
-        /**
-         * Sorts the results returned from the query via thread IDs.
-         *
-         * TODO - add sorting support for other fields
-         *
-         * @param isAscending whether to sort in ascending order or not
-         * @return The same instance of the builder to chain parameters.
-         */
-        @CheckResult
-        public Builder sort(boolean isAscending) {
-            mIsAscending = isAscending;
-            return this;
-        }
-
-        /**
-         * Builds the {@link RcsThreadQueryParameters} to use in
-         * {@link RcsMessageStore#getRcsThreads(RcsThreadQueryParameters)}
-         *
-         * @return An instance of {@link RcsThreadQueryParameters} to use with the thread query.
-         */
-        public RcsThreadQueryParameters build() {
-            return new RcsThreadQueryParameters(
-                    mIsGroupThread, mParticipants, mLimit, mIsAscending);
-        }
-    }
-
-    /**
-     * Parcelable boilerplate below.
-     */
-    protected RcsThreadQueryParameters(Parcel in) {
-        mIsGroup = in.readBoolean();
-
-        ArrayList<RcsParticipant> participantArrayList = new ArrayList<>();
-        in.readTypedList(participantArrayList, RcsParticipant.CREATOR);
-        mRcsParticipants = new HashSet<>(participantArrayList);
-
-        mLimit = in.readInt();
-        mIsAscending = in.readBoolean();
-    }
-
-    public static final Creator<RcsThreadQueryParameters> CREATOR =
-            new Creator<RcsThreadQueryParameters>() {
-                @Override
-                public RcsThreadQueryParameters createFromParcel(Parcel in) {
-                    return new RcsThreadQueryParameters(in);
-                }
-
-                @Override
-                public RcsThreadQueryParameters[] newArray(int size) {
-                    return new RcsThreadQueryParameters[size];
-                }
-            };
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeBoolean(mIsGroup);
-        dest.writeTypedList(new ArrayList<>(mRcsParticipants));
-        dest.writeInt(mLimit);
-        dest.writeBoolean(mIsAscending);
-    }
-
-}
diff --git a/telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl b/telephony/java/android/telephony/ims/RcsThreadQueryParams.aidl
similarity index 94%
copy from telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl
copy to telephony/java/android/telephony/ims/RcsThreadQueryParams.aidl
index 82d985d..3f351dc 100644
--- a/telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl
+++ b/telephony/java/android/telephony/ims/RcsThreadQueryParams.aidl
@@ -17,4 +17,4 @@
 
 package android.telephony.ims;
 
-parcelable RcsThreadIconChangedEvent;
+parcelable RcsThreadQueryParams;
diff --git a/telephony/java/android/telephony/ims/RcsThreadQueryParams.java b/telephony/java/android/telephony/ims/RcsThreadQueryParams.java
new file mode 100644
index 0000000..ba32e32
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsThreadQueryParams.java
@@ -0,0 +1,305 @@
+/*
+ * 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.telephony.ims;
+
+import android.annotation.CheckResult;
+import android.annotation.IntDef;
+import android.annotation.IntRange;
+import android.annotation.NonNull;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.security.InvalidParameterException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * The parameters to pass into {@link RcsMessageStore#getRcsThreads(RcsThreadQueryParams)} in
+ * order to select a subset of {@link RcsThread}s present in the message store.
+ *
+ * @hide - TODO: make public
+ */
+public final class RcsThreadQueryParams implements Parcelable {
+    /**
+     * Bitmask flag to be used with {@link Builder#setThreadType(int)} to make
+     * {@link RcsMessageStore#getRcsThreads(RcsThreadQueryParams)} return
+     * {@link RcsGroupThread}s.
+     */
+    public static final int THREAD_TYPE_GROUP = 0x0001;
+
+    /**
+     * Bitmask flag to be used with {@link Builder#setThreadType(int)} to make
+     * {@link RcsMessageStore#getRcsThreads(RcsThreadQueryParams)} return
+     * {@link Rcs1To1Thread}s.
+     */
+    public static final int THREAD_TYPE_1_TO_1 = 0x0002;
+
+    // The type of threads to be filtered with the query
+    private final int mThreadType;
+    // The list of participants that are expected in the resulting threads
+    private final List<Integer> mRcsParticipantIds;
+    // The number of RcsThread's that should be returned with this query
+    private final int mLimit;
+    // The property which the result of the query should be sorted against
+    private final @SortingProperty int mSortingProperty;
+    // Whether the sorting should be done in ascending
+    private final boolean mIsAscending;
+
+    /**
+     * Flag to be used with {@link Builder#setSortProperty(int)} to denote that the results should
+     * be sorted in the order of {@link RcsThread} creation time for faster results.
+     */
+    public static final int SORT_BY_CREATION_ORDER = 0;
+
+    /**
+     * Flag to be used with {@link Builder#setSortProperty(int)} to denote that the results should
+     * be sorted according to the timestamp of {@link RcsThread#getSnippet()}
+     */
+    public static final int SORT_BY_TIMESTAMP = 1;
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({SORT_BY_CREATION_ORDER, SORT_BY_TIMESTAMP})
+    public @interface SortingProperty {
+    }
+
+    /**
+     * @hide
+     */
+    public static final String THREAD_QUERY_PARAMETERS_KEY = "thread_query_parameters";
+
+    RcsThreadQueryParams(int threadType, Set<RcsParticipant> participants,
+            int limit, int sortingProperty, boolean isAscending) {
+        mThreadType = threadType;
+        mRcsParticipantIds = convertParticipantSetToIdList(participants);
+        mLimit = limit;
+        mSortingProperty = sortingProperty;
+        mIsAscending = isAscending;
+    }
+
+    private static List<Integer> convertParticipantSetToIdList(Set<RcsParticipant> participants) {
+        List<Integer> ids = new ArrayList<>(participants.size());
+        for (RcsParticipant participant : participants) {
+            ids.add(participant.getId());
+        }
+        return ids;
+    }
+
+    /**
+     * This is used in {@link com.android.internal.telephony.ims.RcsMessageStoreController} to get
+     * the list of participant IDs.
+     *
+     * As we don't expose any integer ID's to API users, this should stay hidden
+     *
+     * @hide - not meant for public use
+     */
+    public List<Integer> getRcsParticipantsIds() {
+        return Collections.unmodifiableList(mRcsParticipantIds);
+    }
+
+    /**
+     * @return Returns the bitmask flag for types of {@link RcsThread}s that this query should
+     * return.
+     */
+    public int getThreadType() {
+        return mThreadType;
+    }
+
+    /**
+     * @return Returns the number of {@link RcsThread}s to be returned from the query. A value
+     * of 0 means there is no set limit.
+     */
+    public int getLimit() {
+        return mLimit;
+    }
+
+    /**
+     * @return Returns the property that will be used to sort the result against.
+     * @see SortingProperty
+     */
+    public @SortingProperty int getSortingProperty() {
+        return mSortingProperty;
+    }
+
+    /**
+     * @return Returns {@code true} if the result set will be sorted in ascending order,
+     * {@code false} if it will be sorted in descending order.
+     */
+    public boolean getSortDirection() {
+        return mIsAscending;
+    }
+
+    /**
+     * A helper class to build the {@link RcsThreadQueryParams}.
+     */
+    public static class Builder {
+        private int mThreadType;
+        private Set<RcsParticipant> mParticipants;
+        private int mLimit = 100;
+        private @SortingProperty int mSortingProperty;
+        private boolean mIsAscending;
+
+        /**
+         * Constructs a {@link RcsThreadQueryParams.Builder} to help build an
+         * {@link RcsThreadQueryParams}
+         */
+        public Builder() {
+            mParticipants = new HashSet<>();
+        }
+
+        /**
+         * Limits the query to only return group threads.
+         *
+         * @param threadType Whether to limit the query result to group threads.
+         * @return The same instance of the builder to chain parameters.
+         * @see RcsThreadQueryParams#THREAD_TYPE_GROUP
+         * @see RcsThreadQueryParams#THREAD_TYPE_1_TO_1
+         */
+        @CheckResult
+        public Builder setThreadType(int threadType) {
+            mThreadType = threadType;
+            return this;
+        }
+
+        /**
+         * Limits the query to only return threads that contain the given participant. If this
+         * property was not set, participants will not be taken into account while querying for
+         * threads.
+         *
+         * @param participant The participant that must be included in all of the returned threads.
+         * @return The same instance of the builder to chain parameters.
+         */
+        @CheckResult
+        public Builder setParticipant(@NonNull RcsParticipant participant) {
+            mParticipants.add(participant);
+            return this;
+        }
+
+        /**
+         * Limits the query to only return threads that contain the given list of participants. If
+         * this property was not set, participants will not be taken into account while querying
+         * for threads.
+         *
+         * @param participants An iterable list of participants that must be included in all of the
+         *                     returned threads.
+         * @return The same instance of the builder to chain parameters.
+         */
+        @CheckResult
+        public Builder setParticipants(@NonNull List<RcsParticipant> participants) {
+            mParticipants.addAll(participants);
+            return this;
+        }
+
+        /**
+         * Desired number of threads to be returned from the query. Passing in 0 will return all
+         * existing threads at once. The limit defaults to 100.
+         *
+         * @param limit The number to limit the query result to.
+         * @return The same instance of the builder to chain parameters.
+         * @throws InvalidParameterException If the given limit is negative.
+         */
+        @CheckResult
+        public Builder setResultLimit(@IntRange(from = 0) int limit)
+                throws InvalidParameterException {
+            if (limit < 0) {
+                throw new InvalidParameterException("The query limit must be non-negative");
+            }
+
+            mLimit = limit;
+            return this;
+        }
+
+        /**
+         * Sets the property where the results should be sorted against. Defaults to
+         * {@link SortingProperty#SORT_BY_CREATION_ORDER}
+         *
+         * @param sortingProperty whether to sort in ascending order or not
+         * @return The same instance of the builder to chain parameters.
+         */
+        @CheckResult
+        public Builder setSortProperty(@SortingProperty int sortingProperty) {
+            mSortingProperty = sortingProperty;
+            return this;
+        }
+
+        /**
+         * Sets whether the results should be sorted ascending or descending
+         *
+         * @param isAscending whether the results should be sorted ascending
+         * @return The same instance of the builder to chain parameters.
+         */
+        @CheckResult
+        public Builder setSortDirection(boolean isAscending) {
+            mIsAscending = isAscending;
+            return this;
+        }
+
+        /**
+         * Builds the {@link RcsThreadQueryParams} to use in
+         * {@link RcsMessageStore#getRcsThreads(RcsThreadQueryParams)}
+         *
+         * @return An instance of {@link RcsThreadQueryParams} to use with the thread query.
+         */
+        public RcsThreadQueryParams build() {
+            return new RcsThreadQueryParams(mThreadType, mParticipants, mLimit,
+                    mSortingProperty, mIsAscending);
+        }
+    }
+
+    /**
+     * Parcelable boilerplate below.
+     */
+    private RcsThreadQueryParams(Parcel in) {
+        mThreadType = in.readInt();
+        mRcsParticipantIds = new ArrayList<>();
+        in.readList(mRcsParticipantIds, Integer.class.getClassLoader());
+        mLimit = in.readInt();
+        mSortingProperty = in.readInt();
+        mIsAscending = in.readByte() == 1;
+    }
+
+    public static final Creator<RcsThreadQueryParams> CREATOR =
+            new Creator<RcsThreadQueryParams>() {
+                @Override
+                public RcsThreadQueryParams createFromParcel(Parcel in) {
+                    return new RcsThreadQueryParams(in);
+                }
+
+                @Override
+                public RcsThreadQueryParams[] newArray(int size) {
+                    return new RcsThreadQueryParams[size];
+                }
+            };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mThreadType);
+        dest.writeList(mRcsParticipantIds);
+        dest.writeInt(mLimit);
+        dest.writeInt(mSortingProperty);
+        dest.writeByte((byte) (mIsAscending ? 1 : 0));
+    }
+}
diff --git a/telephony/java/android/telephony/ims/RcsThreadQueryResult.aidl b/telephony/java/android/telephony/ims/RcsThreadQueryResult.aidl
index 4b06529..b1d5cf4 100644
--- a/telephony/java/android/telephony/ims/RcsThreadQueryResult.aidl
+++ b/telephony/java/android/telephony/ims/RcsThreadQueryResult.aidl
@@ -1,19 +1,19 @@
 /*
-**
-** Copyright 2018, 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.
-*/
+ *
+ * Copyright 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 
 package android.telephony.ims;
 
diff --git a/telephony/java/android/telephony/ims/RcsThreadQueryResult.java b/telephony/java/android/telephony/ims/RcsThreadQueryResult.java
index 47715f8..a91126b 100644
--- a/telephony/java/android/telephony/ims/RcsThreadQueryResult.java
+++ b/telephony/java/android/telephony/ims/RcsThreadQueryResult.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * 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.
@@ -16,22 +16,30 @@
 
 package android.telephony.ims;
 
+import static android.provider.Telephony.RcsColumns.RcsUnifiedThreadColumns.THREAD_TYPE_1_TO_1;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import com.android.ims.RcsTypeIdPair;
+
+import java.util.ArrayList;
 import java.util.List;
 
 /**
- * The result of a {@link RcsMessageStore#getRcsThreads(RcsThreadQueryContinuationToken,
- * RcsThreadQueryParameters)}
+ * The result of a {@link RcsMessageStore#getRcsThreads(RcsThreadQueryParams)}
  * call. This class allows getting the token for querying the next batch of threads in order to
  * prevent handling large amounts of data at once.
  *
- * @hide
+ * @hide - TODO: make public
  */
-public class RcsThreadQueryResult implements Parcelable {
-    private RcsThreadQueryContinuationToken mContinuationToken;
-    private List<RcsThread> mRcsThreads;
+public final class RcsThreadQueryResult implements Parcelable {
+    // A token for the caller to continue their query for the next batch of results
+    private RcsQueryContinuationToken mContinuationToken;
+    // The list of thread IDs returned with this query
+    private List<RcsTypeIdPair> mRcsThreadIds;
 
     /**
      * Internal constructor for {@link com.android.internal.telephony.ims.RcsMessageStoreController}
@@ -40,31 +48,47 @@
      * @hide
      */
     public RcsThreadQueryResult(
-            RcsThreadQueryContinuationToken continuationToken, List<RcsThread> rcsThreads) {
+            RcsQueryContinuationToken continuationToken,
+            List<RcsTypeIdPair> rcsThreadIds) {
         mContinuationToken = continuationToken;
-        mRcsThreads = rcsThreads;
+        mRcsThreadIds = rcsThreadIds;
     }
 
     /**
      * Returns a token to call
-     * {@link RcsMessageStore#getRcsThreads(RcsThreadQueryContinuationToken)}
+     * {@link RcsMessageStore#getRcsThreads(RcsQueryContinuationToken)}
      * to get the next batch of {@link RcsThread}s.
      */
-    public RcsThreadQueryContinuationToken nextChunkToken() {
+    @Nullable
+    public RcsQueryContinuationToken getContinuationToken() {
         return mContinuationToken;
     }
 
     /**
      * Returns all the RcsThreads in the current query result. Call {@link
-     * RcsMessageStore#getRcsThreads(RcsThreadQueryContinuationToken)} to get the next batch of
+     * RcsMessageStore#getRcsThreads(RcsQueryContinuationToken)} to get the next batch of
      * {@link RcsThread}s.
      */
+    @NonNull
     public List<RcsThread> getThreads() {
-        return mRcsThreads;
+        List<RcsThread> rcsThreads = new ArrayList<>();
+
+        for (RcsTypeIdPair typeIdPair : mRcsThreadIds) {
+            if (typeIdPair.getType() == THREAD_TYPE_1_TO_1) {
+                rcsThreads.add(new Rcs1To1Thread(typeIdPair.getId()));
+            } else {
+                rcsThreads.add(new RcsGroupThread(typeIdPair.getId()));
+            }
+        }
+
+        return rcsThreads;
     }
 
-    protected RcsThreadQueryResult(Parcel in) {
-        // TODO - implement
+    private RcsThreadQueryResult(Parcel in) {
+        mContinuationToken = in.readParcelable(
+            RcsQueryContinuationToken.class.getClassLoader());
+        mRcsThreadIds = new ArrayList<>();
+        in.readList(mRcsThreadIds, Integer.class.getClassLoader());
     }
 
     public static final Creator<RcsThreadQueryResult> CREATOR =
@@ -87,6 +111,7 @@
 
     @Override
     public void writeToParcel(Parcel dest, int flags) {
-        // TODO - implement
+        dest.writeParcelable(mContinuationToken, flags);
+        dest.writeList(mRcsThreadIds);
     }
 }
diff --git a/telephony/java/android/telephony/ims/aidl/IRcs.aidl b/telephony/java/android/telephony/ims/aidl/IRcs.aidl
index 0c958ba..2478f8c 100644
--- a/telephony/java/android/telephony/ims/aidl/IRcs.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IRcs.aidl
@@ -16,10 +16,19 @@
 
 package android.telephony.ims.aidl;
 
-import android.telephony.ims.RcsParticipant;
-import android.telephony.ims.Rcs1To1Thread;
-import android.telephony.ims.RcsThreadQueryContinuationToken;
-import android.telephony.ims.RcsThreadQueryParameters;
+import android.net.Uri;
+import android.telephony.ims.RcsEventQueryParams;
+import android.telephony.ims.RcsEventQueryResult;
+import android.telephony.ims.RcsFileTransferCreationParams;
+import android.telephony.ims.RcsIncomingMessageCreationParams;
+import android.telephony.ims.RcsMessageSnippet;
+import android.telephony.ims.RcsMessageQueryParams;
+import android.telephony.ims.RcsMessageQueryResult;
+import android.telephony.ims.RcsOutgoingMessageCreationParams;
+import android.telephony.ims.RcsParticipantQueryParams;
+import android.telephony.ims.RcsParticipantQueryResult;
+import android.telephony.ims.RcsQueryContinuationToken;
+import android.telephony.ims.RcsThreadQueryParams;
 import android.telephony.ims.RcsThreadQueryResult;
 
 /**
@@ -27,23 +36,231 @@
  * {@hide}
  */
 interface IRcs {
+    /////////////////////////
     // RcsMessageStore APIs
-    RcsThreadQueryResult getRcsThreads(in RcsThreadQueryParameters queryParameters);
+    /////////////////////////
+    RcsThreadQueryResult getRcsThreads(in RcsThreadQueryParams queryParams);
 
     RcsThreadQueryResult getRcsThreadsWithToken(
-        in RcsThreadQueryContinuationToken continuationToken);
+        in RcsQueryContinuationToken continuationToken);
 
-    void deleteThread(int threadId);
+    RcsParticipantQueryResult getParticipants(in RcsParticipantQueryParams queryParams);
 
-    Rcs1To1Thread createRcs1To1Thread(in RcsParticipant participant);
+    RcsParticipantQueryResult getParticipantsWithToken(
+        in RcsQueryContinuationToken continuationToken);
 
+    RcsMessageQueryResult getMessages(in RcsMessageQueryParams queryParams);
+
+    RcsMessageQueryResult getMessagesWithToken(
+        in RcsQueryContinuationToken continuationToken);
+
+    RcsEventQueryResult getEvents(in RcsEventQueryParams queryParams);
+
+    RcsEventQueryResult getEventsWithToken(
+        in RcsQueryContinuationToken continuationToken);
+
+    // returns true if the thread was successfully deleted
+    boolean deleteThread(int threadId, int threadType);
+
+    // Creates an Rcs1To1Thread and returns its row ID
+    int createRcs1To1Thread(int participantId);
+
+    // Creates an RcsGroupThread and returns its row ID
+    int createGroupThread(in int[] participantIds, String groupName, in Uri groupIcon);
+
+    /////////////////////////
     // RcsThread APIs
-    int getMessageCount(int rcsThreadId);
+    /////////////////////////
 
+    // Creates a new RcsIncomingMessage on the given thread and returns its row ID
+    int addIncomingMessage(int rcsThreadId,
+            in RcsIncomingMessageCreationParams rcsIncomingMessageCreationParams);
+
+    // Creates a new RcsOutgoingMessage on the given thread and returns its row ID
+    int addOutgoingMessage(int rcsThreadId,
+            in RcsOutgoingMessageCreationParams rcsOutgoingMessageCreationParams);
+
+    // TODO: modify RcsProvider URI's to allow deleting a message without specifying its thread
+    void deleteMessage(int rcsMessageId, boolean isIncoming, int rcsThreadId, boolean isGroup);
+
+    RcsMessageSnippet getMessageSnippet(int rcsThreadId);
+
+    /////////////////////////
+    // Rcs1To1Thread APIs
+    /////////////////////////
+    void set1To1ThreadFallbackThreadId(int rcsThreadId, long fallbackId);
+
+    long get1To1ThreadFallbackThreadId(int rcsThreadId);
+
+    int get1To1ThreadOtherParticipantId(int rcsThreadId);
+
+    /////////////////////////
+    // RcsGroupThread APIs
+    /////////////////////////
+    void setGroupThreadName(int rcsThreadId, String groupName);
+
+    String getGroupThreadName(int rcsThreadId);
+
+    void setGroupThreadIcon(int rcsThreadId, in Uri groupIcon);
+
+    Uri getGroupThreadIcon(int rcsThreadId);
+
+    void setGroupThreadOwner(int rcsThreadId, int participantId);
+
+    int getGroupThreadOwner(int rcsThreadId);
+
+    void setGroupThreadConferenceUri(int rcsThreadId, in Uri conferenceUri);
+
+    Uri getGroupThreadConferenceUri(int rcsThreadId);
+
+    void addParticipantToGroupThread(int rcsThreadId, int participantId);
+
+    void removeParticipantFromGroupThread(int rcsThreadId, int participantId);
+
+    /////////////////////////
     // RcsParticipant APIs
-    RcsParticipant createRcsParticipant(String canonicalAddress);
+    /////////////////////////
 
-    void updateRcsParticipantCanonicalAddress(int id, String canonicalAddress);
+    // Creates a new RcsParticipant and returns its rowId
+    int createRcsParticipant(String canonicalAddress, String alias);
 
-    void updateRcsParticipantAlias(int id, String alias);
+    String getRcsParticipantCanonicalAddress(int participantId);
+
+    String getRcsParticipantAlias(int participantId);
+
+    void setRcsParticipantAlias(int id, String alias);
+
+    String getRcsParticipantContactId(int participantId);
+
+    void setRcsParticipantContactId(int participantId, String contactId);
+
+    /////////////////////////
+    // RcsMessage APIs
+    /////////////////////////
+    void setMessageSubId(int messageId, boolean isIncoming, int subId);
+
+    int getMessageSubId(int messageId, boolean isIncoming);
+
+    void setMessageStatus(int messageId, boolean isIncoming, int status);
+
+    int getMessageStatus(int messageId, boolean isIncoming);
+
+    void setMessageOriginationTimestamp(int messageId, boolean isIncoming, long originationTimestamp);
+
+    long getMessageOriginationTimestamp(int messageId, boolean isIncoming);
+
+    void setGlobalMessageIdForMessage(int messageId, boolean isIncoming, String globalId);
+
+    String getGlobalMessageIdForMessage(int messageId, boolean isIncoming);
+
+    void setMessageArrivalTimestamp(int messageId, boolean isIncoming, long arrivalTimestamp);
+
+    long getMessageArrivalTimestamp(int messageId, boolean isIncoming);
+
+    void setMessageSeenTimestamp(int messageId, boolean isIncoming, long seenTimestamp);
+
+    long getMessageSeenTimestamp(int messageId, boolean isIncoming);
+
+    void setTextForMessage(int messageId, boolean isIncoming, String text);
+
+    String getTextForMessage(int messageId, boolean isIncoming);
+
+    void setLatitudeForMessage(int messageId, boolean isIncoming, double latitude);
+
+    double getLatitudeForMessage(int messageId, boolean isIncoming);
+
+    void setLongitudeForMessage(int messageId, boolean isIncoming, double longitude);
+
+    double getLongitudeForMessage(int messageId, boolean isIncoming);
+
+    // Returns the ID's of the file transfers attached to the given message
+    int[] getFileTransfersAttachedToMessage(int messageId, boolean isIncoming);
+
+    int getSenderParticipant(int messageId);
+
+    /////////////////////////
+    // RcsOutgoingMessageDelivery APIs
+    /////////////////////////
+
+    // Returns the participant ID's that this message is intended to be delivered to
+    int[] getMessageRecipients(int messageId);
+
+    long getOutgoingDeliveryDeliveredTimestamp(int messageId, int participantId);
+
+    void setOutgoingDeliveryDeliveredTimestamp(int messageId, int participantId, long deliveredTimestamp);
+
+    long getOutgoingDeliverySeenTimestamp(int messageId, int participantId);
+
+    void setOutgoingDeliverySeenTimestamp(int messageId, int participantId, long seenTimestamp);
+
+    int getOutgoingDeliveryStatus(int messageId, int participantId);
+
+    void setOutgoingDeliveryStatus(int messageId, int participantId, int status);
+
+    /////////////////////////
+    // RcsFileTransferPart APIs
+    /////////////////////////
+
+    // Performs the initial write to storage and returns the row ID.
+    int storeFileTransfer(int messageId, boolean isIncoming,
+            in RcsFileTransferCreationParams fileTransferCreationParams);
+
+    void deleteFileTransfer(int partId);
+
+    void setFileTransferSessionId(int partId, String sessionId);
+
+    String getFileTransferSessionId(int partId);
+
+    void setFileTransferContentUri(int partId, in Uri contentUri);
+
+    Uri getFileTransferContentUri(int partId);
+
+    void setFileTransferContentType(int partId, String contentType);
+
+    String getFileTransferContentType(int partId);
+
+    void setFileTransferFileSize(int partId, long fileSize);
+
+    long getFileTransferFileSize(int partId);
+
+    void setFileTransferTransferOffset(int partId, long transferOffset);
+
+    long getFileTransferTransferOffset(int partId);
+
+    void setFileTransferStatus(int partId, int transferStatus);
+
+    int getFileTransferStatus(int partId);
+
+    void setFileTransferWidth(int partId, int width);
+
+    int getFileTransferWidth(int partId);
+
+    void setFileTransferHeight(int partId, int height);
+
+    int getFileTransferHeight(int partId);
+
+    void setFileTransferLength(int partId, long length);
+
+    long getFileTransferLength(int partId);
+
+    void setFileTransferPreviewUri(int partId, in Uri uri);
+
+    Uri getFileTransferPreviewUri(int partId);
+
+    void setFileTransferPreviewType(int partId, String type);
+
+    String getFileTransferPreviewType(int partId);
+
+    /////////////////////////
+    // RcsEvent APIs
+    /////////////////////////
+    int createGroupThreadNameChangedEvent(long timestamp, int threadId, int originationParticipantId, String newName);
+
+    int createGroupThreadIconChangedEvent(long timestamp, int threadId, int originationParticipantId, in Uri newIcon);
+
+    int createGroupThreadParticipantJoinedEvent(long timestamp, int threadId, int originationParticipantId, int participantId);
+
+    int createGroupThreadParticipantLeftEvent(long timestamp, int threadId, int originationParticipantId, int participantId);
+
+    int createParticipantAliasChangedEvent(long timestamp, int participantId, String newAlias);
 }
\ No newline at end of file
diff --git a/telephony/java/com/android/ims/RcsTypeIdPair.java b/telephony/java/com/android/ims/RcsTypeIdPair.java
new file mode 100644
index 0000000..a517735
--- /dev/null
+++ b/telephony/java/com/android/ims/RcsTypeIdPair.java
@@ -0,0 +1,79 @@
+/*
+ * 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.ims;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * A utility class to pass RCS IDs and types in RPC calls
+ *
+ * @hide
+ */
+public class RcsTypeIdPair implements Parcelable {
+    private int mType;
+    private int mId;
+
+    public RcsTypeIdPair(int type, int id) {
+        mType = type;
+        mId = id;
+    }
+
+    public int getType() {
+        return mType;
+    }
+
+    public void setType(int type) {
+        mType = type;
+    }
+
+    public int getId() {
+        return mId;
+    }
+
+    public void setId(int id) {
+        mId = id;
+    }
+
+    public RcsTypeIdPair(Parcel in) {
+        mType = in.readInt();
+        mId = in.readInt();
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mType);
+        dest.writeInt(mId);
+    }
+
+    public static final Creator<RcsTypeIdPair> CREATOR =
+            new Creator<RcsTypeIdPair>() {
+                @Override
+                public RcsTypeIdPair createFromParcel(Parcel in) {
+                    return new RcsTypeIdPair(in);
+                }
+
+                @Override
+                public RcsTypeIdPair[] newArray(int size) {
+                    return new RcsTypeIdPair[size];
+                }
+            };
+}
diff --git a/telephony/java/com/android/internal/telephony/SmsApplication.java b/telephony/java/com/android/internal/telephony/SmsApplication.java
index d3420ee..7478a00 100644
--- a/telephony/java/com/android/internal/telephony/SmsApplication.java
+++ b/telephony/java/com/android/internal/telephony/SmsApplication.java
@@ -636,7 +636,7 @@
             // Update the setting.
             RoleManagerCallback.Future res = new RoleManagerCallback.Future();
             context.getSystemService(RoleManager.class).addRoleHolderAsUser(
-                    RoleManager.ROLE_SMS, applicationData.mPackageName, UserHandle.of(userId),
+                    RoleManager.ROLE_SMS, applicationData.mPackageName, 0, UserHandle.of(userId),
                     AsyncTask.THREAD_POOL_EXECUTOR, res);
             try {
                 res.get(5, TimeUnit.SECONDS);
diff --git a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
index 964a313..9080e23 100644
--- a/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
+++ b/telephony/java/com/android/internal/telephony/cdma/SmsMessage.java
@@ -21,7 +21,6 @@
 import android.telephony.PhoneNumberUtils;
 import android.telephony.SmsCbLocation;
 import android.telephony.SmsCbMessage;
-import android.telephony.TelephonyManager;
 import android.telephony.cdma.CdmaSmsCbProgramData;
 import android.telephony.Rlog;
 import android.util.Log;
@@ -746,8 +745,10 @@
 
     /**
      * Parses a broadcast SMS, possibly containing a CMAS alert.
+     *
+     * @param plmn the PLMN for a broadcast SMS
      */
-    public SmsCbMessage parseBroadcastSms() {
+    public SmsCbMessage parseBroadcastSms(String plmn) {
         BearerData bData = BearerData.decode(mEnvelope.bearerData, mEnvelope.serviceCategory);
         if (bData == null) {
             Rlog.w(LOG_TAG, "BearerData.decode() returned null");
@@ -758,7 +759,6 @@
             Rlog.d(LOG_TAG, "MT raw BearerData = " + HexDump.toHexString(mEnvelope.bearerData));
         }
 
-        String plmn = TelephonyManager.getDefault().getNetworkOperator();
         SmsCbLocation location = new SmsCbLocation(plmn);
 
         return new SmsCbMessage(SmsCbMessage.MESSAGE_FORMAT_3GPP2,
@@ -858,11 +858,11 @@
         bearerData.userData = userData;
 
         byte[] encodedBearerData = BearerData.encode(bearerData);
+        if (encodedBearerData == null) return null;
         if (Rlog.isLoggable(LOGGABLE_TAG, Log.VERBOSE)) {
             Rlog.d(LOG_TAG, "MO (encoded) BearerData = " + bearerData);
             Rlog.d(LOG_TAG, "MO raw BearerData = '" + HexDump.toHexString(encodedBearerData) + "'");
         }
-        if (encodedBearerData == null) return null;
 
         int teleservice = bearerData.hasUserDataHeader ?
                 SmsEnvelope.TELESERVICE_WEMT : SmsEnvelope.TELESERVICE_WMT;
diff --git a/test-base/api/TEST_MAPPING b/test-base/api/TEST_MAPPING
new file mode 100644
index 0000000..3535954
--- /dev/null
+++ b/test-base/api/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsAndroidTestBase27ApiSignatureTestCases"
+    }
+  ]
+}
diff --git a/test-mock/api/TEST_MAPPING b/test-mock/api/TEST_MAPPING
new file mode 100644
index 0000000..d1bd9af
--- /dev/null
+++ b/test-mock/api/TEST_MAPPING
@@ -0,0 +1,10 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsAndroidTestMockCurrentApiSignatureTestCases"
+    },
+    {
+      "name": "CtsCurrentApiSignatureTestCases"
+    }
+  ]
+}
diff --git a/test-runner/api/TEST_MAPPING b/test-runner/api/TEST_MAPPING
new file mode 100644
index 0000000..76ade3c
--- /dev/null
+++ b/test-runner/api/TEST_MAPPING
@@ -0,0 +1,10 @@
+{
+  "presubmit": [
+    {
+      "name": "CtsAndroidTestRunnerCurrentApiSignatureTestCases"
+    },
+    {
+      "name": "CtsCurrentApiSignatureTestCases"
+    }
+  ]
+}
diff --git a/tests/RcsTests/src/com/android/tests/ims/RcsGroupThreadIconChangedEventTest.java b/tests/RcsTests/src/com/android/tests/ims/RcsGroupThreadIconChangedEventTest.java
new file mode 100644
index 0000000..915a260
--- /dev/null
+++ b/tests/RcsTests/src/com/android/tests/ims/RcsGroupThreadIconChangedEventTest.java
@@ -0,0 +1,55 @@
+/*
+ * 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.tests.ims;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.net.Uri;
+import android.os.Parcel;
+import android.support.test.runner.AndroidJUnit4;
+import android.telephony.ims.RcsGroupThread;
+import android.telephony.ims.RcsGroupThreadIconChangedEvent;
+import android.telephony.ims.RcsParticipant;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class RcsGroupThreadIconChangedEventTest {
+
+    @Test
+    public void testCanUnparcel() {
+        RcsGroupThread rcsGroupThread = new RcsGroupThread(1);
+        RcsParticipant rcsParticipant = new RcsParticipant(2);
+        Uri newIconUri = Uri.parse("content://new_icon");
+
+        RcsGroupThreadIconChangedEvent iconChangedEvent =
+                new RcsGroupThreadIconChangedEvent(1234567890, rcsGroupThread, rcsParticipant,
+                        newIconUri);
+
+        Parcel parcel = Parcel.obtain();
+        iconChangedEvent.writeToParcel(parcel, iconChangedEvent.describeContents());
+
+        parcel.setDataPosition(0);
+
+        iconChangedEvent = RcsGroupThreadIconChangedEvent.CREATOR.createFromParcel(parcel);
+
+        assertThat(iconChangedEvent.getNewIcon()).isEqualTo(newIconUri);
+        assertThat(iconChangedEvent.getRcsGroupThread().getThreadId()).isEqualTo(1);
+        assertThat(iconChangedEvent.getOriginatingParticipant().getId()).isEqualTo(2);
+        assertThat(iconChangedEvent.getTimestamp()).isEqualTo(1234567890);
+    }
+}
diff --git a/tests/RcsTests/src/com/android/tests/ims/RcsGroupThreadNameChangedEventTest.java b/tests/RcsTests/src/com/android/tests/ims/RcsGroupThreadNameChangedEventTest.java
new file mode 100644
index 0000000..1384c01
--- /dev/null
+++ b/tests/RcsTests/src/com/android/tests/ims/RcsGroupThreadNameChangedEventTest.java
@@ -0,0 +1,55 @@
+/*
+ * 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.tests.ims;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.Parcel;
+import android.support.test.runner.AndroidJUnit4;
+import android.telephony.ims.RcsGroupThread;
+import android.telephony.ims.RcsGroupThreadNameChangedEvent;
+import android.telephony.ims.RcsParticipant;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class RcsGroupThreadNameChangedEventTest {
+    @Test
+    public void testCanUnparcel() {
+        String newName = "new name";
+
+        RcsGroupThread rcsGroupThread = new RcsGroupThread(1);
+        RcsParticipant rcsParticipant = new RcsParticipant(2);
+
+        RcsGroupThreadNameChangedEvent nameChangedEvent =
+                new RcsGroupThreadNameChangedEvent(1234567890, rcsGroupThread, rcsParticipant,
+                        newName);
+
+        Parcel parcel = Parcel.obtain();
+        nameChangedEvent.writeToParcel(parcel, nameChangedEvent.describeContents());
+
+        parcel.setDataPosition(0);
+
+        nameChangedEvent = RcsGroupThreadNameChangedEvent.CREATOR.createFromParcel(
+                parcel);
+
+        assertThat(nameChangedEvent.getNewName()).isEqualTo(newName);
+        assertThat(nameChangedEvent.getRcsGroupThread().getThreadId()).isEqualTo(1);
+        assertThat(nameChangedEvent.getOriginatingParticipant().getId()).isEqualTo(2);
+        assertThat(nameChangedEvent.getTimestamp()).isEqualTo(1234567890);
+    }
+}
diff --git a/tests/RcsTests/src/com/android/tests/ims/RcsGroupThreadParticipantJoinedEventTest.java b/tests/RcsTests/src/com/android/tests/ims/RcsGroupThreadParticipantJoinedEventTest.java
new file mode 100644
index 0000000..d0af7db
--- /dev/null
+++ b/tests/RcsTests/src/com/android/tests/ims/RcsGroupThreadParticipantJoinedEventTest.java
@@ -0,0 +1,54 @@
+/*
+ * 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.tests.ims;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.Parcel;
+import android.support.test.runner.AndroidJUnit4;
+import android.telephony.ims.RcsGroupThread;
+import android.telephony.ims.RcsGroupThreadParticipantJoinedEvent;
+import android.telephony.ims.RcsParticipant;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class RcsGroupThreadParticipantJoinedEventTest {
+
+    @Test
+    public void testCanUnparcel() {
+        RcsGroupThread rcsGroupThread = new RcsGroupThread(1);
+        RcsParticipant rcsParticipant = new RcsParticipant(2);
+
+        RcsGroupThreadParticipantJoinedEvent participantJoinedEvent =
+                new RcsGroupThreadParticipantJoinedEvent(1234567890, rcsGroupThread, rcsParticipant,
+                        rcsParticipant);
+
+        Parcel parcel = Parcel.obtain();
+        participantJoinedEvent.writeToParcel(parcel, participantJoinedEvent.describeContents());
+
+        parcel.setDataPosition(0);
+
+        participantJoinedEvent = RcsGroupThreadParticipantJoinedEvent.CREATOR.createFromParcel(
+                parcel);
+
+        assertThat(participantJoinedEvent.getJoinedParticipant().getId()).isEqualTo(2);
+        assertThat(participantJoinedEvent.getRcsGroupThread().getThreadId()).isEqualTo(1);
+        assertThat(participantJoinedEvent.getOriginatingParticipant().getId()).isEqualTo(2);
+        assertThat(participantJoinedEvent.getTimestamp()).isEqualTo(1234567890);
+    }
+}
diff --git a/tests/RcsTests/src/com/android/tests/ims/RcsGroupThreadParticipantLeftEventTest.java b/tests/RcsTests/src/com/android/tests/ims/RcsGroupThreadParticipantLeftEventTest.java
new file mode 100644
index 0000000..7ba5fa6
--- /dev/null
+++ b/tests/RcsTests/src/com/android/tests/ims/RcsGroupThreadParticipantLeftEventTest.java
@@ -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.
+ */
+package com.android.tests.ims;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.Parcel;
+import android.support.test.runner.AndroidJUnit4;
+import android.telephony.ims.RcsGroupThread;
+import android.telephony.ims.RcsGroupThreadParticipantLeftEvent;
+import android.telephony.ims.RcsParticipant;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class RcsGroupThreadParticipantLeftEventTest {
+    @Test
+    public void testCanUnparcel() {
+        RcsGroupThread rcsGroupThread = new RcsGroupThread(1);
+        RcsParticipant rcsParticipant = new RcsParticipant(2);
+
+        RcsGroupThreadParticipantLeftEvent participantLeftEvent =
+                new RcsGroupThreadParticipantLeftEvent(1234567890, rcsGroupThread, rcsParticipant,
+                        rcsParticipant);
+
+        Parcel parcel = Parcel.obtain();
+        participantLeftEvent.writeToParcel(parcel, participantLeftEvent.describeContents());
+
+        parcel.setDataPosition(0);
+
+        // create from parcel
+        parcel.setDataPosition(0);
+        participantLeftEvent = RcsGroupThreadParticipantLeftEvent.CREATOR.createFromParcel(
+                parcel);
+        assertThat(participantLeftEvent.getRcsGroupThread().getThreadId()).isEqualTo(1);
+        assertThat(participantLeftEvent.getLeavingParticipantId().getId()).isEqualTo(2);
+        assertThat(participantLeftEvent.getTimestamp()).isEqualTo(1234567890);
+    }
+}
diff --git a/tests/RcsTests/src/com/android/tests/ims/RcsMessageStoreTest.java b/tests/RcsTests/src/com/android/tests/ims/RcsMessageStoreTest.java
deleted file mode 100644
index 44277ed..0000000
--- a/tests/RcsTests/src/com/android/tests/ims/RcsMessageStoreTest.java
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright (C) 2018 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.tests.ims;
-
-import android.support.test.runner.AndroidJUnit4;
-import android.telephony.ims.RcsMessageStore;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-public class RcsMessageStoreTest {
-    //TODO(sahinc): Add meaningful tests once we have more of the implementation in place
-    @Test
-    public void testDeleteThreadDoesntCrash() {
-        RcsMessageStore mRcsMessageStore = new RcsMessageStore();
-        mRcsMessageStore.deleteThread(0);
-    }
-}
diff --git a/tests/RcsTests/src/com/android/tests/ims/RcsParticipantAliasChangedEventTest.java b/tests/RcsTests/src/com/android/tests/ims/RcsParticipantAliasChangedEventTest.java
new file mode 100644
index 0000000..3e2bbbf
--- /dev/null
+++ b/tests/RcsTests/src/com/android/tests/ims/RcsParticipantAliasChangedEventTest.java
@@ -0,0 +1,57 @@
+/*
+ * 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.tests.ims;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.Parcel;
+import android.support.test.runner.AndroidJUnit4;
+import android.telephony.ims.RcsParticipant;
+import android.telephony.ims.RcsParticipantAliasChangedEvent;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class RcsParticipantAliasChangedEventTest {
+    private static final String OLD_ALIAS = "old alias";
+    private static final String NEW_ALIAS = "new alias";
+    private RcsParticipant mParticipant;
+
+    @Before
+    public void setUp() {
+        mParticipant = new RcsParticipant(3);
+    }
+
+    @Test
+    public void testCanUnparcel() {
+        RcsParticipantAliasChangedEvent aliasChangedEvent =
+                new RcsParticipantAliasChangedEvent(1234567890, mParticipant, NEW_ALIAS);
+
+        Parcel parcel = Parcel.obtain();
+        aliasChangedEvent.writeToParcel(parcel, aliasChangedEvent.describeContents());
+
+        parcel.setDataPosition(0);
+
+        aliasChangedEvent = RcsParticipantAliasChangedEvent.CREATOR.createFromParcel(
+                parcel);
+
+        assertThat(aliasChangedEvent.getParticipantId().getId()).isEqualTo(3);
+        assertThat(aliasChangedEvent.getNewAlias()).isEqualTo(NEW_ALIAS);
+        assertThat(aliasChangedEvent.getTimestamp()).isEqualTo(1234567890);
+    }
+}
diff --git a/tests/RcsTests/src/com/android/tests/ims/RcsParticipantQueryParamsTest.java b/tests/RcsTests/src/com/android/tests/ims/RcsParticipantQueryParamsTest.java
new file mode 100644
index 0000000..6361a39
--- /dev/null
+++ b/tests/RcsTests/src/com/android/tests/ims/RcsParticipantQueryParamsTest.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2018 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.tests.ims;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.Parcel;
+import android.support.test.runner.AndroidJUnit4;
+import android.telephony.ims.RcsParticipantQueryParams;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class RcsParticipantQueryParamsTest {
+
+    @Test
+    public void testCanUnparcel() {
+        RcsParticipantQueryParams rcsParticipantQueryParams =
+                new RcsParticipantQueryParams.Builder()
+                        .setAliasLike("%alias_")
+                        .setCanonicalAddressLike("_canonical%")
+                        .setSortProperty(RcsParticipantQueryParams.SORT_BY_CANONICAL_ADDRESS)
+                        .setSortDirection(true)
+                        .setResultLimit(432)
+                        .build();
+
+
+        Parcel parcel = Parcel.obtain();
+        rcsParticipantQueryParams.writeToParcel(parcel,
+                rcsParticipantQueryParams.describeContents());
+
+        parcel.setDataPosition(0);
+        rcsParticipantQueryParams = RcsParticipantQueryParams.CREATOR.createFromParcel(
+                parcel);
+
+        assertThat(rcsParticipantQueryParams.getAliasLike()).isEqualTo("%alias_");
+        assertThat(rcsParticipantQueryParams.getCanonicalAddressLike()).contains("_canonical%");
+        assertThat(rcsParticipantQueryParams.getLimit()).isEqualTo(432);
+        assertThat(rcsParticipantQueryParams.getSortingProperty()).isEqualTo(
+                RcsParticipantQueryParams.SORT_BY_CANONICAL_ADDRESS);
+        assertThat(rcsParticipantQueryParams.getSortDirection()).isTrue();
+    }
+}
diff --git a/tests/RcsTests/src/com/android/tests/ims/RcsParticipantTest.java b/tests/RcsTests/src/com/android/tests/ims/RcsParticipantTest.java
deleted file mode 100644
index c402dbf..0000000
--- a/tests/RcsTests/src/com/android/tests/ims/RcsParticipantTest.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2018 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.tests.ims;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.os.Bundle;
-import android.support.test.runner.AndroidJUnit4;
-import android.telephony.ims.RcsParticipant;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@RunWith(AndroidJUnit4.class)
-public class RcsParticipantTest {
-    private static final int ID = 123;
-    private static final String ALIAS = "alias";
-    private static final String CANONICAL_ADDRESS = "+1234567890";
-
-    @Test
-    public void testCanUnparcel() {
-        RcsParticipant rcsParticipant = new RcsParticipant(ID, CANONICAL_ADDRESS);
-        rcsParticipant.setAlias(ALIAS);
-
-        Bundle bundle = new Bundle();
-        bundle.putParcelable("Some key", rcsParticipant);
-        rcsParticipant = bundle.getParcelable("Some key");
-
-        assertThat(rcsParticipant.getId()).isEqualTo(ID);
-        assertThat(rcsParticipant.getAlias()).isEqualTo(ALIAS);
-        assertThat(rcsParticipant.getCanonicalAddress()).isEqualTo(CANONICAL_ADDRESS);
-    }
-}
diff --git a/tests/RcsTests/src/com/android/tests/ims/RcsThreadQueryParametersTest.java b/tests/RcsTests/src/com/android/tests/ims/RcsThreadQueryParametersTest.java
deleted file mode 100644
index a890a38..0000000
--- a/tests/RcsTests/src/com/android/tests/ims/RcsThreadQueryParametersTest.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2018 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.tests.ims;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import android.os.Bundle;
-import android.support.test.runner.AndroidJUnit4;
-import android.telephony.ims.RcsParticipant;
-import android.telephony.ims.RcsThreadQueryParameters;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.Mock;
-
-@RunWith(AndroidJUnit4.class)
-public class RcsThreadQueryParametersTest {
-    private RcsThreadQueryParameters mRcsThreadQueryParameters;
-    @Mock RcsParticipant mMockParticipant;
-
-    @Test
-    public void testUnparceling() {
-        String key = "some key";
-        mRcsThreadQueryParameters = RcsThreadQueryParameters.builder()
-                .isGroupThread(true)
-                .withParticipant(mMockParticipant)
-                .limitResultsTo(50)
-                .sort(true)
-                .build();
-
-        Bundle bundle = new Bundle();
-        bundle.putParcelable(key, mRcsThreadQueryParameters);
-        mRcsThreadQueryParameters = bundle.getParcelable(key);
-
-        assertThat(mRcsThreadQueryParameters.isGroupThread()).isTrue();
-        assertThat(mRcsThreadQueryParameters.getRcsParticipants()).contains(mMockParticipant);
-        assertThat(mRcsThreadQueryParameters.getLimit()).isEqualTo(50);
-        assertThat(mRcsThreadQueryParameters.isAscending()).isTrue();
-    }
-}
diff --git a/tests/RcsTests/src/com/android/tests/ims/RcsThreadQueryParamsTest.java b/tests/RcsTests/src/com/android/tests/ims/RcsThreadQueryParamsTest.java
new file mode 100644
index 0000000..beb4f8a
--- /dev/null
+++ b/tests/RcsTests/src/com/android/tests/ims/RcsThreadQueryParamsTest.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2018 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.tests.ims;
+
+import static android.telephony.ims.RcsThreadQueryParams.SORT_BY_TIMESTAMP;
+import static android.telephony.ims.RcsThreadQueryParams.THREAD_TYPE_GROUP;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.os.Parcel;
+import android.support.test.runner.AndroidJUnit4;
+import android.telephony.ims.RcsParticipant;
+import android.telephony.ims.RcsThreadQueryParams;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class RcsThreadQueryParamsTest {
+
+    @Test
+    public void testCanUnparcel() {
+        RcsParticipant rcsParticipant = new RcsParticipant(1);
+        RcsThreadQueryParams rcsThreadQueryParams = new RcsThreadQueryParams.Builder()
+                .setThreadType(THREAD_TYPE_GROUP)
+                .setParticipant(rcsParticipant)
+                .setResultLimit(50)
+                .setSortProperty(SORT_BY_TIMESTAMP)
+                .setSortDirection(true)
+                .build();
+
+        Parcel parcel = Parcel.obtain();
+        rcsThreadQueryParams.writeToParcel(parcel, rcsThreadQueryParams.describeContents());
+
+        parcel.setDataPosition(0);
+        rcsThreadQueryParams = RcsThreadQueryParams.CREATOR.createFromParcel(parcel);
+
+        assertThat(rcsThreadQueryParams.getThreadType()).isEqualTo(THREAD_TYPE_GROUP);
+        assertThat(rcsThreadQueryParams.getRcsParticipantsIds())
+                .contains(rcsParticipant.getId());
+        assertThat(rcsThreadQueryParams.getLimit()).isEqualTo(50);
+        assertThat(rcsThreadQueryParams.getSortingProperty()).isEqualTo(SORT_BY_TIMESTAMP);
+        assertThat(rcsThreadQueryParams.getSortDirection()).isTrue();
+    }
+}
diff --git a/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java b/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
index 4b277ae..f07ae9f 100644
--- a/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
+++ b/tests/RollbackTest/src/com/android/tests/rollback/RollbackTest.java
@@ -685,7 +685,7 @@
                             ActivityManager am = context.getSystemService(ActivityManager.class);
                             am.killBackgroundProcesses(TEST_APP_A);
                             // Allow another package launch
-                            crashQueue.offer(intent.getIntExtra("count", 0), 5, TimeUnit.SECONDS);
+                            crashQueue.put(intent.getIntExtra("count", 0));
                         } catch (InterruptedException e) {
                             fail("Failed to communicate with test app");
                         }
@@ -694,14 +694,9 @@
             context.registerReceiver(crashCountReceiver, crashCountFilter);
 
             // Start apps PackageWatchdog#TRIGGER_FAILURE_COUNT times so TEST_APP_A crashes
-            Integer crashCount = null;
             do {
                 RollbackTestUtils.launchPackage(TEST_APP_A);
-                crashCount = crashQueue.poll(5, TimeUnit.SECONDS);
-                if (crashCount == null) {
-                    fail("Timed out waiting for crash signal from test app");
-                }
-            } while(crashCount < 5);
+            } while(crashQueue.take() < 5);
 
             // TEST_APP_A is automatically rolled back by the RollbackPackageHealthObserver
             assertEquals(1, RollbackTestUtils.getInstalledVersion(TEST_APP_A));
diff --git a/tests/utils/testutils/java/android/view/test/InsetsModeSession.java b/tests/utils/testutils/java/android/view/test/InsetsModeSession.java
new file mode 100644
index 0000000..c83dfa4
--- /dev/null
+++ b/tests/utils/testutils/java/android/view/test/InsetsModeSession.java
@@ -0,0 +1,37 @@
+/*
+ * 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.view.test;
+
+import android.view.ViewRootImpl;
+
+/**
+ * Session to set insets mode for {@link ViewRootImpl#sNewInsetsMode}.
+ */
+public class InsetsModeSession implements AutoCloseable {
+
+    private int mOldMode;
+
+    public InsetsModeSession(int flag) {
+        mOldMode = ViewRootImpl.sNewInsetsMode;
+        ViewRootImpl.sNewInsetsMode = flag;
+    }
+
+    @Override
+    public void close() throws Exception {
+        ViewRootImpl.sNewInsetsMode = mOldMode;
+    }
+}
diff --git a/tools/stats_log_api_gen/Collation.cpp b/tools/stats_log_api_gen/Collation.cpp
index 257043b..a8d970e 100644
--- a/tools/stats_log_api_gen/Collation.cpp
+++ b/tools/stats_log_api_gen/Collation.cpp
@@ -48,6 +48,7 @@
       primaryFields(that.primaryFields),
       exclusiveField(that.exclusiveField),
       uidField(that.uidField),
+      whitelisted(that.whitelisted),
       binaryFields(that.binaryFields) {}
 
 AtomDecl::AtomDecl(int c, const string& n, const string& m)
@@ -162,6 +163,7 @@
                  vector<java_type_t> *signature) {
 
   int errorCount = 0;
+
   // Build a sorted list of the fields. Descriptor has them in source file
   // order.
   map<int, const FieldDescriptor *> fields;
@@ -387,6 +389,11 @@
 
     const Descriptor *atom = atomField->message_type();
     AtomDecl atomDecl(atomField->number(), atomField->name(), atom->name());
+
+    if (atomField->options().GetExtension(os::statsd::allow_from_any_uid) == true) {
+      atomDecl.whitelisted = true;
+    }
+
     vector<java_type_t> signature;
     errorCount += collate_atom(atom, &atomDecl, &signature);
     if (atomDecl.primaryFields.size() != 0 && atomDecl.exclusiveField == 0) {
diff --git a/tools/stats_log_api_gen/Collation.h b/tools/stats_log_api_gen/Collation.h
index 450b305..6b86b862 100644
--- a/tools/stats_log_api_gen/Collation.h
+++ b/tools/stats_log_api_gen/Collation.h
@@ -89,6 +89,8 @@
 
     int uidField = 0;
 
+    bool whitelisted = false;
+
     vector<int> binaryFields;
 
     AtomDecl();
diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp
index 4491a85..0270c72 100644
--- a/tools/stats_log_api_gen/main.cpp
+++ b/tools/stats_log_api_gen/main.cpp
@@ -158,6 +158,20 @@
             }
         }
     }
+
+    fprintf(out, "};\n");
+    fprintf(out, "\n");
+
+    fprintf(out,
+            "const std::set<int> AtomsInfo::kWhitelistedAtoms = {\n");
+    for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
+         atom != atoms.decls.end(); atom++) {
+        if (atom->whitelisted) {
+            string constant = make_constant_name(atom->name);
+            fprintf(out, " %s,\n", constant.c_str());
+        }
+    }
+
     fprintf(out, "};\n");
     fprintf(out, "\n");
 
@@ -674,7 +688,7 @@
     build_non_chained_decl_map(atoms, &atom_code_to_non_chained_decl_map);
 
     size_t i = 0;
-    // Print constants
+    // Print atom constants
     for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
         atom != atoms.decls.end(); atom++) {
         string constant = make_constant_name(atom->name);
@@ -700,6 +714,30 @@
     fprintf(out, "};\n");
     fprintf(out, "\n");
 
+    // Print constants for the enum values.
+    fprintf(out, "//\n");
+    fprintf(out, "// Constants for enum values\n");
+    fprintf(out, "//\n\n");
+    for (set<AtomDecl>::const_iterator atom = atoms.decls.begin();
+        atom != atoms.decls.end(); atom++) {
+        for (vector<AtomField>::const_iterator field = atom->fields.begin();
+            field != atom->fields.end(); field++) {
+            if (field->javaType == JAVA_TYPE_ENUM) {
+                fprintf(out, "// Values for %s.%s\n", atom->message.c_str(),
+                    field->name.c_str());
+                for (map<int, string>::const_iterator value = field->enumValues.begin();
+                    value != field->enumValues.end(); value++) {
+                    fprintf(out, "const int32_t %s__%s__%s = %d;\n",
+                        make_constant_name(atom->message).c_str(),
+                        make_constant_name(field->name).c_str(),
+                        make_constant_name(value->second).c_str(),
+                        value->first);
+                }
+                fprintf(out, "\n");
+            }
+        }
+    }
+
     fprintf(out, "struct BytesField {\n");
     fprintf(out,
             "  BytesField(char const* array, size_t len) : arg(array), "
@@ -728,6 +766,8 @@
     fprintf(out,
             "  const static std::map<int, std::vector<int>> "
             "kBytesFieldAtoms;");
+    fprintf(out,
+            "  const static std::set<int> kWhitelistedAtoms;\n");
     fprintf(out, "};\n");
 
     fprintf(out, "const static int kMaxPushedAtomId = %d;\n\n",
diff --git a/tools/stats_log_api_gen/test.proto b/tools/stats_log_api_gen/test.proto
index 3be87d9..24ebf4d 100644
--- a/tools/stats_log_api_gen/test.proto
+++ b/tools/stats_log_api_gen/test.proto
@@ -195,4 +195,22 @@
             [(android.os.statsd.state_field_option).option = PRIMARY];
     optional int32 state = 3
             [(android.os.statsd.state_field_option).option = EXCLUSIVE];
+}
+
+message WhitelistedAtom {
+  optional int32 field = 1;
+}
+
+message NonWhitelistedAtom {
+  optional int32 field = 1;
+}
+
+message ListedAtoms {
+  oneof event {
+    // Atoms can be whitelisted i.e. they can be triggered by any source
+    WhitelistedAtom whitelisted_atom = 1 [(android.os.statsd.allow_from_any_uid) = true];
+    // Atoms are not whitelisted by default, so they can only be triggered
+    // by whitelisted sources
+    NonWhitelistedAtom non_whitelisted_atom = 2;
+  }
 }
\ No newline at end of file
diff --git a/tools/stats_log_api_gen/test_collation.cpp b/tools/stats_log_api_gen/test_collation.cpp
index ad3bffac..dc585c1 100644
--- a/tools/stats_log_api_gen/test_collation.cpp
+++ b/tools/stats_log_api_gen/test_collation.cpp
@@ -226,5 +226,25 @@
     EXPECT_TRUE(errorCount > 0);
 }
 
+TEST(CollationTest, PassOnWhitelistedAtom) {
+    Atoms atoms;
+    int errorCount =
+            collate_atoms(ListedAtoms::descriptor(), &atoms);
+    EXPECT_EQ(errorCount, 0);
+    EXPECT_EQ(atoms.decls.size(), 2ul);
+}
+
+TEST(CollationTest, RecogniseWhitelistedAtom) {
+    Atoms atoms;
+    collate_atoms(ListedAtoms::descriptor(), &atoms);
+    for (const auto& atomDecl : atoms.decls) {
+        if (atomDecl.code == 1) {
+            EXPECT_TRUE(atomDecl.whitelisted);
+        } else {
+            EXPECT_FALSE(atomDecl.whitelisted);
+        }
+    }
+}
+
 }  // namespace stats_log_api_gen
 }  // namespace android
\ No newline at end of file
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index c5b9cf1..3881e9e 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -969,7 +969,8 @@
 
     /**
      * Returns MAC address set to be the local randomized MAC address.
-     * Does not guarantee that the returned address is valid for use.
+     * Depending on user preference, the device may or may not use the returned MAC address for
+     * connections to this network.
      * <p>
      * Information is restricted to Device Owner, Profile Owner, and Carrier apps
      * (which will only obtain addresses for configurations which they create). Other callers
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 289f99d..2cc1d83 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -981,7 +981,7 @@
      * @deprecated This API is non-functional and will have no impact.
      */
     @Deprecated
-    public static final int WIFI_MODE_FULL = 1;
+    public static final int WIFI_MODE_FULL = WifiProtoEnums.WIFI_MODE_FULL; // 1
 
     /**
      * In this Wi-Fi lock mode, Wi-Fi will be kept active,
@@ -995,7 +995,7 @@
      * @deprecated This API is non-functional and will have no impact.
      */
     @Deprecated
-    public static final int WIFI_MODE_SCAN_ONLY = 2;
+    public static final int WIFI_MODE_SCAN_ONLY = WifiProtoEnums.WIFI_MODE_SCAN_ONLY; // 2
 
     /**
      * In this Wi-Fi lock mode, Wi-Fi will not go to power save.
@@ -1013,7 +1013,7 @@
      * When there is no support from the hardware, the {@link #WIFI_MODE_FULL_HIGH_PERF}
      * lock will have no impact.
      */
-    public static final int WIFI_MODE_FULL_HIGH_PERF = 3;
+    public static final int WIFI_MODE_FULL_HIGH_PERF = WifiProtoEnums.WIFI_MODE_FULL_HIGH_PERF; // 3
 
     /**
      * In this Wi-Fi lock mode, Wi-Fi will operate with a priority to achieve low latency.
@@ -1037,15 +1037,13 @@
      * Example use cases are real time gaming or virtual reality applications where
      * low latency is a key factor for user experience.
      * <p>
-     * When there is no support from the hardware, the {@link #WIFI_MODE_FULL_LOW_LATENCY}
-     * lock will cause the device not to go power save.
-     * <p>
      * Note: For an app which acquires both {@link #WIFI_MODE_FULL_LOW_LATENCY} and
      * {@link #WIFI_MODE_FULL_HIGH_PERF} locks, {@link #WIFI_MODE_FULL_LOW_LATENCY}
      * lock will be effective when app is running in foreground and screen is on,
      * while the {@link #WIFI_MODE_FULL_HIGH_PERF} lock will take effect otherwise.
      */
-    public static final int WIFI_MODE_FULL_LOW_LATENCY = 4;
+    public static final int WIFI_MODE_FULL_LOW_LATENCY =
+            WifiProtoEnums.WIFI_MODE_FULL_LOW_LATENCY; // 4
 
     /** Anything worse than or equal to this will show 0 bars. */
     @UnsupportedAppUsage
@@ -4876,4 +4874,4 @@
             throw e.rethrowFromSystemServer();
         }
     }
-}
\ No newline at end of file
+}
diff --git a/wifi/java/android/net/wifi/WifiNetworkSpecifier.java b/wifi/java/android/net/wifi/WifiNetworkSpecifier.java
index a69c7a5..333b82c 100644
--- a/wifi/java/android/net/wifi/WifiNetworkSpecifier.java
+++ b/wifi/java/android/net/wifi/WifiNetworkSpecifier.java
@@ -421,7 +421,7 @@
          *      .setSsidPattern(new PatternMatcher("test", PatterMatcher.PATTERN_PREFIX))
          *      .setBssidPattern(MacAddress.fromString("10:03:23:00:00:00"),
          *                       MacAddress.fromString("ff:ff:ff:00:00:00"))
-         *      .buildNetworkSpecifier()
+         *      .build()
          * final NetworkRequest request =
          *      new NetworkRequest.Builder()
          *      .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
diff --git a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
index 460c633..233fa2c 100644
--- a/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
+++ b/wifi/java/android/net/wifi/WifiNetworkSuggestion.java
@@ -413,17 +413,17 @@
          * final WifiNetworkSuggestion suggestion1 =
          *      new Builder()
          *      .setSsid("test111111")
-         *      .buildNetworkSuggestion()
+         *      .build()
          * final WifiNetworkSuggestion suggestion2 =
          *      new Builder()
          *      .setSsid("test222222")
          *      .setWpa2Passphrase("test123456")
-         *      .buildNetworkSuggestion()
+         *      .build()
          * final WifiNetworkSuggestion suggestion3 =
          *      new Builder()
          *      .setSsid("test333333")
          *      .setWpa3Passphrase("test6789")
-         *      .buildNetworkSuggestion()
+         *      .build()
          * final List<WifiNetworkSuggestion> suggestionsList =
          *      new ArrayList<WifiNetworkSuggestion> {{
          *          add(suggestion1);