Merge "Disallow access to IGraphicsStats$Stub starting with Q"
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 7f526bb..f8a164d 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
@@ -19447,9 +19423,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 +19442,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 +22620,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 +22646,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 +23725,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 +23881,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";
@@ -34202,7 +34182,6 @@
   }
 
   public static class Build.Partition {
-    ctor public Build.Partition();
     method public long getBuildTimeMillis();
     method @NonNull public String getFingerprint();
     method @NonNull public String getName();
@@ -41360,6 +41339,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 +41685,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();
@@ -42454,6 +42439,7 @@
     method public static java.io.FileDescriptor accept(java.io.FileDescriptor, java.net.InetSocketAddress) throws android.system.ErrnoException, java.net.SocketException;
     method public static boolean access(String, int) throws android.system.ErrnoException;
     method public static void bind(java.io.FileDescriptor, java.net.InetAddress, int) throws android.system.ErrnoException, java.net.SocketException;
+    method public static void bind(java.io.FileDescriptor, java.net.SocketAddress) throws android.system.ErrnoException, java.net.SocketException;
     method public static void chmod(String, int) throws android.system.ErrnoException;
     method public static void chown(String, int, int) throws android.system.ErrnoException;
     method public static void close(java.io.FileDescriptor) throws android.system.ErrnoException;
@@ -42522,6 +42508,7 @@
     method public static long sendfile(java.io.FileDescriptor, java.io.FileDescriptor, android.system.Int64Ref, long) throws android.system.ErrnoException;
     method public static int sendto(java.io.FileDescriptor, java.nio.ByteBuffer, int, java.net.InetAddress, int) throws android.system.ErrnoException, java.net.SocketException;
     method public static int sendto(java.io.FileDescriptor, byte[], int, int, int, java.net.InetAddress, int) throws android.system.ErrnoException, java.net.SocketException;
+    method public static int sendto(java.io.FileDescriptor, byte[], int, int, int, java.net.SocketAddress) throws android.system.ErrnoException, java.net.SocketException;
     method @Deprecated public static void setegid(int) throws android.system.ErrnoException;
     method public static void setenv(String, String, boolean) throws android.system.ErrnoException;
     method @Deprecated public static void seteuid(int) throws android.system.ErrnoException;
@@ -45163,13 +45150,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
@@ -49563,6 +49550,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();
@@ -49574,6 +49562,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);
@@ -50319,6 +50308,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();
@@ -50349,6 +50340,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();
@@ -50643,6 +50635,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);
@@ -54858,6 +54851,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();
@@ -54872,6 +54866,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();
@@ -54899,9 +54894,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);
@@ -54920,6 +54917,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);
@@ -55552,6 +55550,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();
@@ -55559,8 +55558,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 {
@@ -56296,6 +56297,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();
@@ -56308,30 +56310,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);
@@ -56365,7 +56374,11 @@
     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();
@@ -56389,7 +56402,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);
@@ -56653,6 +56670,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..262ffec 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 {
diff --git a/api/system-current.txt b/api/system-current.txt
index a0eef1d..d1a8a56 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -711,6 +711,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 +1072,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 +3914,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 +5003,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 +5029,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 {
@@ -5703,7 +5709,6 @@
     method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static void resetToDefaults(int, @Nullable String);
     method @RequiresPermission(android.Manifest.permission.WRITE_DEVICE_CONFIG) public static boolean setProperty(String, String, String, boolean);
     field public static final String NAMESPACE_AUTOFILL = "autofill";
-    field public static final String NAMESPACE_CONTENT_CAPTURE = "content_capture";
     field public static final String NAMESPACE_GAME_DRIVER = "game_driver";
     field public static final String NAMESPACE_INPUT_NATIVE_BOOT = "input_native_boot";
     field public static final String NAMESPACE_NETD_NATIVE = "netd_native";
@@ -5771,11 +5776,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 +6035,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..b977f87 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -429,11 +429,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 +767,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 +935,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,10 +1784,16 @@
   }
 
   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);
   }
 
+  public static interface DeviceConfig.ContentCapture {
+    field public static final String NAMESPACE = "content_capture";
+    field public static final String PROPERTY_CONTENTCAPTURE_ENABLED = "enable_contentcapture";
+  }
+
   public static interface DeviceConfig.Privacy {
     field public static final String NAMESPACE = "privacy";
     field public static final String PROPERTY_LOCATION_ACCESS_CHECK_ENABLED = "location_access_check_enabled";
@@ -1851,6 +1859,7 @@
     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_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";
@@ -2577,6 +2586,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 +2676,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 {
@@ -2712,6 +2727,66 @@
 
   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..2fef407 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",
     ],
@@ -93,6 +94,7 @@
         "tests/PrettyPrintVisitorTests.cpp",
         "tests/RawPrintVisitorTests.cpp",
         "tests/ResourceUtilsTests.cpp",
+        "tests/ResultTests.cpp",
         "tests/XmlTests.cpp",
         "tests/ZipFileTests.cpp",
     ],
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/libidmap2/Idmap.cpp b/cmds/idmap2/libidmap2/Idmap.cpp
index fa5ac8e..b19d7a9 100644
--- a/cmds/idmap2/libidmap2/Idmap.cpp
+++ b/cmds/idmap2/libidmap2/Idmap.cpp
@@ -117,6 +117,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 +159,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 +179,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;
@@ -356,14 +362,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/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..250f5bf 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,70 @@
     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<const MetricProducer*> acrtiveMetrics;
+        pair.second->getActiveMetrics(acrtiveMetrics);
+        for (const MetricProducer* metric : acrtiveMetrics) {
+            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..77d9a2f 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,8 @@
     FRIEND_TEST(StatsLogProcessorTest, TestRateLimitByteSize);
     FRIEND_TEST(StatsLogProcessorTest, TestRateLimitBroadcast);
     FRIEND_TEST(StatsLogProcessorTest, TestDropWhenByteSizeTooLarge);
+    FRIEND_TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead);
+
     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/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..d0974d6 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;
@@ -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;
 }
 
 /**
@@ -5344,6 +5349,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..b071682 100644
--- a/cmds/statsd/src/external/PullDataReceiver.h
+++ b/cmds/statsd/src/external/PullDataReceiver.h
@@ -28,9 +28,15 @@
 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.
+   */
+  virtual void onDataPulled(const std::vector<std::shared_ptr<LogEvent>>& data, 
+                            bool pullSuccess) = 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..991bef4 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);
+                // 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..c774719 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.cpp
+++ b/cmds/statsd/src/guardrail/StatsdStats.cpp
@@ -423,31 +423,41 @@
     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++;
+}
+
 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..ed42b1f 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.h
+++ b/cmds/statsd/src/guardrail/StatsdStats.h
@@ -342,27 +342,37 @@
     /**
      * 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);
 
     /**
      * Reset the historical stats. Including all stats in icebox, and the tracked stats about
@@ -408,6 +418,8 @@
         long skippedForwardBuckets = 0;
         long badValueType = 0;
         long conditionChangeInNextBucket = 0;
+        long invalidatedBucket = 0;
+        long bucketDropped = 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..2609937 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) {
     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..d480941 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) 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..b362e37 100644
--- a/cmds/statsd/src/metrics/MetricProducer.cpp
+++ b/cmds/statsd/src/metrics/MetricProducer.cpp
@@ -112,6 +112,28 @@
     mIsActive = true;
 }
 
+void MetricProducer::setActiveLocked(int64_t currentTimeNs, int64_t remainingTtlNs) {
+    if (mEventActivationMap.size() == 0) {
+        return;
+    }
+    auto& activation = mEventActivationMap.begin()->second;
+    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);
+}
+
+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;
+}
 
 }  // namespace statsd
 }  // namespace os
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index 09e2409..ca37bbb 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -179,10 +179,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,6 +213,11 @@
         activateLocked(activationTrackerIndex, elapsedTimestampNs);
     }
 
+    bool isActive() const {
+        std::lock_guard<std::mutex> lock(mMutex);
+        return isActiveLocked();
+    }
+
     void addActivation(int activationTrackerIndex, int64_t ttl_seconds);
 
     void flushIfExpire(int64_t elapsedTimestampNs);
@@ -227,6 +243,10 @@
         return mIsActive;
     }
 
+    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.
@@ -348,6 +368,8 @@
     bool mIsActive;
 
     FRIEND_TEST(MetricActivationE2eTest, TestCountMetric);
+
+    FRIEND_TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead);
 };
 
 }  // 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..fdc28ea 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,20 @@
     // Does not change the state.
     virtual size_t byteSize();
 
+    inline bool isActive() const {
+        return mIsActive;
+    }
+
+    inline void getActiveMetrics(std::vector<const MetricProducer*>& metrics) const {
+        for (const auto& metric : mAllMetricProducers) {
+            if (metric->isActive()) {
+                metrics.push_back(metric.get());
+            }
+        }
+    }
+
+    void setActiveMetrics(ActiveConfig config, int64_t currentTimeNs);
+
 private:
     // For test only.
     inline int64_t getTtlEndNs() const { return mTtlEndNs; }
@@ -216,6 +235,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 +269,8 @@
     FRIEND_TEST(AlarmE2eTest, TestMultipleAlarms);
     FRIEND_TEST(ConfigTtlE2eTest, TestCountMetric);
     FRIEND_TEST(MetricActivationE2eTest, TestCountMetric);
+
+    FRIEND_TEST(StatsLogProcessorTest, TestActiveConfigMetricDiskWriteRead);
 };
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index 6aa8e84..1bd3ef2 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,19 +358,20 @@
     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;
+    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);
-        StatsdStats::getInstance().notePullDelay(mPullTagId, pullDelayNs);
-        resetBase();
+        // We are missing one pull from the bucket which means we will not have a complete view of
+        // what's going on.
+        invalidateCurrentBucket();
         return;
     }
-    StatsdStats::getInstance().notePullDelay(mPullTagId, pullDelayNs);
 
     if (timestampNs < mCurrentBucketStartTimeNs) {
         // The data will be skipped in onMatchedLogEventInternalLocked, but we don't want to report
@@ -382,9 +395,16 @@
     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) {
     std::lock_guard<std::mutex> lock(mMutex);
     if (mCondition) {
+        if (!pullSuccess) {
+            // If the pull failed, we won't be able to compute a diff.
+            invalidateCurrentBucket();
+            return;
+        }
+
         if (allData.size() == 0) {
             VLOG("Data pulled is empty");
             StatsdStats::getInstance().noteEmptyData(mPullTagId);
@@ -399,12 +419,13 @@
         // 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) {
+        bool isEventLate = bucketEndTime < mCurrentBucketStartTimeNs;
+        if (isEventLate) {
             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) ==
@@ -414,6 +435,10 @@
             }
         }
         mHasGlobalBase = true;
+
+        // We can probably flush the bucket. Since we used bucketEndTime when calling
+        // #onMatchedLogEventInternalLocked, the current bucket will not have been flushed.
+        flushIfNeededLocked(realEventTime);
     } else {
         VLOG("No need to commit data on condition false.");
     }
@@ -679,31 +704,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 +721,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 +810,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..0cfefa9 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) 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;
@@ -155,6 +160,11 @@
 
     void pullAndMatchEventsLocked(const int64_t timestampNs);
 
+    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 +196,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 +213,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 +233,15 @@
     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);
 };
 
 }  // namespace statsd
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
index cca09ac..73aab48 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -417,6 +417,8 @@
       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;
     }
     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..f76a9ad 100644
--- a/cmds/statsd/src/stats_log_util.cpp
+++ b/cmds/statsd/src/stats_log_util.cpp
@@ -78,6 +78,8 @@
 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;
 
 namespace {
 
@@ -494,6 +496,10 @@
                        (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->end(token);
 }
 
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..64008b5 100644
--- a/cmds/statsd/tests/StatsLogProcessor_test.cpp
+++ b/cmds/statsd/tests/StatsLogProcessor_test.cpp
@@ -286,6 +286,294 @@
     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);
+}
+
 #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..1725160 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);
     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);
     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);
     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);
     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);
     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);
 
     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);
 
     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);
     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);
     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);
     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);
     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..91b98ec 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);
     // 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);
     // 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);
     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);
+
+    // 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);
     // 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);
+    // 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);
     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);
     // 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);
     // 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);
     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);
     // 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);
     // 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);
     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);
 
     // 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);
     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);
+    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);
     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);
     // 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);
     // 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);
     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);
 
     curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
     EXPECT_EQ(false, curInterval.hasBase);
@@ -1224,7 +1299,7 @@
     event->write(110);
     event->init();
     allData.push_back(event);
-    valueProducer.onDataPulled(allData);
+    valueProducer.onDataPulled(allData, /** succeed */ true);
 
     curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
     EXPECT_EQ(true, curInterval.hasBase);
@@ -1677,11 +1752,11 @@
     allData.push_back(event1);
     allData.push_back(event2);
 
-    valueProducer.onDataPulled(allData);
+    valueProducer.onDataPulled(allData, /** succeed */ true);
     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);
     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);
 
-    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);
 
     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);
     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);
 
-    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);
 
-    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);
+    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);
+    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,34 +2226,334 @@
                                       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(0UL, valueProducer.mPastBuckets.size());
     EXPECT_EQ(true, valueProducer.mHasGlobalBase);
+}
 
-    valueProducer.onConditionChanged(false, bucket2StartTimeNs + 1);
+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);
 
-    // has one slice
+    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);
+
+    // 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);
+
+    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);
+
+    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);
+
+    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);
+
+    // 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);
+
+    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);
 }
 
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.txt b/config/hiddenapi-greylist.txt
index b1c4cd2..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
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/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/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..3ff6973 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -6408,11 +6408,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 {
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..04d5c5a 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;
@@ -130,20 +131,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 +154,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,7 +170,7 @@
      * 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.
@@ -181,6 +182,22 @@
     public static final String ROLE_ASSISTANT = "android.app.role.ASSISTANT";
 
     /**
+     * @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
+    public static final int MANAGE_HOLDERS_FLAG_DONT_KILL_APP = 1;
+
+    /**
      * The action used to request user approval of a role for an application.
      *
      * @hide
@@ -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/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 6044914..5020a94 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);
                 }
             }
         }
@@ -2175,12 +2170,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 +2493,7 @@
                     newPermsMsg.append(' ');
                 }
                 newPermsMsg.append(npi.name);
-                addRequestedPermission(pkg, npi.name);
+                pkg.requestedPermissions.add(npi.name);
                 pkg.implicitPermissions.add(npi.name);
             }
         }
@@ -2519,7 +2514,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 +2594,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 +2640,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
@@ -2987,8 +2976,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 +3001,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 +3033,6 @@
                     + parser.getPositionDescription());
         }
 
-        UsesPermissionInfo info = new UsesPermissionInfo(name, dataSentOffDevice,
-                dataSharedWithThirdParty, dataUsedForMonetization, retention, retentionWeeks);
-        pkg.usesPermissionInfos.add(info);
-
         return true;
     }
 
@@ -3420,10 +3367,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 +5203,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 +6568,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 +7099,6 @@
 
             dest.readStringList(requestedPermissions);
             internStringArrayList(requestedPermissions);
-            dest.readParcelableList(usesPermissionInfos, boot);
             dest.readStringList(implicitPermissions);
             internStringArrayList(implicitPermissions);
             protectedBroadcasts = dest.createStringArrayList();
@@ -7323,7 +7266,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..faf17e0 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -1051,6 +1051,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,
@@ -1419,6 +1427,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);
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/IRollbackManager.aidl b/core/java/android/content/rollback/IRollbackManager.aidl
index d951756..db9fcb6 100644
--- a/core/java/android/content/rollback/IRollbackManager.aidl
+++ b/core/java/android/content/rollback/IRollbackManager.aidl
@@ -47,4 +47,8 @@
     //
     // NOTE: This call is synchronous.
     boolean notifyStagedSession(int sessionId);
+
+    // Used by the staging manager to notify the RollbackManager of the apk
+    // session for a staged session.
+    void notifyStagedApkSession(int originalSessionId, int apkSessionId);
 }
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/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..d67d98c 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -77,6 +77,7 @@
      * @hide
      */
     @SystemApi
+    @TestApi
     public interface ContentCapture {
         String NAMESPACE = "content_capture";
 
@@ -101,19 +102,11 @@
          * @hide
          */
         // TODO(b/121153631): revert back to SERVICE_EXPLICITLY_ENABLED approach
+        @TestApi
         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
-    public static final String NAMESPACE_CONTENT_CAPTURE = "content_capture";
-
-    /**
      * Namespace for all input-related features that are used at the native level.
      * These features are applied at reboot.
      *
@@ -154,21 +147,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 +353,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/Settings.java b/core/java/android/provider/Settings.java
index 90749bb..e95d6046 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -8294,6 +8294,16 @@
         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 +8614,7 @@
             ASSIST_GESTURE_WAKE_ENABLED,
             VR_DISPLAY_MODE,
             NOTIFICATION_BADGING,
+            NOTIFICATION_BUBBLES,
             NOTIFICATION_DISMISS_RTL,
             QS_AUTO_ADDED_TILES,
             SCREENSAVER_ENABLED,
@@ -8766,6 +8777,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 +9300,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 +14029,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..03e8a0f 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;
@@ -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/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..ff4ee9c 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;
@@ -281,7 +282,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/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/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/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/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/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/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/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/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 4dd7d3a..1f8a908 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -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;
 
     /**
@@ -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;
@@ -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;
 
@@ -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/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/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..88d9380 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,22 +476,39 @@
     }
 
     /**
-     * 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;
+    }
+
+    /**
+     * <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) {
+    public void setEpicenterBounds(@Nullable Rect bounds) {
         mEpicenterBounds = bounds;
     }
 
@@ -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..6b48c65 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;
@@ -393,6 +406,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
diff --git a/core/java/android/widget/ScrollView.java b/core/java/android/widget/ScrollView.java
index fc4e9ec..24bc9f1 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;
 
     /**
@@ -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/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/NotificationBackupHelper.java b/core/java/com/android/server/backup/NotificationBackupHelper.java
index 0d225e8..7d4f8f7 100644
--- a/core/java/com/android/server/backup/NotificationBackupHelper.java
+++ b/core/java/com/android/server/backup/NotificationBackupHelper.java
@@ -18,9 +18,7 @@
 
 import android.app.INotificationManager;
 import android.app.backup.BlobBackupHelper;
-import android.content.Context;
 import android.os.ServiceManager;
-import android.os.UserHandle;
 import android.util.Log;
 import android.util.Slog;
 
@@ -34,9 +32,11 @@
     // Key under which the payload blob is stored
     static final String KEY_NOTIFICATIONS = "notifications";
 
-    public NotificationBackupHelper(Context context) {
+    private final int mUserId;
+
+    public NotificationBackupHelper(int userId) {
         super(BLOB_VERSION, KEY_NOTIFICATIONS);
-        // context is currently unused
+        mUserId = userId;
     }
 
     @Override
@@ -46,8 +46,7 @@
             try {
                 INotificationManager nm = INotificationManager.Stub.asInterface(
                         ServiceManager.getService("notification"));
-                // TODO: http://b/22388012
-                newPayload = nm.getBackupPayload(UserHandle.USER_SYSTEM);
+                newPayload = nm.getBackupPayload(mUserId);
             } catch (Exception e) {
                 // Treat as no data
                 Slog.e(TAG, "Couldn't communicate with notification manager");
@@ -67,8 +66,7 @@
             try {
                 INotificationManager nm = INotificationManager.Stub.asInterface(
                         ServiceManager.getService("notification"));
-                // TODO: http://b/22388012
-                nm.applyRestore(payload, UserHandle.USER_SYSTEM);
+                nm.applyRestore(payload, mUserId);
             } catch (Exception e) {
                 Slog.e(TAG, "Couldn't communicate with notification manager");
             }
diff --git a/core/java/com/android/server/backup/SystemBackupAgent.java b/core/java/com/android/server/backup/SystemBackupAgent.java
index 8878421..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);
+            PERMISSION_HELPER, NOTIFICATION_HELPER, SYNC_SETTINGS_HELPER);
 
     private int mUserId = UserHandle.USER_SYSTEM;
 
@@ -91,9 +91,9 @@
 
         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(this));
+        addHelper(NOTIFICATION_HELPER, new NotificationBackupHelper(mUserId));
         addHelper(PERMISSION_HELPER, new PermissionBackupHelper(mUserId));
         addHelper(USAGE_STATS_HELPER, new UsageStatsBackupHelper(this));
         addHelper(SHORTCUT_MANAGER_HELPER, new ShortcutBackupHelper());
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..d493ddf 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -1105,6 +1105,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 +1496,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},
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..bbe89d6 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -620,15 +620,10 @@
 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,
@@ -646,7 +641,8 @@
 
 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, 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,6 +651,10 @@
             StringAppendF(&mntTarget, "/%d", userId);
         }
 
+        std::string sandboxSource = StringPrintf("%s/Android/sandbox/%s",
+            mntSource.c_str(), sandboxId.c_str());
+        BindMount(sandboxSource, mntTarget, fail_fn);
+
         for (auto& package : packageNames) {
             MountPkgSpecificDir(mntSource, mntTarget, package, "data", fail_fn);
             MountPkgSpecificDir(mntSource, mntTarget, package, "media", fail_fn);
@@ -676,7 +676,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 +728,7 @@
                                      strerror(errno)));
             }
         } else {
-            if (package_name.empty()) {
+            if (package_name.empty() || sandbox_id.empty()) {
                 return;
             }
 
@@ -773,7 +774,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, fail_fn);
             }
         }
     } else {
@@ -1110,7 +1111,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 +1121,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 +1164,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 +1464,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 +1496,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 +1522,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 +1676,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 +1775,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 +1790,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/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..07dd26e 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.
@@ -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_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..ec53811 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
@@ -2632,6 +2632,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 +3425,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/public.xml b/core/res/res/values/public.xml
index e7d8102..e6d478a 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">
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index fadb28f..75a91eb 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1512,7 +1512,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 +1555,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 +1594,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..3f63628 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2521,6 +2521,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 +2752,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 +3159,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" />
@@ -3596,7 +3603,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" />
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/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/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/libs/androidfw/AssetManager2.cpp b/libs/androidfw/AssetManager2.cpp
index 20303eb..81afd93 100644
--- a/libs/androidfw/AssetManager2.cpp
+++ b/libs/androidfw/AssetManager2.cpp
@@ -704,9 +704,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/include/androidfw/AssetManager2.h b/libs/androidfw/include/androidfw/AssetManager2.h
index f29769b..d862182 100644
--- a/libs/androidfw/include/androidfw/AssetManager2.h
+++ b/libs/androidfw/include/androidfw/AssetManager2.h
@@ -237,6 +237,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 +357,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/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/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/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/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/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/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/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/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/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/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/src/com/android/keyguard/KeyguardClockSwitch.java b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
index 7218acf..6c970c0 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardClockSwitch.java
@@ -15,8 +15,8 @@
 import com.android.keyguard.clock.ClockManager;
 import com.android.systemui.Dependency;
 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;
 
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..b15c5de 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;
@@ -26,17 +30,16 @@
 import android.annotation.Nullable;
 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;
 import android.graphics.Point;
 import android.graphics.Rect;
-import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.provider.Settings;
 import android.service.notification.StatusBarNotification;
 import android.util.Log;
+import android.util.StatsLog;
 import android.view.LayoutInflater;
 import android.view.ViewGroup;
 import android.view.WindowManager;
@@ -48,7 +51,7 @@
 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.statusbar.notification.NotificationEntryListener;
 import com.android.systemui.statusbar.notification.NotificationEntryManager;
 import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
@@ -70,7 +73,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";
@@ -427,11 +430,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 +449,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 +492,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;
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedViewContainer.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
similarity index 96%
rename from packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedViewContainer.java
rename to packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index f08ba19..bf9d7ba 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedViewContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -51,7 +51,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 +81,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();
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index afa9f02..305f866 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -94,7 +94,7 @@
     private StackAnimationController mStackAnimationController;
     private ExpandedAnimationController mExpandedAnimationController;
 
-    private BubbleExpandedViewContainer mExpandedViewContainer;
+    private BubbleExpandedView mExpandedViewContainer;
 
     private int mBubbleSize;
     private int mBubblePadding;
@@ -173,7 +173,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 +226,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);
     }
 
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/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/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/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/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/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/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/doze/DozeTriggersTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
index cdac7c97..c0dca35 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java
@@ -50,7 +50,6 @@
 import org.junit.runner.RunWith;
 
 @SmallTest
-@Ignore("failing")
 @RunWith(AndroidTestingRunner.class)
 @RunWithLooper
 public class DozeTriggersTest extends SysuiTestCase {
@@ -90,6 +89,7 @@
     }
 
     @Test
+    @Ignore
     public void testOnNotification_stillWorksAfterOneFailedProxCheck() throws Exception {
         when(mMachine.getState()).thenReturn(DozeMachine.State.DOZE);
 
@@ -111,6 +111,7 @@
     }
 
     @Test
+    @Ignore
     public void testDockEventListener_registerAndUnregister() {
         mTriggers.transitionTo(DozeMachine.State.UNINITIALIZED, DozeMachine.State.INITIALIZED);
 
@@ -122,6 +123,7 @@
     }
 
     @Test
+    @Ignore
     public void testOnSensor_whenUndockedWithNearAndDoubleTapScreen_shouldNotWakeUp() {
         mSensors.getMockProximitySensor().sendProximityResult(false /* far */);
 
@@ -133,6 +135,7 @@
     }
 
     @Test
+    @Ignore
     public void testOnSensor_whenDockedWithNearAndDoubleTapScreen_shouldWakeUp() {
         doReturn(true).when(mDockManagerFake).isDocked();
         mSensors.getMockProximitySensor().sendProximityResult(false /* far */);
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/QSFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
index 823485f..769fdb5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFragmentTest.java
@@ -56,7 +56,6 @@
 @RunWith(AndroidTestingRunner.class)
 @RunWithLooper
 @SmallTest
-@Ignore
 public class QSFragmentTest extends SysuiBaseFragmentTest {
 
     private MetricsLogger mMockMetricsLogger;
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/NonPhoneDependencyTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java
index 8e926848..39e1d10 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NonPhoneDependencyTest.java
@@ -52,7 +52,6 @@
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @TestableLooper.RunWithLooper
-@Ignore("b/118400112")
 public class NonPhoneDependencyTest extends SysuiTestCase {
     @Mock private NotificationPresenter mPresenter;
     @Mock private NotificationListContainer mListContainer;
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..ba2aec0 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
@@ -377,7 +377,7 @@
                         outRanking.getImportance(), outRanking.getImportanceExplanation(),
                         outRanking.getOverrideGroupKey(), outRanking.getChannel(), null, null,
                         outRanking.canShowBadge(), outRanking.getUserSentiment(), true,
-                        -1, false, null, null);
+                        -1, false, null, null, outRanking.canBubble());
             } else if (key.equals(TEST_EXEMPT_DND_VISUAL_SUPPRESSION_KEY)) {
                 outRanking.populate(key, outRanking.getRank(),
                         outRanking.matchesInterruptionFilter(),
@@ -385,7 +385,7 @@
                         outRanking.getImportance(), outRanking.getImportanceExplanation(),
                         outRanking.getOverrideGroupKey(), outRanking.getChannel(), null, null,
                         outRanking.canShowBadge(), outRanking.getUserSentiment(), true, -1,
-                        false, null, null);
+                        false, null, null, outRanking.canBubble());
             } else {
                 outRanking.populate(key, outRanking.getRank(),
                         outRanking.matchesInterruptionFilter(),
@@ -393,7 +393,7 @@
                         outRanking.getImportance(), outRanking.getImportanceExplanation(),
                         outRanking.getOverrideGroupKey(), NOTIFICATION_CHANNEL, null, null,
                         outRanking.canShowBadge(), outRanking.getUserSentiment(), false, -1,
-                        false, null, null);
+                        false, null, null, 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/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/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/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..5932f99 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -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 {
@@ -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(" ");
@@ -11334,7 +11334,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 +11434,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:
@@ -12871,7 +12871,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 +14997,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..7035698 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -1709,8 +1709,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..6ae671f 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -679,47 +679,65 @@
         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_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 +1740,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 +1754,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 +1763,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/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..0dc73d9 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -381,11 +381,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 +415,22 @@
                 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_HEARING_AID, SENDMSG_QUEUE);
+    }
+
+    /*package*/ void postDisconnectHeadset() {
+        sendMsgNoDelay(MSG_DISCONNECT_HEADSET, SENDMSG_QUEUE);
+    }
+
     //---------------------------------------------------------------------
     // Method forwarding between the helper classes (BtHelper, AudioDeviceInventory)
     // only call from a "handle"* method or "on"* method
@@ -444,23 +460,6 @@
         }
     }
 
-    /*package*/ void handleDisconnectA2dp() {
-        synchronized (mDeviceStateLock) {
-            mDeviceInventory.disconnectA2dp();
-        }
-    }
-    /*package*/ void handleDisconnectA2dpSink() {
-        synchronized (mDeviceStateLock) {
-            mDeviceInventory.disconnectA2dpSink();
-        }
-    }
-
-    /*package*/ void handleDisconnectHearingAid() {
-        synchronized (mDeviceStateLock) {
-            mDeviceInventory.disconnectHearingAid();
-        }
-    }
-
     /*package*/ void handleSetA2dpSinkConnectionState(@BluetoothProfile.BtProfileState int state,
                 @NonNull BtHelper.BluetoothA2dpDeviceInfo btDeviceInfo) {
         final int intState = (state == BluetoothA2dp.STATE_CONNECTED)
@@ -482,7 +481,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 +709,26 @@
                                 (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_HEARING_AID:
+                    synchronized (mDeviceStateLock) {
+                        mDeviceInventory.disconnectHearingAid();
+                    }
+                    break;
+                case MSG_DISCONNECT_HEADSET:
+                    synchronized (mDeviceStateLock) {
+                        mBtHelper.disconnectHeadset();
+                    }
+                    break;
                 default:
                     Log.wtf(TAG, "Invalid message " + msg.what);
             }
@@ -745,6 +764,10 @@
     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_HEARING_AID = 21;
+    private static final int MSG_DISCONNECT_HEADSET = 22;
 
 
     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..e918997 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,14 @@
         mDeviceBroker.setBluetoothScoOn(false, "resetBluetoothSco");
     }
 
+    /*package*/ synchronized void disconnectHeadset() {
+        setBtScoActiveDevice(null);
+        mBluetoothHeadset = null;
+    }
+
     //----------------------------------------------------------------------
     private void broadcastScoConnectionState(int state) {
-        mDeviceBroker.broadcastScoConnectionState(state);
+        mDeviceBroker.postBroadcastScoConnectionState(state);
     }
 
     private boolean handleBtScoActiveDeviceChange(BluetoothDevice btDevice, boolean isActive) {
@@ -487,7 +492,7 @@
                                 btDevice = deviceList.get(0);
                                 final @BluetoothProfile.BtProfileState int state =
                                         proxy.getConnectionState(btDevice);
-                                mDeviceBroker.handleSetA2dpSourceConnectionState(
+                                mDeviceBroker.postSetA2dpSourceConnectionState(
                                         state, new BluetoothA2dpDeviceInfo(btDevice));
                             }
                             break;
@@ -558,19 +563,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 +584,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/face/FaceService.java b/services/core/java/com/android/server/biometrics/face/FaceService.java
index 90342ee..017503a 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,
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..9e0a1c0c 100644
--- a/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/fingerprint/FingerprintService.java
@@ -192,6 +192,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,
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/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/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index c222e69..cf09b8f 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -306,18 +306,21 @@
         }
     }
 
-    public void writeXml(XmlSerializer out, boolean forBackup) throws IOException {
+    public void writeXml(XmlSerializer out, boolean forBackup, int userId) throws IOException {
         out.startTag(null, getConfig().xmlTag);
 
         out.attribute(null, ATT_VERSION, String.valueOf(DB_VERSION));
 
         if (forBackup) {
-            trimApprovedListsAccordingToInstalledServices();
+            trimApprovedListsAccordingToInstalledServices(userId);
         }
 
         final int N = mApproved.size();
         for (int i = 0 ; i < N; i++) {
-            final int userId = mApproved.keyAt(i);
+            final int approvedUserId = mApproved.keyAt(i);
+            if (forBackup && approvedUserId != userId) {
+                continue;
+            }
             final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.valueAt(i);
             if (approvedByType != null) {
                 final int M = approvedByType.size();
@@ -328,14 +331,14 @@
                         String allowedItems = String.join(ENABLED_SERVICES_SEPARATOR, approved);
                         out.startTag(null, TAG_MANAGED_SERVICES);
                         out.attribute(null, ATT_APPROVED_LIST, allowedItems);
-                        out.attribute(null, ATT_USER_ID, Integer.toString(userId));
+                        out.attribute(null, ATT_USER_ID, Integer.toString(approvedUserId));
                         out.attribute(null, ATT_IS_PRIMARY, Boolean.toString(isPrimary));
                         out.endTag(null, TAG_MANAGED_SERVICES);
 
                         if (!forBackup && isPrimary) {
                             // Also write values to settings, for observers who haven't migrated yet
                             Settings.Secure.putStringForUser(mContext.getContentResolver(),
-                                    getConfig().secureSettingName, allowedItems, userId);
+                                    getConfig().secureSettingName, allowedItems, approvedUserId);
                         }
 
                     }
@@ -350,15 +353,12 @@
         loadAllowedComponentsFromSettings();
     }
 
-    public void readXml(XmlPullParser parser, Predicate<String> allowedManagedServicePackages)
+    public void readXml(
+            XmlPullParser parser,
+            Predicate<String> allowedManagedServicePackages,
+            boolean forRestore,
+            int userId)
             throws XmlPullParserException, IOException {
-        // upgrade xml
-        int xmlVersion = XmlUtils.readIntAttribute(parser, ATT_VERSION, 0);
-        final List<UserInfo> activeUsers = mUm.getUsers(true);
-        for (UserInfo userInfo : activeUsers) {
-            upgradeXml(xmlVersion, userInfo.getUserHandle().getIdentifier());
-        }
-
         // read grants
         int type;
         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
@@ -372,14 +372,16 @@
                     Slog.i(TAG, "Read " + mConfig.caption + " permissions from xml");
 
                     final String approved = XmlUtils.readStringAttribute(parser, ATT_APPROVED_LIST);
-                    final int userId = XmlUtils.readIntAttribute(parser, ATT_USER_ID, 0);
+                    // Ignore parser's user id for restore.
+                    final int resolvedUserId = forRestore
+                            ? userId : XmlUtils.readIntAttribute(parser, ATT_USER_ID, 0);
                     final boolean isPrimary =
                             XmlUtils.readBooleanAttribute(parser, ATT_IS_PRIMARY, true);
 
                     if (allowedManagedServicePackages == null ||
                             allowedManagedServicePackages.test(getPackageName(approved))) {
-                        if (mUm.getUserInfo(userId) != null) {
-                            addApprovedList(approved, userId, isPrimary);
+                        if (mUm.getUserInfo(resolvedUserId) != null) {
+                            addApprovedList(approved, resolvedUserId, isPrimary);
                         }
                         mUseXml = true;
                     }
@@ -389,8 +391,6 @@
         rebindServices(false, USER_ALL);
     }
 
-    protected void upgradeXml(final int xmlVersion, final int userId) {}
-
     private void loadAllowedComponentsFromSettings() {
         for (UserInfo user : mUm.getUsers()) {
             final ContentResolver cr = mContext.getContentResolver();
@@ -784,26 +784,23 @@
         return allowedPackages;
     }
 
-    private void trimApprovedListsAccordingToInstalledServices() {
-        int N = mApproved.size();
-        for (int i = 0 ; i < N; i++) {
-            final int userId = mApproved.keyAt(i);
-            final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.valueAt(i);
-            int M = approvedByType.size();
-            for (int j = 0; j < M; j++) {
-                final ArraySet<String> approved = approvedByType.valueAt(j);
-                int P = approved.size();
-                for (int k = P - 1; k >= 0; k--) {
-                    final String approvedPackageOrComponent = approved.valueAt(k);
-                    if (!isValidEntry(approvedPackageOrComponent, userId)){
-                        approved.removeAt(k);
-                        Slog.v(TAG, "Removing " + approvedPackageOrComponent
-                                + " from approved list; no matching services found");
-                    } else {
-                        if (DEBUG) {
-                            Slog.v(TAG, "Keeping " + approvedPackageOrComponent
-                                    + " on approved list; matching services found");
-                        }
+    private void trimApprovedListsAccordingToInstalledServices(int userId) {
+        final ArrayMap<Boolean, ArraySet<String>> approvedByType = mApproved.get(userId);
+        if (approvedByType == null) {
+            return;
+        }
+        for (int i = 0; i < approvedByType.size(); i++) {
+            final ArraySet<String> approved = approvedByType.valueAt(i);
+            for (int j = approved.size() - 1; j >= 0; j--) {
+                final String approvedPackageOrComponent = approved.valueAt(j);
+                if (!isValidEntry(approvedPackageOrComponent, userId)){
+                    approved.removeAt(j);
+                    Slog.v(TAG, "Removing " + approvedPackageOrComponent
+                            + " from approved list; no matching services found");
+                } else {
+                    if (DEBUG) {
+                        Slog.v(TAG, "Keeping " + approvedPackageOrComponent
+                                + " on approved list; matching services found");
                     }
                 }
             }
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 34a6663c..3557fcf 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -213,6 +213,7 @@
 import com.android.server.notification.ManagedServices.ManagedServiceInfo;
 import com.android.server.notification.ManagedServices.UserProfiles;
 import com.android.server.pm.PackageManagerService;
+import com.android.server.pm.UserManagerService;
 import com.android.server.policy.PhoneWindowManager;
 import com.android.server.statusbar.StatusBarManagerInternal;
 import com.android.server.uri.UriGrantsManagerInternal;
@@ -538,30 +539,49 @@
         }
     }
 
-    void readPolicyXml(InputStream stream, boolean forRestore)
+    UserManagerService getUserManagerService() {
+        return UserManagerService.getInstance();
+    }
+
+    void readPolicyXml(InputStream stream, boolean forRestore, int userId)
             throws XmlPullParserException, NumberFormatException, IOException {
         final XmlPullParser parser = Xml.newPullParser();
         parser.setInput(stream, StandardCharsets.UTF_8.name());
         XmlUtils.beginDocument(parser, TAG_NOTIFICATION_POLICY);
         boolean migratedManagedServices = false;
+        boolean ineligibleForManagedServices = forRestore
+                && getUserManagerService().isManagedProfile(userId);
         int outerDepth = parser.getDepth();
         while (XmlUtils.nextElementWithin(parser, outerDepth)) {
             if (ZenModeConfig.ZEN_TAG.equals(parser.getName())) {
-                mZenModeHelper.readXml(parser, forRestore);
+                mZenModeHelper.readXml(parser, forRestore, userId);
             } else if (PreferencesHelper.TAG_RANKING.equals(parser.getName())){
-                mPreferencesHelper.readXml(parser, forRestore);
+                mPreferencesHelper.readXml(parser, forRestore, userId);
             }
             if (mListeners.getConfig().xmlTag.equals(parser.getName())) {
-                mListeners.readXml(parser, mAllowedManagedServicePackages);
+                if (ineligibleForManagedServices) {
+                    continue;
+                }
+                mListeners.readXml(parser, mAllowedManagedServicePackages, forRestore, userId);
                 migratedManagedServices = true;
             } else if (mAssistants.getConfig().xmlTag.equals(parser.getName())) {
-                mAssistants.readXml(parser, mAllowedManagedServicePackages);
+                if (ineligibleForManagedServices) {
+                    continue;
+                }
+                mAssistants.readXml(parser, mAllowedManagedServicePackages, forRestore, userId);
                 migratedManagedServices = true;
             } else if (mConditionProviders.getConfig().xmlTag.equals(parser.getName())) {
-                mConditionProviders.readXml(parser, mAllowedManagedServicePackages);
+                if (ineligibleForManagedServices) {
+                    continue;
+                }
+                mConditionProviders.readXml(
+                        parser, mAllowedManagedServicePackages, forRestore, userId);
                 migratedManagedServices = true;
             }
             if (LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_TAG.equals(parser.getName())) {
+                if (forRestore && userId != UserHandle.USER_SYSTEM) {
+                    continue;
+                }
                 mLockScreenAllowSecureNotifications =
                         safeBoolean(parser.getAttributeValue(null,
                                         LOCKSCREEN_ALLOW_SECURE_NOTIFICATIONS_VALUE), true);
@@ -584,7 +604,7 @@
             InputStream infile = null;
             try {
                 infile = mPolicyFile.openRead();
-                readPolicyXml(infile, false /*forRestore*/);
+                readPolicyXml(infile, false /*forRestore*/, UserHandle.USER_ALL);
             } catch (FileNotFoundException e) {
                 // No data yet
                 // Load default managed services approvals
@@ -615,7 +635,7 @@
                 }
 
                 try {
-                    writePolicyXml(stream, false /*forBackup*/);
+                    writePolicyXml(stream, false /*forBackup*/, UserHandle.USER_ALL);
                     mPolicyFile.finishWrite(stream);
                 } catch (IOException e) {
                     Slog.w(TAG, "Failed to save policy file, restoring backup", e);
@@ -626,18 +646,21 @@
         });
     }
 
-    private void writePolicyXml(OutputStream stream, boolean forBackup) throws IOException {
+    private void writePolicyXml(OutputStream stream, boolean forBackup, int userId)
+            throws IOException {
         final XmlSerializer out = new FastXmlSerializer();
         out.setOutput(stream, StandardCharsets.UTF_8.name());
         out.startDocument(null, true);
         out.startTag(null, TAG_NOTIFICATION_POLICY);
         out.attribute(null, ATTR_VERSION, Integer.toString(DB_VERSION));
-        mZenModeHelper.writeXml(out, forBackup, null);
-        mPreferencesHelper.writeXml(out, forBackup);
-        mListeners.writeXml(out, forBackup);
-        mAssistants.writeXml(out, forBackup);
-        mConditionProviders.writeXml(out, forBackup);
-        writeSecureNotificationsPolicy(out);
+        mZenModeHelper.writeXml(out, forBackup, null, userId);
+        mPreferencesHelper.writeXml(out, forBackup, userId);
+        mListeners.writeXml(out, forBackup, userId);
+        mAssistants.writeXml(out, forBackup, userId);
+        mConditionProviders.writeXml(out, forBackup, userId);
+        if (!forBackup || userId == UserHandle.USER_SYSTEM) {
+            writeSecureNotificationsPolicy(out);
+        }
         out.endTag(null, TAG_NOTIFICATION_POLICY);
         out.endDocument();
     }
@@ -1282,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
@@ -1299,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);
         }
 
@@ -1324,6 +1351,9 @@
             if (uri == null || NOTIFICATION_BADGING_URI.equals(uri)) {
                 mPreferencesHelper.updateBadgingEnabled();
             }
+            if (uri == null || NOTIFICATION_BUBBLES_URI.equals(uri)) {
+                mPreferencesHelper.updateBubblesEnabled();
+            }
         }
     }
 
@@ -3507,14 +3537,9 @@
         public byte[] getBackupPayload(int user) {
             checkCallerIsSystem();
             if (DBG) Slog.d(TAG, "getBackupPayload u=" + user);
-            //TODO: http://b/22388012
-            if (user != USER_SYSTEM) {
-                Slog.w(TAG, "getBackupPayload: cannot backup policy for user " + user);
-                return null;
-            }
             final ByteArrayOutputStream baos = new ByteArrayOutputStream();
             try {
-                writePolicyXml(baos, true /*forBackup*/);
+                writePolicyXml(baos, true /*forBackup*/, user);
                 return baos.toByteArray();
             } catch (IOException e) {
                 Slog.w(TAG, "getBackupPayload: error writing payload for user " + user, e);
@@ -3531,14 +3556,9 @@
                 Slog.w(TAG, "applyRestore: no payload to restore for user " + user);
                 return;
             }
-            //TODO: http://b/22388012
-            if (user != USER_SYSTEM) {
-                Slog.w(TAG, "applyRestore: cannot restore policy for user " + user);
-                return;
-            }
             final ByteArrayInputStream bais = new ByteArrayInputStream(payload);
             try {
-                readPolicyXml(bais, true /*forRestore*/);
+                readPolicyXml(bais, true /*forRestore*/, user);
                 handleSavePolicyFile();
             } catch (NumberFormatException | XmlPullParserException | IOException e) {
                 Slog.w(TAG, "applyRestore: error reading payload", e);
@@ -5849,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);
@@ -5863,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());
@@ -5880,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())
@@ -6922,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)) {
@@ -6954,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 6ed4f5c..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,10 +139,11 @@
         mPm = pm;
 
         updateBadgingEnabled();
+        updateBubblesEnabled();
         syncChannelsBypassingDnd(mContext.getUserId());
     }
 
-    public void readXml(XmlPullParser parser, boolean forRestore)
+    public void readXml(XmlPullParser parser, boolean forRestore, int userId)
             throws XmlPullParserException, IOException {
         int type = parser.getEventType();
         if (type != XmlPullParser.START_TAG) return;
@@ -158,6 +160,9 @@
                 }
                 if (type == XmlPullParser.START_TAG) {
                     if (TAG_STATUS_ICONS.equals(tag)) {
+                        if (forRestore && userId != UserHandle.USER_SYSTEM) {
+                            continue;
+                        }
                         mHideSilentStatusBarIcons = XmlUtils.readBooleanAttribute(
                                 parser, ATT_HIDE_SILENT, DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS);
                     } else if (TAG_PACKAGE.equals(tag)) {
@@ -166,9 +171,7 @@
                         if (!TextUtils.isEmpty(name)) {
                             if (forRestore) {
                                 try {
-                                    //TODO: http://b/22388012
-                                    uid = mPm.getPackageUidAsUser(name,
-                                            UserHandle.USER_SYSTEM);
+                                    uid = mPm.getPackageUidAsUser(name, userId);
                                 } catch (PackageManager.NameNotFoundException e) {
                                     // noop
                                 }
@@ -379,10 +382,11 @@
         r.channels.put(channel.getId(), channel);
     }
 
-    public void writeXml(XmlSerializer out, boolean forBackup) throws IOException {
+    public void writeXml(XmlSerializer out, boolean forBackup, int userId) throws IOException {
         out.startTag(null, TAG_RANKING);
         out.attribute(null, ATT_VERSION, Integer.toString(XML_VERSION));
-        if (mHideSilentStatusBarIcons != DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS) {
+        if (mHideSilentStatusBarIcons != DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS
+                && (!forBackup || userId == UserHandle.USER_SYSTEM)) {
             out.startTag(null, TAG_STATUS_ICONS);
             out.attribute(null, ATT_HIDE_SILENT, String.valueOf(mHideSilentStatusBarIcons));
             out.endTag(null, TAG_STATUS_ICONS);
@@ -392,8 +396,7 @@
             final int N = mPackagePreferences.size();
             for (int i = 0; i < N; i++) {
                 final PackagePreferences r = mPackagePreferences.valueAt(i);
-                //TODO: http://b/22388012
-                if (forBackup && UserHandle.getUserId(r.uid) != UserHandle.USER_SYSTEM) {
+                if (forBackup && UserHandle.getUserId(r.uid) != userId) {
                     continue;
                 }
                 final boolean hasNonDefaultSettings =
@@ -485,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;
     }
@@ -1266,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);
         }
     }
@@ -1638,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/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index afc0b72..ea7bf2d2 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -104,7 +104,7 @@
     protected final RingerModeDelegate mRingerModeDelegate = new
             RingerModeDelegate();
     @VisibleForTesting protected final ZenModeConditions mConditions;
-    private final SparseArray<ZenModeConfig> mConfigs = new SparseArray<>();
+    @VisibleForTesting final SparseArray<ZenModeConfig> mConfigs = new SparseArray<>();
     private final Metrics mMetrics = new Metrics();
     private final ConditionProviders.Config mServiceConfig;
 
@@ -662,17 +662,14 @@
         }
     }
 
-    public void readXml(XmlPullParser parser, boolean forRestore)
+    public void readXml(XmlPullParser parser, boolean forRestore, int userId)
             throws XmlPullParserException, IOException {
         ZenModeConfig config = ZenModeConfig.readXml(parser);
         String reason = "readXml";
 
         if (config != null) {
             if (forRestore) {
-                //TODO: http://b/22388012
-                if (config.user != UserHandle.USER_SYSTEM) {
-                    return;
-                }
+                config.user = userId;
                 config.manualRule = null;  // don't restore the manual rule
             }
 
@@ -707,13 +704,15 @@
                 reason += ", reset to default rules";
             }
 
+            // Resolve user id for settings.
+            userId = userId == UserHandle.USER_ALL ? UserHandle.USER_SYSTEM : userId;
             if (config.version < ZenModeConfig.XML_VERSION) {
-                Settings.Secure.putInt(mContext.getContentResolver(),
-                        Settings.Secure.SHOW_ZEN_UPGRADE_NOTIFICATION, 1);
+                Settings.Secure.putIntForUser(mContext.getContentResolver(),
+                        Settings.Secure.SHOW_ZEN_UPGRADE_NOTIFICATION, 1, userId);
             } else {
                 // devices not restoring/upgrading already have updated zen settings
-                Settings.Secure.putInt(mContext.getContentResolver(),
-                        Settings.Secure.ZEN_SETTINGS_UPDATED, 1);
+                Settings.Secure.putIntForUser(mContext.getContentResolver(),
+                        Settings.Secure.ZEN_SETTINGS_UPDATED, 1, userId);
             }
             if (DEBUG) Log.d(TAG, reason);
             synchronized (mConfig) {
@@ -722,11 +721,11 @@
         }
     }
 
-    public void writeXml(XmlSerializer out, boolean forBackup, Integer version) throws IOException {
+    public void writeXml(XmlSerializer out, boolean forBackup, Integer version, int userId)
+            throws IOException {
         final int N = mConfigs.size();
         for (int i = 0; i < N; i++) {
-            //TODO: http://b/22388012
-            if (forBackup && mConfigs.keyAt(i) != UserHandle.USER_SYSTEM) {
+            if (forBackup && mConfigs.keyAt(i) != userId) {
                 continue;
             }
             mConfigs.valueAt(i).writeXml(out, version);
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..eaedec5 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() {
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 55eb7ea..89aea36 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -380,6 +380,19 @@
 
     private boolean commitApkSession(@NonNull PackageInstallerSession apkSession,
                                      int originalSessionId) {
+
+        if ((apkSession.params.installFlags & PackageManager.INSTALL_ENABLE_ROLLBACK) != 0) {
+            // If rollback is available for this session, notify the rollback
+            // manager of the apk session so it can properly enable rollback.
+            final IRollbackManager rm = IRollbackManager.Stub.asInterface(
+                    ServiceManager.getService(Context.ROLLBACK_SERVICE));
+            try {
+                rm.notifyStagedApkSession(originalSessionId, apkSession.sessionId);
+            } catch (RemoteException re) {
+                // Cannot happen, the rollback manager is in the same process.
+            }
+        }
+
         final LocalIntentReceiver receiver = new LocalIntentReceiver();
         apkSession.commit(receiver.getIntentSender(), false);
         final Intent result = receiver.getResult();
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/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..af3bff0 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;
@@ -295,6 +293,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 +1118,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 +1410,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 +1434,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 +1513,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 +1563,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 +1586,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 +1595,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 +1625,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 +1635,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 +1767,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 +2351,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 +4359,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 +4371,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/RollbackData.java b/services/core/java/com/android/server/rollback/RollbackData.java
index f456665..fcd5297 100644
--- a/services/core/java/com/android/server/rollback/RollbackData.java
+++ b/services/core/java/com/android/server/rollback/RollbackData.java
@@ -64,6 +64,11 @@
     public boolean isAvailable;
 
     /**
+     * The id of the post-reboot apk session for a staged install, if any.
+     */
+    public int apkSessionId = -1;
+
+    /**
      * Whether this Rollback is currently in progress. This field is true from the point
      * we commit a {@code PackageInstaller} session containing these packages to the point the
      * {@code PackageInstaller} calls into the {@code onFinished} callback.
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerService.java b/services/core/java/com/android/server/rollback/RollbackManagerService.java
index ba6cddd..f7ba9bb 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerService.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerService.java
@@ -44,4 +44,11 @@
     public void onUnlockUser(int user) {
         mService.onUnlockUser(user);
     }
+
+    @Override
+    public void onBootPhase(int phase) {
+        if (phase == SystemService.PHASE_BOOT_COMPLETED) {
+            mService.onBootCompleted();
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index 438e479..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 {
@@ -486,6 +484,47 @@
         });
     }
 
+    void onBootCompleted() {
+        getHandler().post(() -> {
+            // Check to see if any staged sessions with rollback enabled have
+            // been applied.
+            List<RollbackData> staged = new ArrayList<>();
+            synchronized (mLock) {
+                ensureRollbackDataLoadedLocked();
+                for (RollbackData data : mAvailableRollbacks) {
+                    if (data.stagedSessionId != -1) {
+                        staged.add(data);
+                    }
+                }
+            }
+
+            for (RollbackData data : staged) {
+                PackageInstaller installer = mContext.getPackageManager().getPackageInstaller();
+                PackageInstaller.SessionInfo session = installer.getSessionInfo(
+                        data.stagedSessionId);
+                if (session != null) {
+                    if (session.isSessionApplied()) {
+                        synchronized (mLock) {
+                            data.isAvailable = true;
+                        }
+                        try {
+                            mRollbackStore.saveAvailableRollback(data);
+                        } catch (IOException ioe) {
+                            Log.e(TAG, "Unable to save rollback info for : "
+                                    + data.rollbackId, ioe);
+                        }
+                    } else if (session.isSessionFailed()) {
+                        // TODO: Do we need to remove this from
+                        // mAvailableRollbacks, or is it okay to leave as
+                        // unavailable until the next reboot when it will go
+                        // away on its own?
+                        deleteRollback(data);
+                    }
+                }
+            }
+        });
+    }
+
     /**
      * Load rollback data from storage if it has not already been loaded.
      * After calling this funciton, mAvailableRollbacks and
@@ -551,7 +590,7 @@
                                         info.getVersionRolledBackFrom(),
                                         installedVersion)) {
                         iter.remove();
-                        mRollbackStore.deleteAvailableRollback(data);
+                        deleteRollback(data);
                         break;
                     }
                 }
@@ -664,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;
                 }
@@ -725,6 +764,7 @@
         // ourselves.
         PackageInstaller.SessionInfo session = null;
 
+        int parentSessionId = -1;
         PackageInstaller installer = mContext.getPackageManager().getPackageInstaller();
         for (PackageInstaller.SessionInfo info : installer.getAllSessions()) {
             if (info.isMultiPackage()) {
@@ -732,12 +772,14 @@
                     PackageInstaller.SessionInfo child = installer.getSessionInfo(childId);
                     if (sessionMatchesForEnableRollback(child, installFlags, newPackageCodePath)) {
                         // TODO: Check we only have one matching session?
+                        parentSessionId = info.getSessionId();
                         session = child;
                         break;
                     }
                 }
             } else if (sessionMatchesForEnableRollback(info, installFlags, newPackageCodePath)) {
                 // TODO: Check we only have one matching session?
+                parentSessionId = info.getSessionId();
                 session = info;
                 break;
             }
@@ -748,6 +790,58 @@
             return false;
         }
 
+        // Check to see if this is the apk session for a staged session with
+        // rollback enabled.
+        // TODO: This check could be made more efficient.
+        RollbackData rd = null;
+        synchronized (mLock) {
+            ensureRollbackDataLoadedLocked();
+            for (int i = 0; i < mAvailableRollbacks.size(); ++i) {
+                RollbackData data = mAvailableRollbacks.get(i);
+                if (data.apkSessionId == parentSessionId) {
+                    rd = data;
+                    break;
+                }
+            }
+        }
+
+        if (rd != null) {
+            // This is the apk session for a staged session. We have already
+            // backed up the apks, we just need to do user data backup.
+            PackageParser.PackageLite newPackage = null;
+            try {
+                newPackage = PackageParser.parsePackageLite(
+                        new File(session.resolvedBaseCodePath), 0);
+            } catch (PackageParser.PackageParserException e) {
+                Log.e(TAG, "Unable to parse new package", e);
+                return false;
+            }
+            String packageName = newPackage.packageName;
+            for (PackageRollbackInfo info : rd.packages) {
+                if (info.getPackageName().equals(packageName)) {
+                    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) {
+                        // TODO: Hopefully this is okay because we will try
+                        // again to save the rollback when the staged session
+                        // is applied. Just so long as the device doesn't
+                        // reboot before then.
+                        Log.e(TAG, "Unable to save rollback info for : " + rd.rollbackId, ioe);
+                    }
+                    return true;
+                }
+            }
+            Log.e(TAG, "Unable to find package in apk session");
+            return false;
+        }
+
         return enableRollbackForSession(session, installedUsers, true);
     }
 
@@ -800,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();
@@ -856,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 {
@@ -928,6 +1026,32 @@
         }
     }
 
+    @Override
+    public void notifyStagedApkSession(int originalSessionId, int apkSessionId) {
+        getHandler().post(() -> {
+            RollbackData rd = null;
+            synchronized (mLock) {
+                ensureRollbackDataLoadedLocked();
+                for (int i = 0; i < mAvailableRollbacks.size(); ++i) {
+                    RollbackData data = mAvailableRollbacks.get(i);
+                    if (data.stagedSessionId == originalSessionId) {
+                        data.apkSessionId = apkSessionId;
+                        rd = data;
+                        break;
+                    }
+                }
+            }
+
+            if (rd != null) {
+                try {
+                    mRollbackStore.saveAvailableRollback(rd);
+                } catch (IOException ioe) {
+                    Log.e(TAG, "Unable to save rollback info for : " + rd.rollbackId, ioe);
+                }
+            }
+        });
+    }
+
     /**
      * Gets the version of the package currently installed.
      * Returns null if the package is not currently installed.
@@ -1024,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);
             }
         }
     }
@@ -1128,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/RollbackStore.java b/services/core/java/com/android/server/rollback/RollbackStore.java
index 1e45ba2..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.
      */
@@ -248,6 +271,7 @@
             dataJson.put("timestamp", data.timestamp.toString());
             dataJson.put("stagedSessionId", data.stagedSessionId);
             dataJson.put("isAvailable", data.isAvailable);
+            dataJson.put("apkSessionId", data.apkSessionId);
 
             PrintWriter pw = new PrintWriter(new File(data.backupDir, "rollback.json"));
             pw.println(dataJson.toString());
@@ -262,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);
     }
 
@@ -313,6 +335,7 @@
                     stagedSessionId, isAvailable);
             data.packages.addAll(packageRollbackInfosFromJson(dataJson.getJSONArray("packages")));
             data.timestamp = Instant.parse(dataJson.getString("timestamp"));
+            data.apkSessionId = dataJson.getInt("apkSessionId");
             return data;
         } catch (JSONException | DateTimeParseException e) {
             throw new IOException(e);
@@ -339,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;
     }
 
@@ -360,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/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..7aa3481 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -5666,6 +5666,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..0e14e46 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();
+        mSurfaceControl.remove();
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 3246a87..2cc85e2 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -2504,7 +2504,7 @@
     public void onAnimationLeashDestroyed(Transaction t) {
         super.onAnimationLeashDestroyed(t);
         if (mAnimationBoundsLayer != null) {
-            t.reparent(mAnimationBoundsLayer, null);
+            t.remove(mAnimationBoundsLayer);
             mAnimationBoundsLayer = null;
         }
 
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..429bce0 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -33,14 +33,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;
@@ -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.
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index bbf115f..f98ca3d 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;
@@ -134,6 +135,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;
@@ -1900,7 +1902,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 +1996,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);
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/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/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/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/ManagedServicesTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
index 20f72bf..7a530df 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ManagedServicesTest.java
@@ -74,6 +74,7 @@
 import java.io.ByteArrayOutputStream;
 import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.List;
 import java.util.Set;
 
@@ -305,6 +306,82 @@
         }
     }
 
+    /** Test that restore ignores the user id attribute and applies the data to the target user. */
+    @Test
+    public void testReadXml_onlyRestoresForTargetUser() throws Exception {
+        for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
+            ManagedServices service =
+                    new TestManagedServices(
+                            getContext(), mLock, mUserProfiles, mIpm, approvalLevel);
+            String testPackage = "user.test.package";
+            String testComponent = "user.test.component/C1";
+            String resolvedValue =
+                    (approvalLevel == APPROVAL_BY_COMPONENT) ? testComponent : testPackage;
+            XmlPullParser parser =
+                    getParserWithEntries(service, getXmlEntry(resolvedValue, 0, true));
+
+            service.readXml(parser, null, true, 10);
+
+            assertFalse(service.isPackageOrComponentAllowed(resolvedValue, 0));
+            assertTrue(service.isPackageOrComponentAllowed(resolvedValue, 10));
+        }
+    }
+
+    /** Test that backup only writes packages/components that belong to the target user. */
+    @Test
+    public void testWriteXml_onlyBackupsForTargetUser() throws Exception {
+        for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
+            ManagedServices service =
+                    new TestManagedServices(
+                            getContext(), mLock, mUserProfiles, mIpm, approvalLevel);
+            // Set up components.
+            String testPackage0 = "user0.test.package";
+            String testComponent0 = "user0.test.component/C1";
+            String testPackage10 = "user10.test.package";
+            String testComponent10 = "user10.test.component/C1";
+            String resolvedValue0 =
+                    (approvalLevel == APPROVAL_BY_COMPONENT) ? testComponent0 : testPackage0;
+            String resolvedValue10 =
+                    (approvalLevel == APPROVAL_BY_COMPONENT) ? testComponent10 : testPackage10;
+            addExpectedServices(
+                    service, Collections.singletonList(service.getPackageName(resolvedValue0)), 0);
+            addExpectedServices(
+                    service,
+                    Collections.singletonList(service.getPackageName(resolvedValue10)),
+                    10);
+            XmlPullParser parser =
+                    getParserWithEntries(
+                            service,
+                            getXmlEntry(resolvedValue0, 0, true),
+                            getXmlEntry(resolvedValue10, 10, true));
+            service.readXml(parser, null, false, UserHandle.USER_ALL);
+
+            // Write backup.
+            XmlSerializer serializer = new FastXmlSerializer();
+            ByteArrayOutputStream baos = new ByteArrayOutputStream();
+            serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
+            serializer.startDocument(null, true);
+            service.writeXml(serializer, true, 10);
+            serializer.endDocument();
+            serializer.flush();
+
+            // Reset values.
+            service.setPackageOrComponentEnabled(resolvedValue0, 0, true, false);
+            service.setPackageOrComponentEnabled(resolvedValue10, 10, true, false);
+
+            // Parse backup via restore.
+            XmlPullParser restoreParser = Xml.newPullParser();
+            restoreParser.setInput(
+                    new BufferedInputStream(new ByteArrayInputStream(baos.toByteArray())), null);
+            restoreParser.nextTag();
+            service.readXml(restoreParser, null, true, 10);
+
+            assertFalse(service.isPackageOrComponentAllowed(resolvedValue0, 0));
+            assertFalse(service.isPackageOrComponentAllowed(resolvedValue0, 10));
+            assertTrue(service.isPackageOrComponentAllowed(resolvedValue10, 10));
+        }
+    }
+
     @Test
     public void testWriteXml_trimsMissingServices() throws Exception {
         for (int approvalLevel : new int[] {APPROVAL_BY_COMPONENT, APPROVAL_BY_PACKAGE}) {
@@ -348,7 +425,9 @@
             ByteArrayOutputStream baos = new ByteArrayOutputStream();
             serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
             serializer.startDocument(null, true);
-            service.writeXml(serializer, true);
+            for (UserInfo userInfo : mUm.getUsers()) {
+                service.writeXml(serializer, true, userInfo.id);
+            }
             serializer.endDocument();
             serializer.flush();
 
@@ -356,7 +435,9 @@
             parser.setInput(new BufferedInputStream(
                     new ByteArrayInputStream(baos.toByteArray())), null);
             parser.nextTag();
-            service.readXml(parser, null);
+            for (UserInfo userInfo : mUm.getUsers()) {
+                service.readXml(parser, null, true, userInfo.id);
+            }
 
             verifyExpectedApprovedEntries(service);
             assertFalse(service.isPackageOrComponentAllowed("this.is.a.package.name", 0));
@@ -376,7 +457,7 @@
             ByteArrayOutputStream baos = new ByteArrayOutputStream();
             serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
             serializer.startDocument(null, true);
-            service.writeXml(serializer, false);
+            service.writeXml(serializer, false, UserHandle.USER_ALL);
             serializer.endDocument();
             serializer.flush();
 
@@ -921,7 +1002,23 @@
         parser.setInput(new BufferedInputStream(
                 new ByteArrayInputStream(xml.toString().getBytes())), null);
         parser.nextTag();
-        service.readXml(parser, null);
+        service.readXml(parser, null, false, UserHandle.USER_ALL);
+    }
+
+    private XmlPullParser getParserWithEntries(ManagedServices service, String... xmlEntries)
+            throws Exception {
+        final StringBuffer xml = new StringBuffer();
+        xml.append("<" + service.getConfig().xmlTag + ">\n");
+        for (String xmlEntry : xmlEntries) {
+            xml.append(xmlEntry);
+        }
+        xml.append("</" + service.getConfig().xmlTag + ">");
+
+        XmlPullParser parser = Xml.newPullParser();
+        parser.setInput(new BufferedInputStream(
+                new ByteArrayInputStream(xml.toString().getBytes())), null);
+        parser.nextTag();
+        return parser;
     }
 
     private void addExpectedServices(final ManagedServices service, final List<String> packages,
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
index 0b488c0..19b567f 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationAssistantsTest.java
@@ -33,6 +33,7 @@
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.content.pm.UserInfo;
+import android.os.UserHandle;
 import android.os.UserManager;
 import android.util.IntArray;
 import android.util.Xml;
@@ -129,7 +130,7 @@
         parser.setInput(new BufferedInputStream(
                 new ByteArrayInputStream(xml.toString().getBytes())), null);
         parser.nextTag();
-        mAssistants.readXml(parser, null);
+        mAssistants.readXml(parser, null, false, UserHandle.USER_ALL);
 
         verify(mNm, never()).readDefaultAssistant(anyInt());
         verify(mAssistants, times(1)).addApprovedList(
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 72aa0f2..cc62138 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -123,6 +123,7 @@
 import com.android.server.lights.LightsManager;
 import com.android.server.notification.NotificationManagerService.NotificationAssistants;
 import com.android.server.notification.NotificationManagerService.NotificationListeners;
+import com.android.server.pm.UserManagerService;
 import com.android.server.uri.UriGrantsManagerInternal;
 import com.android.server.wm.WindowManagerInternal;
 
@@ -206,15 +207,19 @@
     UriGrantsManagerInternal mUgmInternal;
     @Mock
     AppOpsManager mAppOpsManager;
+    @Mock
+    private UserManagerService mUserMangerService;
 
     // Use a Testable subclass so we can simulate calls from the system without failing.
     private static class TestableNotificationManagerService extends NotificationManagerService {
         int countSystemChecks = 0;
         boolean isSystemUid = true;
         int countLogSmartSuggestionsVisible = 0;
+        UserManagerService mUserManagerService;
 
-        public TestableNotificationManagerService(Context context) {
+        TestableNotificationManagerService(Context context, UserManagerService userManagerService) {
             super(context);
+            mUserManagerService = userManagerService;
         }
 
         @Override
@@ -250,7 +255,10 @@
             countLogSmartSuggestionsVisible++;
         }
 
-
+        @Override
+        UserManagerService getUserManagerService() {
+            return mUserManagerService;
+        }
     }
 
     private class TestableToastCallback extends ITransientNotification.Stub {
@@ -267,17 +275,12 @@
     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);
         LocalServices.addService(WindowManagerInternal.class, mWindowManagerInternal);
 
-        mService = new TestableNotificationManagerService(mContext);
+        mService = new TestableNotificationManagerService(mContext, mUserMangerService);
 
         // Use this testable looper.
         mTestableLooper = TestableLooper.get(this);
@@ -426,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);
@@ -1847,7 +1855,7 @@
 
     @Test
     public void testHasCompanionDevice_noService() throws Exception {
-        mService = new TestableNotificationManagerService(mContext);
+        mService = new TestableNotificationManagerService(mContext, mUserMangerService);
 
         assertFalse(mService.hasCompanionDevice(mListener));
     }
@@ -2500,10 +2508,12 @@
                 + "</dnd_apps>"
                 + "</notification-policy>";
         mService.readPolicyXml(
-                new BufferedInputStream(new ByteArrayInputStream(upgradeXml.getBytes())), false);
-        verify(mListeners, times(1)).readXml(any(), any());
-        verify(mConditionProviders, times(1)).readXml(any(), any());
-        verify(mAssistants, times(1)).readXml(any(), any());
+                new BufferedInputStream(new ByteArrayInputStream(upgradeXml.getBytes())),
+                false,
+                UserHandle.USER_ALL);
+        verify(mListeners, times(1)).readXml(any(), any(), anyBoolean(), anyInt());
+        verify(mConditionProviders, times(1)).readXml(any(), any(), anyBoolean(), anyInt());
+        verify(mAssistants, times(1)).readXml(any(), any(), anyBoolean(), anyInt());
 
         // numbers are inflated for setup
         verify(mListeners, times(1)).migrateToXml();
@@ -2518,10 +2528,12 @@
                 + "<ranking></ranking>"
                 + "</notification-policy>";
         mService.readPolicyXml(
-                new BufferedInputStream(new ByteArrayInputStream(preupgradeXml.getBytes())), false);
-        verify(mListeners, never()).readXml(any(), any());
-        verify(mConditionProviders, never()).readXml(any(), any());
-        verify(mAssistants, never()).readXml(any(), any());
+                new BufferedInputStream(new ByteArrayInputStream(preupgradeXml.getBytes())),
+                false,
+                UserHandle.USER_ALL);
+        verify(mListeners, never()).readXml(any(), any(), anyBoolean(), anyInt());
+        verify(mConditionProviders, never()).readXml(any(), any(), anyBoolean(), anyInt());
+        verify(mAssistants, never()).readXml(any(), any(), anyBoolean(), anyInt());
 
         // numbers are inflated for setup
         verify(mListeners, times(2)).migrateToXml();
@@ -2530,6 +2542,53 @@
         verify(mAssistants, times(2)).ensureAssistant();
     }
 
+    @Test
+    public void testReadPolicyXml_doesNotRestoreManagedServicesForManagedUser() throws Exception {
+        final String policyXml = "<notification-policy version=\"1\">"
+                + "<ranking></ranking>"
+                + "<enabled_listeners>"
+                + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />"
+                + "</enabled_listeners>"
+                + "<enabled_assistants>"
+                + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />"
+                + "</enabled_assistants>"
+                + "<dnd_apps>"
+                + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />"
+                + "</dnd_apps>"
+                + "</notification-policy>";
+        when(mUserMangerService.isManagedProfile(10)).thenReturn(true);
+        mService.readPolicyXml(
+                new BufferedInputStream(new ByteArrayInputStream(policyXml.getBytes())),
+                true,
+                10);
+        verify(mListeners, never()).readXml(any(), any(), eq(true), eq(10));
+        verify(mConditionProviders, never()).readXml(any(), any(), eq(true), eq(10));
+        verify(mAssistants, never()).readXml(any(), any(), eq(true), eq(10));
+    }
+
+    @Test
+    public void testReadPolicyXml_restoresManagedServicesForNonManagedUser() throws Exception {
+        final String policyXml = "<notification-policy version=\"1\">"
+                + "<ranking></ranking>"
+                + "<enabled_listeners>"
+                + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />"
+                + "</enabled_listeners>"
+                + "<enabled_assistants>"
+                + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />"
+                + "</enabled_assistants>"
+                + "<dnd_apps>"
+                + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />"
+                + "</dnd_apps>"
+                + "</notification-policy>";
+        when(mUserMangerService.isManagedProfile(10)).thenReturn(false);
+        mService.readPolicyXml(
+                new BufferedInputStream(new ByteArrayInputStream(policyXml.getBytes())),
+                true,
+                10);
+        verify(mListeners, times(1)).readXml(any(), any(), eq(true), eq(10));
+        verify(mConditionProviders, times(1)).readXml(any(), any(), eq(true), eq(10));
+        verify(mAssistants, times(1)).readXml(any(), any(), eq(true), eq(10));
+    }
 
     @Test
     public void testLocaleChangedCallsUpdateDefaultZenModeRules() throws Exception {
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 47ec390..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);
@@ -174,14 +176,14 @@
                 .build();
     }
 
-    private ByteArrayOutputStream writeXmlAndPurge(String pkg, int uid, boolean forBackup,
-            String... channelIds)
+    private ByteArrayOutputStream writeXmlAndPurge(
+            String pkg, int uid, boolean forBackup, int userId, String... channelIds)
             throws Exception {
         XmlSerializer serializer = new FastXmlSerializer();
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
         serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
         serializer.startDocument(null, true);
-        mHelper.writeXml(serializer, forBackup);
+        mHelper.writeXml(serializer, forBackup, userId);
         serializer.endDocument();
         serializer.flush();
         for (String channelId : channelIds) {
@@ -190,15 +192,17 @@
         return baos;
     }
 
-    private void loadStreamXml(ByteArrayOutputStream stream, boolean forRestore) throws Exception {
-        loadByteArrayXml(stream.toByteArray(), forRestore);
+    private void loadStreamXml(ByteArrayOutputStream stream, boolean forRestore, int userId)
+            throws Exception {
+        loadByteArrayXml(stream.toByteArray(), forRestore, userId);
     }
 
-    private void loadByteArrayXml(byte[] byteArray, boolean forRestore) throws Exception {
+    private void loadByteArrayXml(byte[] byteArray, boolean forRestore, int userId)
+            throws Exception {
         XmlPullParser parser = Xml.newPullParser();
         parser.setInput(new BufferedInputStream(new ByteArrayInputStream(byteArray)), null);
         parser.nextTag();
-        mHelper.readXml(parser, forRestore);
+        mHelper.readXml(parser, forRestore, userId);
     }
 
     private void compareChannels(NotificationChannel expected, NotificationChannel actual) {
@@ -242,6 +246,69 @@
         when(mMockZenModeHelper.getNotificationPolicy()).thenReturn(mTestNotificationPolicy);
     }
 
+    private void setUpPackageWithUid(String packageName, int uid) throws Exception {
+        when(mPm.getApplicationInfoAsUser(eq(packageName), anyInt(), anyInt()))
+                .thenReturn(new ApplicationInfo());
+        when(mPm.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid);
+    }
+
+    @Test
+    public void testWriteXml_onlyBackupsTargetUser() throws Exception {
+        // Setup package notifications.
+        String package0 = "test.package.user0";
+        int uid0 = 1001;
+        setUpPackageWithUid(package0, uid0);
+        NotificationChannel channel0 = new NotificationChannel("id0", "name0", IMPORTANCE_HIGH);
+        mHelper.createNotificationChannel(package0, uid0, channel0, true, false);
+
+        String package10 = "test.package.user10";
+        int uid10 = 1001001;
+        setUpPackageWithUid(package10, uid10);
+        NotificationChannel channel10 = new NotificationChannel("id10", "name10", IMPORTANCE_HIGH);
+        mHelper.createNotificationChannel(package10, uid10, channel10, true, false);
+
+        ByteArrayOutputStream baos = writeXmlAndPurge(package10, uid10, true, 10);
+
+        // Reset state.
+        mHelper.onPackagesChanged(true, 0, new String[] {package0}, new int[] {uid0});
+        mHelper.onPackagesChanged(true, 10, new String[] {package10}, new int[] {uid10});
+
+        // Parse backup data.
+        loadStreamXml(baos, true, 0);
+        loadStreamXml(baos, true, 10);
+
+        assertEquals(
+                channel10,
+                mHelper.getNotificationChannel(package10, uid10, channel10.getId(), false));
+        assertNull(mHelper.getNotificationChannel(package0, uid0, channel0.getId(), false));
+    }
+
+    @Test
+    public void testReadXml_onlyRestoresTargetUser() throws Exception {
+        // Setup package in user 0.
+        String package0 = "test.package.user0";
+        int uid0 = 1001;
+        setUpPackageWithUid(package0, uid0);
+        NotificationChannel channel0 = new NotificationChannel("id0", "name0", IMPORTANCE_HIGH);
+        mHelper.createNotificationChannel(package0, uid0, channel0, true, false);
+
+        ByteArrayOutputStream baos = writeXmlAndPurge(package0, uid0, true, 0);
+
+        // Reset state.
+        mHelper.onPackagesChanged(true, 0, new String[] {package0}, new int[] {uid0});
+
+        // Restore should convert the uid according to the target user.
+        int expectedUid = 1001001;
+        setUpPackageWithUid(package0, expectedUid);
+        // Parse backup data.
+        loadStreamXml(baos, true, 10);
+
+        assertEquals(
+                channel0,
+                mHelper.getNotificationChannel(package0, expectedUid, channel0.getId(), false));
+        assertNull(mHelper.getNotificationChannel(package0, uid0, channel0.getId(), false));
+    }
+
     @Test
     public void testChannelXml() throws Exception {
         NotificationChannelGroup ncg = new NotificationChannelGroup("1", "bye");
@@ -270,12 +337,13 @@
         mHelper.setShowBadge(PKG_N_MR1, UID_N_MR1, true);
         mHelper.setAppImportanceLocked(PKG_N_MR1, UID_N_MR1);
 
-        ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, false, channel1.getId(),
-                channel2.getId(), NotificationChannel.DEFAULT_CHANNEL_ID);
+        ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, false,
+                UserHandle.USER_ALL, channel1.getId(), channel2.getId(),
+                NotificationChannel.DEFAULT_CHANNEL_ID);
         mHelper.onPackagesChanged(true, UserHandle.myUserId(), new String[]{PKG_N_MR1}, new int[]{
                 UID_N_MR1});
 
-        loadStreamXml(baos, false);
+        loadStreamXml(baos, false, UserHandle.USER_ALL);
 
         assertTrue(mHelper.canShowBadge(PKG_N_MR1, UID_N_MR1));
         assertTrue(mHelper.getIsAppImportanceLocked(PKG_N_MR1, UID_N_MR1));
@@ -337,14 +405,15 @@
 
         mHelper.setImportance(PKG_O, UID_O, IMPORTANCE_NONE);
 
-        ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, true, channel1.getId(),
-                channel2.getId(), channel3.getId(), NotificationChannel.DEFAULT_CHANNEL_ID);
+        ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, true,
+                UserHandle.USER_SYSTEM, channel1.getId(), channel2.getId(), channel3.getId(),
+                NotificationChannel.DEFAULT_CHANNEL_ID);
         mHelper.onPackagesChanged(true, UserHandle.myUserId(), new String[]{PKG_N_MR1, PKG_O},
                 new int[]{UID_N_MR1, UID_O});
 
         mHelper.setShowBadge(PKG_O, UID_O, true);
 
-        loadStreamXml(baos, true);
+        loadStreamXml(baos, true, UserHandle.USER_SYSTEM);
 
         assertEquals(IMPORTANCE_NONE, mHelper.getImportance(PKG_O, UID_O));
         assertTrue(mHelper.canShowBadge(PKG_N_MR1, UID_N_MR1));
@@ -385,10 +454,11 @@
         channel.setSound(SOUND_URI, mAudioAttributes);
         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false);
 
-        ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, true, channel.getId());
+        ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, true,
+                UserHandle.USER_SYSTEM, channel.getId());
 
         // Testing that in restore we are given the canonical version
-        loadStreamXml(baos, true);
+        loadStreamXml(baos, true, UserHandle.USER_SYSTEM);
         verify(mTestIContentProvider).uncanonicalize(any(), eq(CANONICAL_SOUND_URI));
     }
 
@@ -410,9 +480,10 @@
                 new NotificationChannel("id", "name", IMPORTANCE_LOW);
         channel.setSound(SOUND_URI, mAudioAttributes);
         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false);
-        ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, true, channel.getId());
+        ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, true,
+                UserHandle.USER_SYSTEM, channel.getId());
 
-        loadStreamXml(baos, true);
+        loadStreamXml(baos, true, UserHandle.USER_SYSTEM);
 
         NotificationChannel actualChannel = mHelper.getNotificationChannel(
                 PKG_N_MR1, UID_N_MR1, channel.getId(), false);
@@ -431,9 +502,10 @@
                 new NotificationChannel("id", "name", IMPORTANCE_LOW);
         channel.setSound(SOUND_URI, mAudioAttributes);
         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false);
-        ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, true, channel.getId());
+        ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, true,
+                UserHandle.USER_SYSTEM, channel.getId());
 
-        loadStreamXml(baos, true);
+        loadStreamXml(baos, true, UserHandle.USER_SYSTEM);
 
         NotificationChannel actualChannel = mHelper.getNotificationChannel(
                 PKG_N_MR1, UID_N_MR1, channel.getId(), false);
@@ -460,7 +532,8 @@
                 + "</package>\n"
                 + "</ranking>\n";
 
-        loadByteArrayXml(backupWithUncanonicalizedSoundUri.getBytes(), true);
+        loadByteArrayXml(
+                backupWithUncanonicalizedSoundUri.getBytes(), true, UserHandle.USER_SYSTEM);
 
         NotificationChannel actualChannel = mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, id, false);
         assertEquals(Settings.System.DEFAULT_NOTIFICATION_URI, actualChannel.getSound());
@@ -472,9 +545,10 @@
                 new NotificationChannel("id", "name", IMPORTANCE_LOW);
         channel.setSound(null, mAudioAttributes);
         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false);
-        ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, true, channel.getId());
+        ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, true,
+                UserHandle.USER_SYSTEM, channel.getId());
 
-        loadStreamXml(baos, true);
+        loadStreamXml(baos, true, UserHandle.USER_SYSTEM);
 
         NotificationChannel actualChannel = mHelper.getNotificationChannel(
                 PKG_N_MR1, UID_N_MR1, channel.getId(), false);
@@ -504,8 +578,9 @@
         assertEquals(channel2,
                 mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel2.getId(), false));
 
-        ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, true, channel1.getId(),
-                channel2.getId(), channel3.getId(), NotificationChannel.DEFAULT_CHANNEL_ID);
+        ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, true,
+                UserHandle.USER_SYSTEM, channel1.getId(), channel2.getId(), channel3.getId(),
+                NotificationChannel.DEFAULT_CHANNEL_ID);
         mHelper.onPackagesChanged(true, UserHandle.myUserId(), new String[]{PKG_N_MR1}, new int[]{
                 UID_N_MR1});
 
@@ -513,7 +588,7 @@
         parser.setInput(new BufferedInputStream(new ByteArrayInputStream(baos.toByteArray())),
                 null);
         parser.nextTag();
-        mHelper.readXml(parser, true);
+        mHelper.readXml(parser, true, UserHandle.USER_SYSTEM);
 
         assertNull(mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel1.getId(), false));
         assertNull(mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel3.getId(), false));
@@ -525,9 +600,9 @@
     @Test
     public void testChannelXml_defaultChannelLegacyApp_noUserSettings() throws Exception {
         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, false,
-                NotificationChannel.DEFAULT_CHANNEL_ID);
+                UserHandle.USER_ALL, NotificationChannel.DEFAULT_CHANNEL_ID);
 
-        loadStreamXml(baos, false);
+        loadStreamXml(baos, false, UserHandle.USER_ALL);
 
         final NotificationChannel updated = mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1,
                 NotificationChannel.DEFAULT_CHANNEL_ID, false);
@@ -546,9 +621,9 @@
         mHelper.updateNotificationChannel(PKG_N_MR1, UID_N_MR1, defaultChannel, true);
 
         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, false,
-                NotificationChannel.DEFAULT_CHANNEL_ID);
+                UserHandle.USER_ALL, NotificationChannel.DEFAULT_CHANNEL_ID);
 
-        loadStreamXml(baos, false);
+        loadStreamXml(baos, false, UserHandle.USER_ALL);
 
         assertEquals(NotificationManager.IMPORTANCE_LOW, mHelper.getNotificationChannel(
                 PKG_N_MR1, UID_N_MR1, NotificationChannel.DEFAULT_CHANNEL_ID, false).getImportance());
@@ -568,7 +643,7 @@
         parser.setInput(new BufferedInputStream(new ByteArrayInputStream(preupgradeXml.getBytes())),
                 null);
         parser.nextTag();
-        mHelper.readXml(parser, false);
+        mHelper.readXml(parser, false, UserHandle.USER_ALL);
 
         final NotificationChannel updated1 =
             mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, NotificationChannel.DEFAULT_CHANNEL_ID, false);
@@ -590,13 +665,13 @@
         final NotificationChannel defaultChannel = mHelper.getNotificationChannel(
                 PKG_N_MR1, UID_N_MR1, NotificationChannel.DEFAULT_CHANNEL_ID, false);
         assertTrue(defaultChannel != null);
-        ByteArrayOutputStream baos =
-                writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, false, NotificationChannel.DEFAULT_CHANNEL_ID);
+        ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, false,
+                UserHandle.USER_ALL, NotificationChannel.DEFAULT_CHANNEL_ID);
         // Load package at higher sdk.
         final ApplicationInfo upgraded = new ApplicationInfo();
         upgraded.targetSdkVersion = Build.VERSION_CODES.N_MR1 + 1;
         when(mPm.getApplicationInfoAsUser(eq(PKG_N_MR1), anyInt(), anyInt())).thenReturn(upgraded);
-        loadStreamXml(baos, false);
+        loadStreamXml(baos, false, UserHandle.USER_ALL);
 
         // Default Channel should be gone.
         assertEquals(null, mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1,
@@ -608,13 +683,13 @@
         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1,
                 new NotificationChannel("bananas", "bananas", IMPORTANCE_LOW), true, false);
         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, false,
-                NotificationChannel.DEFAULT_CHANNEL_ID, "bananas");
+                UserHandle.USER_ALL, NotificationChannel.DEFAULT_CHANNEL_ID, "bananas");
 
         // Load package at higher sdk.
         final ApplicationInfo upgraded = new ApplicationInfo();
         upgraded.targetSdkVersion = Build.VERSION_CODES.N_MR1 + 1;
         when(mPm.getApplicationInfoAsUser(eq(PKG_N_MR1), anyInt(), anyInt())).thenReturn(upgraded);
-        loadStreamXml(baos, false);
+        loadStreamXml(baos, false, UserHandle.USER_ALL);
 
         // Default Channel should be gone.
         assertEquals(null, mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1,
@@ -624,11 +699,11 @@
     @Test
     public void testLoadingOldChannelsDoesNotDeleteNewlyCreatedChannels() throws Exception {
         ByteArrayOutputStream baos = writeXmlAndPurge(PKG_N_MR1, UID_N_MR1, false,
-                NotificationChannel.DEFAULT_CHANNEL_ID, "bananas");
+                UserHandle.USER_ALL, NotificationChannel.DEFAULT_CHANNEL_ID, "bananas");
         mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1,
                 new NotificationChannel("bananas", "bananas", IMPORTANCE_LOW), true, false);
 
-        loadStreamXml(baos, false);
+        loadStreamXml(baos, false, UserHandle.USER_ALL);
 
         // Should still have the newly created channel that wasn't in the xml.
         assertTrue(mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, "bananas", false) != null);
@@ -1828,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,
@@ -2007,9 +2122,9 @@
 
     @Test
     public void testXml_statusBarIcons_default() throws Exception {
-        ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false);
+        ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper);
-        loadStreamXml(baos, false);
+        loadStreamXml(baos, false, UserHandle.USER_ALL);
 
         assertEquals(PreferencesHelper.DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS,
                 mHelper.shouldHideSilentStatusIcons());
@@ -2019,9 +2134,9 @@
     public void testXml_statusBarIcons() throws Exception {
         mHelper.setHideSilentStatusIcons(!PreferencesHelper.DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS);
 
-        ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false);
+        ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper);
-        loadStreamXml(baos, false);
+        loadStreamXml(baos, false, UserHandle.USER_ALL);
 
         assertEquals(!PreferencesHelper.DEFAULT_HIDE_SILENT_STATUS_BAR_ICONS,
                 mHelper.shouldHideSilentStatusIcons());
@@ -2115,9 +2230,9 @@
     public void testDelegateXml_noDelegate() throws Exception {
         mHelper.setImportance(PKG_O, UID_O, IMPORTANCE_UNSPECIFIED);
 
-        ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false);
+        ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper);
-        loadStreamXml(baos, false);
+        loadStreamXml(baos, false, UserHandle.USER_ALL);
 
         assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
     }
@@ -2126,9 +2241,9 @@
     public void testDelegateXml_delegate() throws Exception {
         mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
 
-        ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false);
+        ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper);
-        loadStreamXml(baos, false);
+        loadStreamXml(baos, false, UserHandle.USER_ALL);
 
         assertEquals("other", mHelper.getNotificationDelegate(PKG_O, UID_O));
     }
@@ -2138,9 +2253,9 @@
         mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
         mHelper.revokeNotificationDelegate(PKG_O, UID_O);
 
-        ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false);
+        ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper);
-        loadStreamXml(baos, false);
+        loadStreamXml(baos, false, UserHandle.USER_ALL);
 
         assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
     }
@@ -2150,9 +2265,9 @@
         mHelper.setNotificationDelegate(PKG_O, UID_O, "other", 53);
         mHelper.toggleNotificationDelegate(PKG_O, UID_O, false);
 
-        ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false);
+        ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper);
-        loadStreamXml(baos, false);
+        loadStreamXml(baos, false, UserHandle.USER_ALL);
 
         // appears disabled
         assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
@@ -2168,9 +2283,9 @@
         mHelper.toggleNotificationDelegate(PKG_O, UID_O, false);
         mHelper.revokeNotificationDelegate(PKG_O, UID_O);
 
-        ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false);
+        ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper);
-        loadStreamXml(baos, false);
+        loadStreamXml(baos, false, UserHandle.USER_ALL);
 
         // appears disabled
         assertNull(mHelper.getNotificationDelegate(PKG_O, UID_O));
@@ -2186,9 +2301,9 @@
     public void testAllowBubbles_defaults() throws Exception {
         assertTrue(mHelper.areBubblesAllowed(PKG_O, UID_O));
 
-        ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false);
+        ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper);
-        loadStreamXml(baos, false);
+        loadStreamXml(baos, false, UserHandle.USER_ALL);
 
         assertTrue(mHelper.areBubblesAllowed(PKG_O, UID_O));
         assertEquals(0, mHelper.getAppLockedFields(PKG_O, UID_O));
@@ -2201,9 +2316,9 @@
         assertEquals(PreferencesHelper.LockableAppFields.USER_LOCKED_BUBBLE,
                 mHelper.getAppLockedFields(PKG_O, UID_O));
 
-        ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false);
+        ByteArrayOutputStream baos = writeXmlAndPurge(PKG_O, UID_O, false, UserHandle.USER_ALL);
         mHelper = new PreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper);
-        loadStreamXml(baos, false);
+        loadStreamXml(baos, false, UserHandle.USER_ALL);
 
         assertFalse(mHelper.areBubblesAllowed(PKG_O, UID_O));
         assertEquals(PreferencesHelper.LockableAppFields.USER_LOCKED_BUBBLE,
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/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index a459b0a..08d8333 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -25,6 +25,7 @@
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.TestCase.assertTrue;
 
+import static org.junit.Assert.assertNotEquals;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
 import static org.mockito.ArgumentMatchers.anyInt;
@@ -56,6 +57,7 @@
 import android.media.AudioSystem;
 import android.media.VolumePolicy;
 import android.net.Uri;
+import android.os.UserHandle;
 import android.provider.Settings;
 import android.provider.Settings.Global;
 import android.service.notification.Condition;
@@ -158,19 +160,58 @@
         return new XmlResourceParserImpl(parser);
     }
 
-    private ByteArrayOutputStream writeXmlAndPurge(boolean forBackup, Integer version)
+    private ByteArrayOutputStream writeXmlAndPurge(Integer version) throws Exception {
+        XmlSerializer serializer = new FastXmlSerializer();
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
+        serializer.startDocument(null, true);
+        mZenModeHelperSpy.writeXml(serializer, false, version, UserHandle.USER_ALL);
+        serializer.endDocument();
+        serializer.flush();
+        mZenModeHelperSpy.setConfig(new ZenModeConfig(), null, "writing xml");
+        return baos;
+    }
+
+    private ByteArrayOutputStream writeXmlAndPurgeForUser(Integer version, int userId)
             throws Exception {
         XmlSerializer serializer = new FastXmlSerializer();
         ByteArrayOutputStream baos = new ByteArrayOutputStream();
         serializer.setOutput(new BufferedOutputStream(baos), "utf-8");
         serializer.startDocument(null, true);
-        mZenModeHelperSpy.writeXml(serializer, forBackup, version);
+        mZenModeHelperSpy.writeXml(serializer, true, version, userId);
         serializer.endDocument();
         serializer.flush();
-        mZenModeHelperSpy.setConfig(new ZenModeConfig(), null, "writing xml");
+        ZenModeConfig newConfig = new ZenModeConfig();
+        newConfig.user = userId;
+        mZenModeHelperSpy.setConfig(newConfig, null, "writing xml");
         return baos;
     }
 
+    private XmlPullParser getParserForByteStream(ByteArrayOutputStream baos) throws Exception {
+        XmlPullParser parser = Xml.newPullParser();
+        parser.setInput(
+                new BufferedInputStream(new ByteArrayInputStream(baos.toByteArray())), null);
+        parser.nextTag();
+        return parser;
+    }
+
+    private ArrayMap<String, ZenModeConfig.ZenRule> getCustomAutomaticRules() {
+        ArrayMap<String, ZenModeConfig.ZenRule> automaticRules = new ArrayMap<>();
+        ZenModeConfig.ZenRule customRule = new ZenModeConfig.ZenRule();
+        final ScheduleInfo customRuleInfo = new ScheduleInfo();
+        customRule.enabled = true;
+        customRule.creationTime = 0;
+        customRule.id = "customRule";
+        customRule.name = "Custom Rule";
+        customRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+        customRule.conditionId = ZenModeConfig.toScheduleConditionId(customRuleInfo);
+        customRule.configurationActivity =
+                new ComponentName("android", "ScheduleConditionProvider");
+        customRule.pkg = customRule.configurationActivity.getPackageName();
+        automaticRules.put("customRule", customRule);
+        return automaticRules;
+    }
+
     @Test
     public void testZenOff_NoMuteApplied() {
         mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_OFF;
@@ -639,50 +680,86 @@
 
         ZenModeConfig expected = mZenModeHelperSpy.mConfig.copy();
 
-        ByteArrayOutputStream baos = writeXmlAndPurge(false, null);
-        XmlPullParser parser = Xml.newPullParser();
-        parser.setInput(new BufferedInputStream(
-                new ByteArrayInputStream(baos.toByteArray())), null);
-        parser.nextTag();
-        mZenModeHelperSpy.readXml(parser, false);
+        ByteArrayOutputStream baos = writeXmlAndPurge(null);
+        XmlPullParser parser = getParserForByteStream(baos);
+        mZenModeHelperSpy.readXml(parser, false, UserHandle.USER_ALL);
 
         assertEquals("Config mismatch: current vs expected: "
                 + mZenModeHelperSpy.mConfig.diff(expected), expected, mZenModeHelperSpy.mConfig);
     }
 
     @Test
-    public void testReadXmlRestore() throws Exception {
+    public void testWriteXml_onlyBackupsTargetUser() throws Exception {
+        // Setup configs for user 10 and 11.
         setupZenConfig();
+        ZenModeConfig config10 = mZenModeHelperSpy.mConfig.copy();
+        config10.user = 10;
+        config10.allowAlarms = true;
+        config10.allowMedia = true;
+        mZenModeHelperSpy.setConfig(config10, null, "writeXml");
+        ZenModeConfig config11 = mZenModeHelperSpy.mConfig.copy();
+        config11.user = 11;
+        config11.allowAlarms = false;
+        config11.allowMedia = false;
+        mZenModeHelperSpy.setConfig(config11, null, "writeXml");
 
+        // Backup user 10 and reset values.
+        ByteArrayOutputStream baos = writeXmlAndPurgeForUser(null, 10);
+        ZenModeConfig newConfig11 = new ZenModeConfig();
+        newConfig11.user = 11;
+        mZenModeHelperSpy.mConfigs.put(11, newConfig11);
+
+        // Parse backup data.
+        XmlPullParser parser = getParserForByteStream(baos);
+        mZenModeHelperSpy.readXml(parser, true, 10);
+        mZenModeHelperSpy.readXml(parser, true, 11);
+
+        ZenModeConfig actual = mZenModeHelperSpy.mConfigs.get(10);
+        assertEquals(
+                "Config mismatch: current vs expected: " + actual.diff(config10), config10, actual);
+        assertNotEquals("Expected config mismatch", config11, mZenModeHelperSpy.mConfigs.get(11));
+    }
+
+    @Test
+    public void testReadXmlRestore_forSystemUser() throws Exception {
+        setupZenConfig();
         // one enabled automatic rule
-        ArrayMap<String, ZenModeConfig.ZenRule> automaticRules = new ArrayMap<>();
-        ZenModeConfig.ZenRule customRule = new ZenModeConfig.ZenRule();
-        final ScheduleInfo customRuleInfo = new ScheduleInfo();
-        customRule.enabled = true;
-        customRule.creationTime = 0;
-        customRule.id = "customRule";
-        customRule.name = "Custom Rule";
-        customRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
-        customRule.conditionId = ZenModeConfig.toScheduleConditionId(customRuleInfo);
-        customRule.configurationActivity
-                = new ComponentName("android", "ScheduleConditionProvider");
-        customRule.pkg = customRule.configurationActivity.getPackageName();
-        automaticRules.put("customRule", customRule);
-        mZenModeHelperSpy.mConfig.automaticRules = automaticRules;
-
+        mZenModeHelperSpy.mConfig.automaticRules = getCustomAutomaticRules();
         ZenModeConfig original = mZenModeHelperSpy.mConfig.copy();
 
-        ByteArrayOutputStream baos = writeXmlAndPurge(false, null);
-        XmlPullParser parser = Xml.newPullParser();
-        parser.setInput(new BufferedInputStream(
-                new ByteArrayInputStream(baos.toByteArray())), null);
-        parser.nextTag();
-        mZenModeHelperSpy.readXml(parser, true);
+        ByteArrayOutputStream baos = writeXmlAndPurgeForUser(null, UserHandle.USER_SYSTEM);
+        XmlPullParser parser = getParserForByteStream(baos);
+        mZenModeHelperSpy.readXml(parser, true, UserHandle.USER_SYSTEM);
+
         assertEquals("Config mismatch: current vs original: "
                 + mZenModeHelperSpy.mConfig.diff(original), original, mZenModeHelperSpy.mConfig);
         assertEquals(original.hashCode(), mZenModeHelperSpy.mConfig.hashCode());
     }
 
+    /** Restore should ignore the data's user id and restore for the target user. */
+    @Test
+    public void testReadXmlRestore_forNonSystemUser() throws Exception {
+        // Setup config.
+        setupZenConfig();
+        mZenModeHelperSpy.mConfig.automaticRules = getCustomAutomaticRules();
+        ZenModeConfig expected = mZenModeHelperSpy.mConfig.copy();
+
+        // Backup data for user 0.
+        ByteArrayOutputStream baos = writeXmlAndPurgeForUser(null, UserHandle.USER_SYSTEM);
+
+        // Restore data for user 10.
+        XmlPullParser parser = getParserForByteStream(baos);
+        mZenModeHelperSpy.readXml(parser, true, 10);
+
+        ZenModeConfig actual = mZenModeHelperSpy.mConfigs.get(10);
+        expected.user = 10;
+        assertEquals(
+                "Config mismatch: current vs original: " + actual.diff(expected), expected, actual);
+        assertEquals(expected.hashCode(), actual.hashCode());
+        expected.user = 0;
+        assertNotEquals(expected, mZenModeHelperSpy.mConfig);
+    }
+
     @Test
     public void testWriteXmlWithZenPolicy() throws Exception {
         final String ruleId = "customRule";
@@ -715,12 +792,12 @@
 
         ZenModeConfig expected = mZenModeHelperSpy.mConfig.copy();
 
-        ByteArrayOutputStream baos = writeXmlAndPurge(false, null);
+        ByteArrayOutputStream baos = writeXmlAndPurge(null);
         XmlPullParser parser = Xml.newPullParser();
         parser.setInput(new BufferedInputStream(
                 new ByteArrayInputStream(baos.toByteArray())), null);
         parser.nextTag();
-        mZenModeHelperSpy.readXml(parser, false);
+        mZenModeHelperSpy.readXml(parser, false, UserHandle.USER_ALL);
 
         ZenModeConfig.ZenRule original = expected.automaticRules.get(ruleId);
         ZenModeConfig.ZenRule current = mZenModeHelperSpy.mConfig.automaticRules.get(ruleId);
@@ -729,7 +806,7 @@
     }
 
     @Test
-    public void testReadXmlRestoreWithZenPolicy() throws Exception {
+    public void testReadXmlRestoreWithZenPolicy_forSystemUser() throws Exception {
         final String ruleId = "customRule";
         setupZenConfig();
 
@@ -756,12 +833,9 @@
 
         ZenModeConfig expected = mZenModeHelperSpy.mConfig.copy();
 
-        ByteArrayOutputStream baos = writeXmlAndPurge(false, null);
-        XmlPullParser parser = Xml.newPullParser();
-        parser.setInput(new BufferedInputStream(
-                new ByteArrayInputStream(baos.toByteArray())), null);
-        parser.nextTag();
-        mZenModeHelperSpy.readXml(parser, true);
+        ByteArrayOutputStream baos = writeXmlAndPurgeForUser(null, UserHandle.USER_SYSTEM);
+        XmlPullParser parser = getParserForByteStream(baos);
+        mZenModeHelperSpy.readXml(parser, true, UserHandle.USER_SYSTEM);
 
         ZenModeConfig.ZenRule original = expected.automaticRules.get(ruleId);
         ZenModeConfig.ZenRule current = mZenModeHelperSpy.mConfig.automaticRules.get(ruleId);
@@ -786,12 +860,12 @@
         mZenModeHelperSpy.mConfig.automaticRules = enabledAutoRule;
 
         // set previous version
-        ByteArrayOutputStream baos = writeXmlAndPurge(false, 5);
+        ByteArrayOutputStream baos = writeXmlAndPurge(5);
         XmlPullParser parser = Xml.newPullParser();
         parser.setInput(new BufferedInputStream(
                 new ByteArrayInputStream(baos.toByteArray())), null);
         parser.nextTag();
-        mZenModeHelperSpy.readXml(parser, false);
+        mZenModeHelperSpy.readXml(parser, false, UserHandle.USER_ALL);
 
         assertTrue(mZenModeHelperSpy.mConfig.automaticRules.containsKey("customRule"));
         setupZenConfigMaintained();
@@ -811,7 +885,7 @@
         parser.setInput(new BufferedInputStream(
                 new ByteArrayInputStream(xml.getBytes())), null);
         parser.nextTag();
-        mZenModeHelperSpy.readXml(parser, false);
+        mZenModeHelperSpy.readXml(parser, false, UserHandle.USER_ALL);
 
         assertEquals(0, mZenModeHelperSpy.mConfig.suppressedVisualEffects);
 
@@ -827,7 +901,7 @@
         parser.setInput(new BufferedInputStream(
                 new ByteArrayInputStream(xml.getBytes())), null);
         parser.nextTag();
-        mZenModeHelperSpy.readXml(parser, false);
+        mZenModeHelperSpy.readXml(parser, false, UserHandle.USER_ALL);
 
         assertEquals(0, mZenModeHelperSpy.mConfig.suppressedVisualEffects);
     }
@@ -846,7 +920,7 @@
         parser.setInput(new BufferedInputStream(
                 new ByteArrayInputStream(xml.getBytes())), null);
         parser.nextTag();
-        mZenModeHelperSpy.readXml(parser, false);
+        mZenModeHelperSpy.readXml(parser, false, UserHandle.USER_ALL);
 
         assertEquals(0, mZenModeHelperSpy.mConfig.suppressedVisualEffects);
     }
@@ -865,7 +939,7 @@
         parser.setInput(new BufferedInputStream(
                 new ByteArrayInputStream(xml.getBytes())), null);
         parser.nextTag();
-        mZenModeHelperSpy.readXml(parser, false);
+        mZenModeHelperSpy.readXml(parser, false, UserHandle.USER_ALL);
 
         assertEquals(SUPPRESSED_EFFECT_FULL_SCREEN_INTENT
                         | SUPPRESSED_EFFECT_LIGHTS
@@ -884,7 +958,7 @@
         parser.setInput(new BufferedInputStream(
                 new ByteArrayInputStream(xml.getBytes())), null);
         parser.nextTag();
-        mZenModeHelperSpy.readXml(parser, false);
+        mZenModeHelperSpy.readXml(parser, false, UserHandle.USER_ALL);
 
         assertEquals(SUPPRESSED_EFFECT_PEEK, mZenModeHelperSpy.mConfig.suppressedVisualEffects);
 
@@ -900,7 +974,7 @@
         parser.setInput(new BufferedInputStream(
                 new ByteArrayInputStream(xml.getBytes())), null);
         parser.nextTag();
-        mZenModeHelperSpy.readXml(parser, false);
+        mZenModeHelperSpy.readXml(parser, false, UserHandle.USER_ALL);
 
         assertEquals(SUPPRESSED_EFFECT_FULL_SCREEN_INTENT | SUPPRESSED_EFFECT_LIGHTS,
                 mZenModeHelperSpy.mConfig.suppressedVisualEffects);
@@ -915,12 +989,12 @@
         mZenModeHelperSpy.mConfig.automaticRules = new ArrayMap<>();
 
         // set previous version
-        ByteArrayOutputStream baos = writeXmlAndPurge(false, 5);
+        ByteArrayOutputStream baos = writeXmlAndPurge(5);
         XmlPullParser parser = Xml.newPullParser();
         parser.setInput(new BufferedInputStream(
                 new ByteArrayInputStream(baos.toByteArray())), null);
         parser.nextTag();
-        mZenModeHelperSpy.readXml(parser, false);
+        mZenModeHelperSpy.readXml(parser, false, UserHandle.USER_ALL);
 
         // check default rules
         ArrayMap<String, ZenModeConfig.ZenRule> rules = mZenModeHelperSpy.mConfig.automaticRules;
@@ -951,12 +1025,12 @@
         mZenModeHelperSpy.mConfig.automaticRules = disabledAutoRule;
 
         // set previous version
-        ByteArrayOutputStream baos = writeXmlAndPurge(false, 5);
+        ByteArrayOutputStream baos = writeXmlAndPurge(5);
         XmlPullParser parser = Xml.newPullParser();
         parser.setInput(new BufferedInputStream(
                 new ByteArrayInputStream(baos.toByteArray())), null);
         parser.nextTag();
-        mZenModeHelperSpy.readXml(parser, false);
+        mZenModeHelperSpy.readXml(parser, false, UserHandle.USER_ALL);
 
         // check default rules
         ArrayMap<String, ZenModeConfig.ZenRule> rules = mZenModeHelperSpy.mConfig.automaticRules;
@@ -1003,12 +1077,12 @@
         mZenModeHelperSpy.mConfig.automaticRules = automaticRules;
 
         // set previous version
-        ByteArrayOutputStream baos = writeXmlAndPurge(false, 5);
+        ByteArrayOutputStream baos = writeXmlAndPurge(5);
         XmlPullParser parser = Xml.newPullParser();
         parser.setInput(new BufferedInputStream(
                 new ByteArrayInputStream(baos.toByteArray())), null);
         parser.nextTag();
-        mZenModeHelperSpy.readXml(parser, false);
+        mZenModeHelperSpy.readXml(parser, false, UserHandle.USER_ALL);
 
         // check default rules
         ArrayMap<String, ZenModeConfig.ZenRule> rules = mZenModeHelperSpy.mConfig.automaticRules;
@@ -1072,12 +1146,12 @@
         mZenModeHelperSpy.mConfig.automaticRules = automaticRules;
 
         // set previous version
-        ByteArrayOutputStream baos = writeXmlAndPurge(false, 5);
+        ByteArrayOutputStream baos = writeXmlAndPurge(5);
         XmlPullParser parser = Xml.newPullParser();
         parser.setInput(new BufferedInputStream(
                 new ByteArrayInputStream(baos.toByteArray())), null);
         parser.nextTag();
-        mZenModeHelperSpy.readXml(parser, false);
+        mZenModeHelperSpy.readXml(parser, false, UserHandle.USER_ALL);
 
         // check default rules
         ArrayMap<String, ZenModeConfig.ZenRule> rules = mZenModeHelperSpy.mConfig.automaticRules;
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..defe981 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
@@ -42,7 +42,6 @@
  * Build/Install/Run:
  *  atest WmTests:AppChangeTransitionTests
  */
-@FlakyTest(detail = "Promote when shown to be stable.")
 @SmallTest
 public class AppChangeTransitionTests extends WindowTestsBase {
 
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/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..8876214 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;
@@ -48,6 +49,7 @@
 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;
@@ -60,13 +62,15 @@
 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;
 import androidx.test.filters.SmallTest;
 
 import com.android.server.wm.utils.WmDisplayCutout;
 
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
 import org.junit.Test;
 
 import java.util.LinkedList;
@@ -77,10 +81,23 @@
  * 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() {
+        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;
+    }
 
     @Test
     public void testIsParentWindowHidden() {
@@ -263,12 +280,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 +296,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 +317,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
@@ -435,6 +452,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/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/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/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/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.aidl b/telephony/java/android/telephony/ims/RcsThreadQueryParameters.aidl
deleted file mode 100644
index feb2d4d..0000000
--- a/telephony/java/android/telephony/ims/RcsThreadQueryParameters.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 RcsThreadQueryParameters;
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..55440d2 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");
 
@@ -728,6 +742,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..1273a4a 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.
@@ -1045,7 +1045,8 @@
      * 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