Merge "Add helper methods for View attribute debugging"
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/current.txt b/api/current.txt
index f6f68e1..98d30a3 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -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
@@ -1508,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
@@ -6738,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);
@@ -10264,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";
@@ -10390,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";
@@ -11355,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;
@@ -11364,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;
   }
@@ -11864,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 {
@@ -12056,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);
@@ -19447,9 +19422,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 +19441,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
@@ -56674,6 +56649,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 8d7ec26..b7fc339 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1072,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";
   }
 
@@ -3919,6 +3920,7 @@
     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);
@@ -5001,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;
   }
@@ -5026,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 {
@@ -6037,11 +6041,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 f71789d..94e83ea 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";
   }
 
@@ -934,6 +934,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";
   }
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..5740710 100755
--- a/cmds/idmap2/static-checks.sh
+++ b/cmds/idmap2/static-checks.sh
@@ -73,6 +73,7 @@
     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: misc-non-private-member-variables-in-classes' \
+        -e 'Unknown NOLINT error category: performance-unnecessary-copy-initialization' \
     )"
     if [[ "$output" ]]; then
         echo "$output"
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..4f17d69 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -110,7 +110,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 +121,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 +239,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.
@@ -5344,6 +5345,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/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp
index a5bd5c6..37d5ba0 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.cpp
+++ b/cmds/statsd/src/guardrail/StatsdStats.cpp
@@ -443,6 +443,11 @@
     getAtomMetricStats(metricId).badValueType++;
 }
 
+void StatsdStats::noteBucketDropped(int metricId) {
+    lock_guard<std::mutex> lock(mLock);
+    getAtomMetricStats(metricId).bucketDropped++;
+}
+
 void StatsdStats::noteConditionChangeInNextBucket(int metricId) {
     lock_guard<std::mutex> lock(mLock);
     getAtomMetricStats(metricId).conditionChangeInNextBucket++;
diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h
index cb17061..20ea7e5 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.h
+++ b/cmds/statsd/src/guardrail/StatsdStats.h
@@ -360,6 +360,11 @@
     void noteBadValueType(int atomId);
 
     /**
+     * Buckets were dropped due to reclaim memory.
+     */
+    void noteBucketDropped(int metricId);
+
+    /**
      * A condition change was too late, arrived in the wrong bucket and was skipped
      */
     void noteConditionChangeInNextBucket(int atomId);
@@ -414,6 +419,7 @@
         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 c9b7165..2609937 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -510,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/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 9fb78e7..1bd3ef2 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -175,6 +175,7 @@
 
 void ValueMetricProducer::dropDataLocked(const int64_t dropTimeNs) {
     flushIfNeededLocked(dropTimeNs);
+    StatsdStats::getInstance().noteBucketDropped(mMetricId);
     mPastBuckets.clear();
 }
 
@@ -434,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.");
     }
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index d9bec5d..0cfefa9 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -61,6 +61,7 @@
         if (!mSplitBucketForAppUpgrade) {
             return;
         }
+        flushIfNeededLocked(eventTimeNs - 1);
         if (mIsPulled && mCondition) {
             pullAndMatchEventsLocked(eventTimeNs - 1);
         }
@@ -212,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);
@@ -238,6 +240,8 @@
     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 5b91482..73aab48 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -418,6 +418,7 @@
       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 3cb7563..f76a9ad 100644
--- a/cmds/statsd/src/stats_log_util.cpp
+++ b/cmds/statsd/src/stats_log_util.cpp
@@ -79,6 +79,7 @@
 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 {
 
@@ -497,6 +498,8 @@
                        (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/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index 6404552..91b98ec 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -167,9 +167,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);
@@ -184,11 +185,12 @@
 
     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);
@@ -202,11 +204,80 @@
 
     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);
 }
 
 /*
@@ -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);
@@ -275,16 +347,15 @@
     event->init();
     allData.push_back(event);
     valueProducer.onDataPulled(allData, /** succeed */ true);
-    // has one slice
-    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    // 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);
@@ -363,9 +434,10 @@
     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);
@@ -378,11 +450,12 @@
     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);
 }
 
 /*
@@ -456,9 +529,10 @@
     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);
 }
 
 /*
@@ -532,9 +606,10 @@
     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);
 
@@ -651,8 +726,8 @@
     event->init();
     allData.push_back(event);
     valueProducer.onDataPulled(allData, /** succeed */ true);
-    EXPECT_EQ(1UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-    EXPECT_EQ(bucket2StartTimeNs + 150, valueProducer.mCurrentBucketStartTimeNs);
+    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);
 }
@@ -694,7 +769,7 @@
 
     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) {
@@ -1018,9 +1093,9 @@
     // 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)
@@ -1681,7 +1756,7 @@
     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);
 }
 
 /*
@@ -1766,7 +1846,7 @@
     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();
@@ -1793,11 +1873,11 @@
     allData.push_back(event1);
     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());
@@ -1817,13 +1897,13 @@
 
     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());
 }
@@ -1892,9 +1972,11 @@
     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();
@@ -1920,35 +2002,34 @@
     allData.push_back(event1);
     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, /** 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, TestResetBaseOnPullFailAfterConditionChange_EndOfBucket) {
@@ -2110,7 +2191,7 @@
     EXPECT_EQ(false, valueProducer.mHasGlobalBase);
 }
 
-TEST(ValueMetricProducerTest, TestResetBaseOnPullTooLate) {
+TEST(ValueMetricProducerTest, TestResetBaseOnPullDelayExceeded) {
     ValueMetric metric;
     metric.set_id(metricId);
     metric.set_bucket(ONE_MINUTE);
@@ -2133,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();
@@ -2145,35 +2226,91 @@
                                       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, /** 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(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);
-
-    // has one slice
-    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-    EXPECT_EQ(false, curInterval.hasValue);
-    EXPECT_EQ(false, curInterval.hasBase);
-    EXPECT_EQ(false, valueProducer.mHasGlobalBase);
 }
 
 TEST(ValueMetricProducerTest, TestInvalidBucketWhenOneConditionFailed) {
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 11bb38b..a0d8a12 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/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/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..fa2a6a1 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;
@@ -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/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 81ed110..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) {
@@ -6625,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<>();
 
@@ -7159,7 +7099,6 @@
 
             dest.readStringList(requestedPermissions);
             internStringArrayList(requestedPermissions);
-            dest.readParcelableList(usesPermissionInfos, boot);
             dest.readStringList(implicitPermissions);
             internStringArrayList(implicitPermissions);
             protectedBroadcasts = dest.createStringArrayList();
@@ -7327,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/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/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/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/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 8a141e2..2aca55a 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -3923,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 3a405d3..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);
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/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/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/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/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/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/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..c0a4028 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;
@@ -131,7 +132,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 +331,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.
@@ -1729,9 +1713,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 +1793,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 +2201,7 @@
         /**
          * @hide
          */
-        @UnsupportedAppUsage
+        @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.O)
         public Transaction setLayerStack(SurfaceControl sc, int layerStack) {
             sc.checkNotReleased();
             nativeSetLayerStack(mNativeObject, sc.mNativeObject, layerStack);
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index e56861e..c641552 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -105,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;
@@ -19181,6 +19182,7 @@
 
         jumpDrawablesToCurrentState();
 
+        AccessibilityNodeIdManager.getInstance().registerViewWithId(this, getAccessibilityViewId());
         resetSubtreeAccessibilityStateChanged();
 
         // rebuild, since Outline not maintained while View is detached
@@ -19573,6 +19575,8 @@
         if ((mViewFlags & TOOLTIP) == TOOLTIP) {
             hideTooltip();
         }
+
+        AccessibilityNodeIdManager.getInstance().unregisterViewWithId(getAccessibilityViewId());
     }
 
     private void cleanupDraw() {
@@ -24087,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/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 47528a0..67cca56 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;
@@ -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/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..924bb9a 100644
--- a/core/java/android/view/contentcapture/ViewNode.java
+++ b/core/java/android/view/contentcapture/ViewNode.java
@@ -600,7 +600,7 @@
     /** @hide */
     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 */
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..542df45 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;
 
     /**
@@ -1611,15 +1613,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.
@@ -4688,7 +4681,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 +4760,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;
 
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/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 3da450d..d876001 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -712,7 +712,7 @@
     @UnsupportedAppUsage
     private ChangeWatcher mChangeWatcher;
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(trackingBug = 123769451)
     private ArrayList<TextWatcher> mListeners;
 
     // display attributes
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 0879af3..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));
             }
         }
 
diff --git a/core/java/com/android/internal/os/Zygote.java b/core/java/com/android/internal/os/Zygote.java
index b881aef..8b669d5 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. */
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index 9ba56b8..4ac7f50 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -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/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/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_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index fad2fe0..68be005 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -483,8 +483,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 +1166,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 +1337,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..0ef4f87 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -647,6 +647,23 @@
 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) {
+    if (volumeLabels.size() > 0) {
+        std::string sandboxDataDir = StringPrintf("/storage/%s", volumeLabels[0].c_str());
+        if (volumeLabels[0] == "emulated") {
+            StringAppendF(&sandboxDataDir, "/%d", userId);
+        }
+        StringAppendF(&sandboxDataDir, "/Android/data/%s", packageNames[0].c_str());
+        struct stat sb;
+        if (TEMP_FAILURE_RETRY(lstat(sandboxDataDir.c_str(), &sb)) == -1) {
+            if (errno == ENOENT) {
+                ALOGD("Sandbox not fully prepared for %s", sandboxDataDir.c_str());
+                return;
+            } else {
+                fail_fn(CREATE_ERROR("Failed to lstat %s: %s",
+                                     sandboxDataDir.c_str(), strerror(errno)));
+            }
+        }
+    }
     for (auto& label : volumeLabels) {
         std::string mntSource = StringPrintf("/mnt/runtime/write/%s", label.c_str());
         std::string mntTarget = StringPrintf("/storage/%s", label.c_str());
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 60b04cf..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.
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 881688b..53cae63 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1689,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
@@ -1792,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
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 9f4fece..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
@@ -3425,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 f84f1f1..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" />
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 401a7fe..1da9149 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3151,7 +3151,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" />
@@ -3595,7 +3595,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/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/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/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/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/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/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/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 8801741..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;
 
@@ -56,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;
@@ -150,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.
@@ -286,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
@@ -306,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;
@@ -789,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;
         }
 
@@ -848,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
@@ -981,6 +1124,8 @@
         //     drop
         //   if it's IPv4 broadcast:
         //     drop
+        // if keepalive ack
+        //   drop
         // pass
 
         if (mMulticastFilter) {
@@ -1024,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);
@@ -1031,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
@@ -1038,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
@@ -1058,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);
 
@@ -1113,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);
+        }
     }
 
     /**
@@ -1491,16 +1656,23 @@
     }
 
     /**
-     * Add keepalive packet filter.
+     * 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 pkt Parameters needed to compose the filter.
+     * @param sentKeepalivePacket The attributes of the sent keepalive packet.
      */
-    public synchronized void addKeepalivePacketFilter(int slot,
-            TcpKeepalivePacketDataParcelable pkt) {
-        // TODO: implement this.
-        Log.e(TAG, "APF function is not implemented: addKeepalivePacketFilter(" + slot + ", "
-                + pkt + ")");
+    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();
     }
 
     /**
@@ -1509,8 +1681,8 @@
      * @param slot The index used to access the filter.
      */
     public synchronized void removeKeepalivePacketFilter(int slot) {
-        // TODO: implement this.
-        Log.e(TAG, "APF function is not implemented: removeKeepalivePacketFilter(" + slot + ")");
+        mKeepaliveAcks.remove(slot);
+        installNewProgramLocked();
     }
 
     static public long counterValue(byte[] data, Counter counter)
@@ -1565,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/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/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/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/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/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index fece94e..c3f61ee 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;
@@ -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/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index d6a46a9..6877f5e 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;
@@ -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;
     }
 
     /**
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/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/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/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/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/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/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/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..37a0610 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -482,7 +482,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,7 +552,7 @@
 
     private final View.OnClickListener mGoToLockedShadeListener = v -> {
         if (mState == StatusBarState.KEYGUARD) {
-            wakeUpIfDozing(SystemClock.uptimeMillis(), v);
+            wakeUpIfDozing(SystemClock.uptimeMillis(), v, "SHADE_CLICK");
             goToLockedShade(null);
         }
     };
@@ -1090,10 +1091,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,
@@ -3729,7 +3730,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 +3892,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/StatusBarWindowView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
index 8b25c34..c39e172 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowView.java
@@ -112,7 +112,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..52cabe2 100644
--- a/packages/SystemUI/src/com/android/systemui/wallpaper/AodMaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/wallpaper/AodMaskView.java
@@ -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/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/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/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/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/telephony/java/android/telephony/ims/RcsPart.java b/services/backup/java/com/android/server/backup/encryption/chunking/OutputStreamWrapper.java
similarity index 60%
rename from telephony/java/android/telephony/ims/RcsPart.java
rename to services/backup/java/com/android/server/backup/encryption/chunking/OutputStreamWrapper.java
index da50173..4aea601 100644
--- a/telephony/java/android/telephony/ims/RcsPart.java
+++ b/services/backup/java/com/android/server/backup/encryption/chunking/OutputStreamWrapper.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2019 The Android Open Source Project
+ * 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.
@@ -13,13 +13,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package android.telephony.ims;
 
-import android.os.Parcelable;
+package com.android.server.backup.encryption.chunking;
 
-/**
- * A part of a composite {@link RcsMessage}.
- * @hide - TODO(sahinc) make this public
- */
-public abstract class RcsPart implements Parcelable {
+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 80b3d67..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();
     }
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/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 d199424..5932f99 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -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..502f078 100644
--- a/services/core/java/com/android/server/am/AppCompactor.java
+++ b/services/core/java/com/android/server/am/AppCompactor.java
@@ -170,6 +170,9 @@
             updateCompactionThrottles();
             updateStatsdSampleRate();
         }
+        Process.setThreadGroupAndCpuset(mCompactionThread.getThreadId(),
+                Process.THREAD_GROUP_SYSTEM);
+
     }
 
     /**
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/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/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/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..2f277e4 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 {
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/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 32dc988..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.");
-                    }
-                }
-            }
         }
     }
 
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/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index 27f7bcf..95c3f4c 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -43,6 +43,7 @@
 import android.util.IntArray;
 import android.util.Log;
 import android.util.SparseBooleanArray;
+import android.util.SparseLongArray;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.server.LocalServices;
@@ -110,7 +111,7 @@
     private final HandlerThread mHandlerThread;
     private final Installer mInstaller;
     private final RollbackPackageHealthObserver mPackageHealthObserver;
-    private final AppDataRollbackHelper mUserdataHelper;
+    private final AppDataRollbackHelper mAppDataRollbackHelper;
 
     RollbackManagerServiceImpl(Context context) {
         mContext = context;
@@ -124,7 +125,7 @@
         mRollbackStore = new RollbackStore(new File(Environment.getDataDirectory(), "rollback"));
 
         mPackageHealthObserver = new RollbackPackageHealthObserver(mContext);
-        mUserdataHelper = new AppDataRollbackHelper(mInstaller);
+        mAppDataRollbackHelper = new AppDataRollbackHelper(mInstaller);
 
         // Kick off loading of the rollback data from strorage in a background
         // thread.
@@ -339,12 +340,9 @@
                 // for apex?
                 if (!info.isApex()) {
                     String installerPackageName = pm.getInstallerPackageName(info.getPackageName());
-                    if (installerPackageName == null) {
-                        sendFailure(statusReceiver, RollbackManager.STATUS_FAILURE,
-                                "Cannot find installer package");
-                        return;
+                    if (installerPackageName != null) {
+                        params.setInstallerPackageName(installerPackageName);
                     }
-                    params.setInstallerPackageName(installerPackageName);
                 }
                 params.setAllowDowngrade(true);
                 if (data.isStaged()) {
@@ -449,7 +447,7 @@
                 for (PackageRollbackInfo info : data.packages) {
                     if (info.getPackageName().equals(packageName)) {
                         iter.remove();
-                        mRollbackStore.deleteAvailableRollback(data);
+                        deleteRollback(data);
                         break;
                     }
                 }
@@ -464,13 +462,13 @@
             final List<RollbackData> changed;
             synchronized (mLock) {
                 ensureRollbackDataLoadedLocked();
-                changed = mUserdataHelper.computePendingBackupsAndRestores(userId,
+                changed = mAppDataRollbackHelper.computePendingBackupsAndRestores(userId,
                         pendingBackupPackages, pendingRestorePackages, mAvailableRollbacks,
                         mRecentlyExecutedRollbacks);
             }
 
-            mUserdataHelper.commitPendingBackupAndRestoreForUser(userId,
-                    pendingBackupPackages, pendingRestorePackages);
+            mAppDataRollbackHelper.commitPendingBackupAndRestoreForUser(userId,
+                    pendingBackupPackages, pendingRestorePackages, changed);
 
             for (RollbackData rd : changed) {
                 try {
@@ -520,7 +518,7 @@
                         // mAvailableRollbacks, or is it okay to leave as
                         // unavailable until the next reboot when it will go
                         // away on its own?
-                        mRollbackStore.deleteAvailableRollback(data);
+                        deleteRollback(data);
                     }
                 }
             }
@@ -592,7 +590,7 @@
                                         info.getVersionRolledBackFrom(),
                                         installedVersion)) {
                         iter.remove();
-                        mRollbackStore.deleteAvailableRollback(data);
+                        deleteRollback(data);
                         break;
                     }
                 }
@@ -705,7 +703,7 @@
 
                 if (!now.isBefore(data.timestamp.plusMillis(ROLLBACK_LIFETIME_DURATION_MILLIS))) {
                     iter.remove();
-                    mRollbackStore.deleteAvailableRollback(data);
+                    deleteRollback(data);
                 } else if (oldest == null || oldest.isAfter(data.timestamp)) {
                     oldest = data.timestamp;
                 }
@@ -821,9 +819,13 @@
             String packageName = newPackage.packageName;
             for (PackageRollbackInfo info : rd.packages) {
                 if (info.getPackageName().equals(packageName)) {
-                    IntArray pendingBackups = mUserdataHelper.snapshotAppData(
-                            packageName, installedUsers);
-                    info.getPendingBackups().addAll(pendingBackups);
+                    AppDataRollbackHelper.SnapshotAppDataResult rs =
+                            mAppDataRollbackHelper.snapshotAppData(packageName, installedUsers);
+                    info.getPendingBackups().addAll(rs.pendingBackups);
+                    for (int i = 0; i < rs.ceSnapshotInodes.size(); i++) {
+                        info.putCeSnapshotInode(rs.ceSnapshotInodes.keyAt(i),
+                                rs.ceSnapshotInodes.valueAt(i));
+                    }
                     try {
                         mRollbackStore.saveAvailableRollback(rd);
                     } catch (IOException ioe) {
@@ -892,13 +894,18 @@
         VersionedPackage installedVersion = new VersionedPackage(packageName,
                 pkgInfo.getLongVersionCode());
 
-        IntArray pendingBackups = IntArray.wrap(new int[0]);
+        final AppDataRollbackHelper.SnapshotAppDataResult result;
         if (snapshotUserData && !isApex) {
-            pendingBackups = mUserdataHelper.snapshotAppData(packageName, installedUsers);
+            result = mAppDataRollbackHelper.snapshotAppData(packageName, installedUsers);
+        } else {
+            result = new AppDataRollbackHelper.SnapshotAppDataResult(IntArray.wrap(new int[0]),
+                new SparseLongArray());
         }
 
         PackageRollbackInfo info = new PackageRollbackInfo(newVersion, installedVersion,
-                pendingBackups, new ArrayList<>(), isApex);
+                result.pendingBackups, new ArrayList<>(), isApex, IntArray.wrap(installedUsers),
+                result.ceSnapshotInodes);
+
         RollbackData data;
         try {
             int childSessionId = session.getSessionId();
@@ -948,9 +955,8 @@
         getHandler().post(() -> {
             final RollbackData rollbackData = getRollbackForPackage(packageName);
             for (int userId : userIds) {
-                final boolean changedRollbackData = mUserdataHelper.restoreAppData(packageName,
-                        rollbackData, userId, appId, ceDataInode, seInfo);
-
+                final boolean changedRollbackData = mAppDataRollbackHelper.restoreAppData(
+                        packageName, rollbackData, userId, appId, ceDataInode, seInfo);
                 // We've updated metadata about this rollback, so save it to flash.
                 if (changedRollbackData) {
                     try {
@@ -1142,12 +1148,12 @@
                     scheduleExpiration(ROLLBACK_LIFETIME_DURATION_MILLIS);
                 } catch (IOException e) {
                     Log.e(TAG, "Unable to enable rollback", e);
-                    mRollbackStore.deleteAvailableRollback(data);
+                    deleteRollback(data);
                 }
             } else {
                 // The install session was aborted, clean up the pending
                 // install.
-                mRollbackStore.deleteAvailableRollback(data);
+                deleteRollback(data);
             }
         }
     }
@@ -1246,4 +1252,17 @@
 
         throw new IOException("Failed to allocate rollback ID");
     }
+
+    private void deleteRollback(RollbackData rollbackData) {
+        for (PackageRollbackInfo info : rollbackData.packages) {
+            IntArray installedUsers = info.getInstalledUsers();
+            SparseLongArray ceSnapshotInodes = info.getCeSnapshotInodes();
+            for (int i = 0; i < installedUsers.size(); i++) {
+                int userId = installedUsers.get(i);
+                mAppDataRollbackHelper.destroyAppDataSnapshot(info.getPackageName(), userId,
+                        ceSnapshotInodes.get(userId, 0));
+            }
+        }
+        mRollbackStore.deleteAvailableRollback(rollbackData);
+    }
 }
diff --git a/services/core/java/com/android/server/rollback/RollbackStore.java b/services/core/java/com/android/server/rollback/RollbackStore.java
index d17ebae..be904ea 100644
--- a/services/core/java/com/android/server/rollback/RollbackStore.java
+++ b/services/core/java/com/android/server/rollback/RollbackStore.java
@@ -23,6 +23,7 @@
 import android.content.rollback.RollbackInfo;
 import android.util.IntArray;
 import android.util.Log;
+import android.util.SparseLongArray;
 
 import libcore.io.IoUtils;
 
@@ -160,6 +161,28 @@
         return restoreInfos;
     }
 
+    private static @NonNull JSONArray ceSnapshotInodesToJson(
+            @NonNull SparseLongArray ceSnapshotInodes) throws JSONException {
+        JSONArray array = new JSONArray();
+        for (int i = 0; i < ceSnapshotInodes.size(); i++) {
+            JSONObject entryJson = new JSONObject();
+            entryJson.put("userId", ceSnapshotInodes.keyAt(i));
+            entryJson.put("ceSnapshotInode", ceSnapshotInodes.valueAt(i));
+            array.put(entryJson);
+        }
+        return array;
+    }
+
+    private static @NonNull SparseLongArray ceSnapshotInodesFromJson(JSONArray json)
+            throws JSONException {
+        SparseLongArray ceSnapshotInodes = new SparseLongArray(json.length());
+        for (int i = 0; i < json.length(); i++) {
+            JSONObject entry = json.getJSONObject(i);
+            ceSnapshotInodes.append(entry.getInt("userId"), entry.getLong("ceSnapshotInode"));
+        }
+        return ceSnapshotInodes;
+    }
+
     /**
      * Reads the list of recently executed rollbacks from persistent storage.
      */
@@ -263,8 +286,6 @@
      * rollback.
      */
     void deleteAvailableRollback(RollbackData data) {
-        // TODO(narayan): Make sure we delete the userdata snapshot along with the backup of the
-        // actual app.
         removeFile(data.backupDir);
     }
 
@@ -341,11 +362,15 @@
 
         IntArray pendingBackups = info.getPendingBackups();
         List<RestoreInfo> pendingRestores = info.getPendingRestores();
+        IntArray installedUsers = info.getInstalledUsers();
         json.put("pendingBackups", convertToJsonArray(pendingBackups));
         json.put("pendingRestores", convertToJsonArray(pendingRestores));
 
         json.put("isApex", info.isApex());
 
+        json.put("installedUsers", convertToJsonArray(installedUsers));
+        json.put("ceSnapshotInodes", ceSnapshotInodesToJson(info.getCeSnapshotInodes()));
+
         return json;
     }
 
@@ -362,8 +387,12 @@
 
         final boolean isApex = json.getBoolean("isApex");
 
+        final IntArray installedUsers = convertToIntArray(json.getJSONArray("installedUsers"));
+        final SparseLongArray ceSnapshotInodes = ceSnapshotInodesFromJson(
+                json.getJSONArray("ceSnapshotInodes"));
+
         return new PackageRollbackInfo(versionRolledBackFrom, versionRolledBackTo,
-                pendingBackups, pendingRestores, isApex);
+                pendingBackups, pendingRestores, isApex, installedUsers, ceSnapshotInodes);
     }
 
     private JSONArray versionedPackagesToJson(List<VersionedPackage> packages)
diff --git a/services/core/java/com/android/server/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/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/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 18df88b..7a8fd49 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -33,14 +33,11 @@
 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.WindowManager.DOCKED_BOTTOM;
 import static android.view.WindowManager.DOCKED_INVALID;
 import static android.view.WindowManager.DOCKED_TOP;
@@ -175,7 +172,6 @@
 import android.view.SurfaceControl.Transaction;
 import android.view.SurfaceSession;
 import android.view.View;
-import android.view.ViewRootImpl;
 import android.view.WindowManager;
 import android.view.WindowManagerPolicyConstants.PointerEventListener;
 
@@ -1162,14 +1158,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 +1185,11 @@
         return handled;
     }
 
+    @Override
+    boolean handlesOrientationChangeFromDescendant() {
+        return getDisplayRotation().respectAppRequestedOrientation();
+    }
+
     /**
      * Determine the new desired orientation of this display.
      *
@@ -1371,8 +1370,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.
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/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/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index b246da4..a054148 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -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/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/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/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/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/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index f399463..3826fac 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -59,7 +59,6 @@
 import android.platform.test.annotations.Presubmit;
 import android.util.DisplayMetrics;
 import android.view.DisplayCutout;
-import android.view.DisplayInfo;
 import android.view.Gravity;
 import android.view.MotionEvent;
 import android.view.Surface;
@@ -585,17 +584,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 +603,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);
 
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..edb395a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java
@@ -179,7 +179,6 @@
     }
 
     @Test
-    @FlakyTest(detail = "Promote once confirmed non-flaky")
     public void testDeferFinish() {
 
         // Start animation
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/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/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/ims/Rcs1To1Thread.java b/telephony/java/android/telephony/ims/Rcs1To1Thread.java
index 709b3aa..cc28ee0 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(109759350) make this 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..744ac76
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsEvent.java
@@ -0,0 +1,60 @@
+/*
+ * 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;
+
+/**
+ * The base class for events that can happen on {@link RcsParticipant}s and {@link RcsThread}s.
+ * @hide - TODO(109759350) make this public
+ */
+public abstract class RcsEvent implements Parcelable {
+    protected 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;
+
+    RcsEvent(Parcel in) {
+        mTimestamp = in.readLong();
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeLong(mTimestamp);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+}
diff --git a/telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl b/telephony/java/android/telephony/ims/RcsEventQueryParameters.aidl
similarity index 94%
rename from telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl
rename to telephony/java/android/telephony/ims/RcsEventQueryParameters.aidl
index 82d985d..9a3600b 100644
--- a/telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl
+++ b/telephony/java/android/telephony/ims/RcsEventQueryParameters.aidl
@@ -17,4 +17,4 @@
 
 package android.telephony.ims;
 
-parcelable RcsThreadIconChangedEvent;
+parcelable RcsEventQueryParameters;
diff --git a/telephony/java/android/telephony/ims/RcsEventQueryParameters.java b/telephony/java/android/telephony/ims/RcsEventQueryParameters.java
new file mode 100644
index 0000000..6aee56f
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsEventQueryParameters.java
@@ -0,0 +1,322 @@
+/*
+ * 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(RcsEventQueryParameters)} in order to select a
+ * subset of {@link RcsEvent}s present in the message store.
+ *
+ * @hide TODO - make the Builder and builder() public. The rest should stay internal only.
+ */
+public class RcsEventQueryParameters implements Parcelable {
+    /**
+     * Flag to be used with {@link Builder#setEventType(int)} to make
+     * {@link RcsMessageStore#getRcsEvents(RcsEventQueryParameters)} 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(RcsEventQueryParameters)} 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(RcsEventQueryParameters)} 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(RcsEventQueryParameters)} 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(RcsEventQueryParameters)} 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(RcsEventQueryParameters)} 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(RcsEventQueryParameters)} 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;
+
+    RcsEventQueryParameters(@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 RcsEventQueryParameters} is
+     * set to query for.
+     */
+    public @EventType int getEventType() {
+        return mEventType;
+    }
+
+    /**
+     * @return Returns the type of {@link RcsEvent}s that this {@link RcsEventQueryParameters} 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 RcsEventQueryParameters}.
+     */
+    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 RcsEventQueryParameters} to be used in
+         * {@link RcsMessageStore#getRcsEvents(RcsEventQueryParameters)}
+         */
+        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 RcsEventQueryParameters.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 RcsEventQueryParameters} to use in
+         * {@link RcsMessageStore#getRcsEvents(RcsEventQueryParameters)}
+         *
+         * @return An instance of {@link RcsEventQueryParameters} to use with the event query.
+         */
+        public RcsEventQueryParameters build() {
+            return new RcsEventQueryParameters(mEventType, mThreadId, mSortingProperty,
+                    mIsAscending, mLimit);
+        }
+    }
+
+    protected RcsEventQueryParameters(Parcel in) {
+        mEventType = in.readInt();
+        mThreadId = in.readInt();
+        mSortingProperty = in.readInt();
+        mIsAscending = in.readBoolean();
+        mLimit = in.readInt();
+    }
+
+    public static final Creator<RcsEventQueryParameters> CREATOR =
+            new Creator<RcsEventQueryParameters>() {
+                @Override
+                public RcsEventQueryParameters createFromParcel(Parcel in) {
+                    return new RcsEventQueryParameters(in);
+                }
+
+                @Override
+                public RcsEventQueryParameters[] newArray(int size) {
+                    return new RcsEventQueryParameters[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..27898ab
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsEventQueryResult.java
@@ -0,0 +1,90 @@
+/*
+ * 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(RcsEventQueryParameters)}
+ * 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
+ */
+public 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;
+    }
+
+    protected RcsEventQueryResult(Parcel in) {
+    }
+
+    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/RcsFileTransferCreationParameters.aidl
similarity index 93%
copy from telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl
copy to telephony/java/android/telephony/ims/RcsFileTransferCreationParameters.aidl
index 82d985d..5fec021 100644
--- a/telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl
+++ b/telephony/java/android/telephony/ims/RcsFileTransferCreationParameters.aidl
@@ -17,4 +17,4 @@
 
 package android.telephony.ims;
 
-parcelable RcsThreadIconChangedEvent;
+parcelable RcsFileTransferCreationParameters;
diff --git a/telephony/java/android/telephony/ims/RcsFileTransferCreationParameters.java b/telephony/java/android/telephony/ims/RcsFileTransferCreationParameters.java
new file mode 100644
index 0000000..bd7cb4b
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsFileTransferCreationParameters.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(RcsFileTransferCreationParameters)} create an
+ * {@link RcsFileTransferPart} and save it into storage.
+ *
+ * @hide - TODO(109759350) make this public
+ */
+public class RcsFileTransferCreationParameters 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
+     */
+    RcsFileTransferCreationParameters(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 RcsFileTransferCreationParameters}
+     */
+    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 RcsFileTransferCreationParameters} with the given
+         * parameters.
+         *
+         * @return The same instance of {@link Builder} to chain methods
+         * @see RcsMessage#insertFileTransfer(RcsFileTransferCreationParameters)
+         */
+        public RcsFileTransferCreationParameters build() {
+            return new RcsFileTransferCreationParameters(this);
+        }
+    }
+
+    protected RcsFileTransferCreationParameters(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<RcsFileTransferCreationParameters> CREATOR =
+            new Creator<RcsFileTransferCreationParameters>() {
+                @Override
+                public RcsFileTransferCreationParameters createFromParcel(Parcel in) {
+                    return new RcsFileTransferCreationParameters(in);
+                }
+
+                @Override
+                public RcsFileTransferCreationParameters[] newArray(int size) {
+                    return new RcsFileTransferCreationParameters[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..2eadc4a 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(109759350) make this 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..6f6258e 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.
+ * or leave. Please see Section 6 (Group Chat) - GSMA RCC.71 (RCS Universal Profile Service
+ * Definition Document)
+ *
  * @hide - TODO(sahinc) make this 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 {
+        RcsParticipantQueryParameters queryParameters =
+                new RcsParticipantQueryParameters.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..a18437b
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsGroupThreadEvent.java
@@ -0,0 +1,65 @@
+/*
+ * 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(109759350) make this 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);
+    }
+
+    RcsGroupThreadEvent(Parcel in) {
+        super(in);
+        mRcsGroupThreadId = in.readInt();
+        mOriginatingParticipantId = in.readInt();
+    }
+
+    @Override
+    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..7beed3b
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsGroupThreadIconChangedEvent.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.net.Uri;
+import android.os.Parcel;
+
+/**
+ * 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(109759350) make this public
+ */
+public class RcsGroupThreadIconChangedEvent extends RcsGroupThreadEvent {
+    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];
+                }
+            };
+
+    protected 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..0d2ea4f
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsGroupThreadNameChangedEvent.java
@@ -0,0 +1,107 @@
+/*
+ * 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;
+
+/**
+ * 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(109759350) make this public
+ */
+public class RcsGroupThreadNameChangedEvent extends RcsGroupThreadEvent {
+    private 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];
+                }
+            };
+
+    protected 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..2adafc7
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsGroupThreadParticipantJoinedEvent.java
@@ -0,0 +1,107 @@
+/*
+ * 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 indicates an RCS participant has joined an {@link RcsThread}. Please see US6-3 -
+ * GSMA RCC.71 (RCS Universal Profile Service Definition Document)
+ *
+ * @hide - TODO(109759350) make this public
+ */
+public class RcsGroupThreadParticipantJoinedEvent extends RcsGroupThreadEvent {
+    private 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];
+                }
+            };
+
+    protected 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..87c1852
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsGroupThreadParticipantLeftEvent.java
@@ -0,0 +1,106 @@
+/*
+ * 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 indicates an RCS participant has left an {@link RcsThread}. Please see US6-23 -
+ * GSMA RCC.71 (RCS Universal Profile Service Definition Document)
+ *
+ * @hide - TODO(109759350) make this public
+ */
+public class RcsGroupThreadParticipantLeftEvent extends RcsGroupThreadEvent {
+    private 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];
+                }
+            };
+
+    protected 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..2ea115b 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(109759350) make this 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/RcsIncomingMessageCreationParameters.aidl
similarity index 92%
copy from telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl
copy to telephony/java/android/telephony/ims/RcsIncomingMessageCreationParameters.aidl
index 82d985d..76073c2 100644
--- a/telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl
+++ b/telephony/java/android/telephony/ims/RcsIncomingMessageCreationParameters.aidl
@@ -17,4 +17,4 @@
 
 package android.telephony.ims;
 
-parcelable RcsThreadIconChangedEvent;
+parcelable RcsIncomingMessageCreationParameters;
diff --git a/telephony/java/android/telephony/ims/RcsIncomingMessageCreationParameters.java b/telephony/java/android/telephony/ims/RcsIncomingMessageCreationParameters.java
new file mode 100644
index 0000000..acde8af
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsIncomingMessageCreationParameters.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 RcsIncomingMessageCreationParameters} is a collection of parameters that should be passed
+ * into {@link RcsThread#addIncomingMessage(RcsIncomingMessageCreationParameters)} to generate an
+ * {@link RcsIncomingMessage} on that {@link RcsThread}
+ *
+ * @hide TODO:make public
+ */
+public class RcsIncomingMessageCreationParameters extends RcsMessageCreationParameters 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 RcsIncomingMessageCreationParameters}
+     *
+     * @see RcsThread#addIncomingMessage(RcsIncomingMessageCreationParameters)
+     */
+    public static class Builder extends RcsMessageCreationParameters.Builder {
+        private RcsParticipant mSenderParticipant;
+        private long mArrivalTimestamp;
+        private long mSeenTimestamp;
+
+        /**
+         * Creates a {@link Builder} to create an instance of
+         * {@link RcsIncomingMessageCreationParameters}
+         *
+         * @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 RcsIncomingMessageCreationParameters} to create a new
+         * {@link RcsIncomingMessage}
+         */
+        public RcsIncomingMessageCreationParameters build() {
+            return new RcsIncomingMessageCreationParameters(this);
+        }
+    }
+
+    private RcsIncomingMessageCreationParameters(Builder builder) {
+        super(builder);
+        mArrivalTimestamp = builder.mArrivalTimestamp;
+        mSeenTimestamp = builder.mSeenTimestamp;
+        mSenderParticipantId = builder.mSenderParticipant.getId();
+    }
+
+    protected RcsIncomingMessageCreationParameters(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<RcsIncomingMessageCreationParameters> CREATOR =
+            new Creator<RcsIncomingMessageCreationParameters>() {
+                @Override
+                public RcsIncomingMessageCreationParameters createFromParcel(Parcel in) {
+                    return new RcsIncomingMessageCreationParameters(in);
+                }
+
+                @Override
+                public RcsIncomingMessageCreationParameters[] newArray(int size) {
+                    return new RcsIncomingMessageCreationParameters[size];
+                }
+            };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        super.writeToParcel(dest, flags);
+        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..e84d4ed 100644
--- a/telephony/java/android/telephony/ims/RcsManager.java
+++ b/telephony/java/android/telephony/ims/RcsManager.java
@@ -28,7 +28,7 @@
     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..b70a9a7 100644
--- a/telephony/java/android/telephony/ims/RcsMessage.java
+++ b/telephony/java/android/telephony/ims/RcsMessage.java
@@ -15,11 +15,314 @@
  */
 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(109759350) make this 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;
+
+    protected 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(
+            RcsFileTransferCreationParameters 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/RcsThreadIconChangedEvent.aidl b/telephony/java/android/telephony/ims/RcsMessageCreationParameters.aidl
similarity index 93%
copy from telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl
copy to telephony/java/android/telephony/ims/RcsMessageCreationParameters.aidl
index 82d985d..5774d00 100644
--- a/telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl
+++ b/telephony/java/android/telephony/ims/RcsMessageCreationParameters.aidl
@@ -17,4 +17,4 @@
 
 package android.telephony.ims;
 
-parcelable RcsThreadIconChangedEvent;
+parcelable RcsMessageCreationParameters;
diff --git a/telephony/java/android/telephony/ims/RcsMessageCreationParameters.java b/telephony/java/android/telephony/ims/RcsMessageCreationParameters.java
new file mode 100644
index 0000000..ff3f33e
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsMessageCreationParameters.java
@@ -0,0 +1,265 @@
+/*
+ * 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;
+import android.os.Parcelable;
+import android.telephony.SubscriptionInfo;
+
+/**
+ * The collection of parameters to be passed into
+ * {@link RcsThread#addIncomingMessage(RcsIncomingMessageCreationParameters)} and
+ * {@link RcsThread#addOutgoingMessage(RcsMessageCreationParameters)} to create and persist
+ * {@link RcsMessage}s on an {@link RcsThread}
+ *
+ * @hide TODO - make public
+ */
+public class RcsMessageCreationParameters implements Parcelable {
+    // 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 RcsIncomingMessageCreationParameters
+     */
+    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;
+
+        /**
+         * Creates a new {@link Builder} to create an instance of
+         * {@link RcsMessageCreationParameters}.
+         *
+         * @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 SubscriptionInfo#getSubscriptionId()
+         */
+        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;
+        }
+
+        /**
+         * @hide
+         */
+        public RcsMessageCreationParameters build() {
+            return new RcsMessageCreationParameters(this);
+        }
+    }
+
+    protected RcsMessageCreationParameters(Builder builder) {
+        mRcsMessageGlobalId = builder.mRcsMessageGlobalId;
+        mSubId = builder.mSubId;
+        mMessageStatus = builder.mMessageStatus;
+        mOriginationTimestamp = builder.mOriginationTimestamp;
+        mText = builder.mText;
+        mLatitude = builder.mLatitude;
+        mLongitude = builder.mLongitude;
+    }
+
+    protected RcsMessageCreationParameters(Parcel in) {
+        mRcsMessageGlobalId = in.readString();
+        mSubId = in.readInt();
+        mMessageStatus = in.readInt();
+        mOriginationTimestamp = in.readLong();
+        mText = in.readString();
+        mLatitude = in.readDouble();
+        mLongitude = in.readDouble();
+    }
+
+    public static final Creator<RcsMessageCreationParameters> CREATOR =
+            new Creator<RcsMessageCreationParameters>() {
+                @Override
+                public RcsMessageCreationParameters createFromParcel(Parcel in) {
+                    return new RcsMessageCreationParameters(in);
+                }
+
+                @Override
+                public RcsMessageCreationParameters[] newArray(int size) {
+                    return new RcsMessageCreationParameters[size];
+                }
+            };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        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/RcsMessageQueryParameters.aidl
similarity index 94%
copy from telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl
copy to telephony/java/android/telephony/ims/RcsMessageQueryParameters.aidl
index 82d985d..c325c23 100644
--- a/telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl
+++ b/telephony/java/android/telephony/ims/RcsMessageQueryParameters.aidl
@@ -17,4 +17,4 @@
 
 package android.telephony.ims;
 
-parcelable RcsThreadIconChangedEvent;
+parcelable RcsMessageQueryParameters;
diff --git a/telephony/java/android/telephony/ims/RcsMessageQueryParameters.java b/telephony/java/android/telephony/ims/RcsMessageQueryParameters.java
new file mode 100644
index 0000000..c964cf9
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsMessageQueryParameters.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(RcsMessageQueryParameters)} in order to select a
+ * subset of {@link RcsMessage}s present in the message store.
+ *
+ * @hide TODO - make the Builder and builder() public. The rest should stay internal only.
+ */
+public class RcsMessageQueryParameters 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(RcsMessageQueryParameters)} 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(RcsMessageQueryParameters)} 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(RcsMessageQueryParameters)} 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(RcsMessageQueryParameters)} 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;
+
+    RcsMessageQueryParameters(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 RcsMessageQueryParameters}
+     * 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 RcsMessageQueryParameters}.
+     */
+    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 RcsMessageQueryParameters} to be used in
+         * {@link RcsMessageStore#getRcsMessages(RcsMessageQueryParameters)}
+         *
+         */
+        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 RcsMessageQueryParameters#MESSAGE_TYPE_INCOMING
+         * @see RcsMessageQueryParameters#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 RcsMessageQueryParameters#MESSAGES_WITH_FILE_TRANSFERS
+         * @see RcsMessageQueryParameters#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 RcsMessageQueryParameters.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 RcsMessageQueryParameters} to use in
+         * {@link RcsMessageStore#getRcsMessages(RcsMessageQueryParameters)}
+         *
+         * @return An instance of {@link RcsMessageQueryParameters} to use with the message
+         * query.
+         */
+        public RcsMessageQueryParameters build() {
+            return new RcsMessageQueryParameters(mMessageType, mFileTransferPresence, mMessageLike,
+                    mThreadId, mSortingProperty, mIsAscending, mLimit);
+        }
+    }
+
+    /**
+     * Parcelable boilerplate below.
+     */
+    protected RcsMessageQueryParameters(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<RcsMessageQueryParameters> CREATOR =
+            new Creator<RcsMessageQueryParameters>() {
+                @Override
+                public RcsMessageQueryParameters createFromParcel(Parcel in) {
+                    return new RcsMessageQueryParameters(in);
+                }
+
+                @Override
+                public RcsMessageQueryParameters[] newArray(int size) {
+                    return new RcsMessageQueryParameters[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..c3846fd
--- /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(RcsMessageQueryParameters)}
+ * 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
+ */
+public 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;
+    }
+
+    protected 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..9399c20
--- /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 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;
+    }
+
+    protected 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..c8c36a8 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
  */
 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 RcsThreadQueryParameters 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 RcsParticipantQueryParameters 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 RcsMessageQueryParameters 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 RcsEventQueryParameters 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..e158f1a
--- /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..0bd55ec 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(109759350) make this 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/RcsOutgoingMessageDelivery.java b/telephony/java/android/telephony/ims/RcsOutgoingMessageDelivery.java
new file mode 100644
index 0000000..b93f892
--- /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(109759350) make this 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/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..ce0ad2c 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(109759350) make this 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..04cdf86 100644
--- a/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEvent.java
+++ b/telephony/java/android/telephony/ims/RcsParticipantAliasChangedEvent.java
@@ -15,27 +15,93 @@
  */
 package android.telephony.ims;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.os.Parcel;
 
 /**
- * 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(109759350) make this public
  */
-public class RcsParticipantAliasChangedEvent extends RcsParticipantEvent {
+public class RcsParticipantAliasChangedEvent extends RcsEvent {
+    // The ID of the participant that changed their alias
+    private int mParticipantId;
+    // The new alias of the above participant
+    private 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) {
+        super(in);
+        mNewAlias = in.readString();
+        mParticipantId = in.readInt();
     }
 
     @Override
@@ -45,5 +111,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/RcsParticipantQueryParameters.aidl
similarity index 93%
copy from telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl
copy to telephony/java/android/telephony/ims/RcsParticipantQueryParameters.aidl
index 82d985d..ea8288c 100644
--- a/telephony/java/android/telephony/ims/RcsThreadIconChangedEvent.aidl
+++ b/telephony/java/android/telephony/ims/RcsParticipantQueryParameters.aidl
@@ -17,4 +17,4 @@
 
 package android.telephony.ims;
 
-parcelable RcsThreadIconChangedEvent;
+parcelable RcsParticipantQueryParameters;
diff --git a/telephony/java/android/telephony/ims/RcsParticipantQueryParameters.java b/telephony/java/android/telephony/ims/RcsParticipantQueryParameters.java
new file mode 100644
index 0000000..3611fc1
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsParticipantQueryParameters.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(RcsParticipantQueryParameters)} 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 RcsParticipantQueryParameters 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";
+
+    RcsParticipantQueryParameters(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 RcsParticipantQueryParameters}.
+     */
+    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 RcsParticipantQueryParameters} to be used in
+         * {@link RcsMessageStore#getRcsParticipants(RcsParticipantQueryParameters)}
+         */
+        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 RcsParticipantQueryParameters.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 RcsParticipantQueryParameters} to use in
+         * {@link RcsMessageStore#getRcsParticipants(RcsParticipantQueryParameters)}
+         *
+         * @return An instance of {@link RcsParticipantQueryParameters} to use with the participant
+         * query.
+         */
+        public RcsParticipantQueryParameters build() {
+            return new RcsParticipantQueryParameters(mThreadId, mAliasLike, mCanonicalAddressLike,
+                    mSortingProperty, mIsAscending, mLimit);
+        }
+    }
+
+    /**
+     * Parcelable boilerplate below.
+     */
+    protected RcsParticipantQueryParameters(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<RcsParticipantQueryParameters> CREATOR =
+            new Creator<RcsParticipantQueryParameters>() {
+                @Override
+                public RcsParticipantQueryParameters createFromParcel(Parcel in) {
+                    return new RcsParticipantQueryParameters(in);
+                }
+
+                @Override
+                public RcsParticipantQueryParameters[] newArray(int size) {
+                    return new RcsParticipantQueryParameters[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..2f4ab46
--- /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(RcsParticipantQueryParameters)}
+ * 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
+ */
+public 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;
+    }
+
+    protected 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..e880651
--- /dev/null
+++ b/telephony/java/android/telephony/ims/RcsQueryContinuationToken.java
@@ -0,0 +1,151 @@
+/*
+ * 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;
+
+/**
+ * This interface allows using the same implementation for continuation token usage in
+ * {@link com.android.providers.telephony.RcsProvider}
+ * @hide - TODO make getQueryType() and types public - the rest should stay internal
+ */
+public 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;
+    }
+
+    protected 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..238f5e7 100644
--- a/telephony/java/android/telephony/ims/RcsThread.java
+++ b/telephony/java/android/telephony/ims/RcsThread.java
@@ -16,60 +16,117 @@
 
 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(109759350) make this 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
     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 RcsIncomingMessageCreationParameters rcsIncomingMessageCreationParameters)
+            throws RcsMessageStoreException {
+        return new RcsIncomingMessage(RcsControllerCall.call(iRcs -> iRcs.addIncomingMessage(
+                mThreadId, rcsIncomingMessageCreationParameters)));
     }
 
-    @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 RcsMessageCreationParameters rcsMessageCreationParameters)
+            throws RcsMessageStoreException {
+        int messageId = RcsControllerCall.call(iRcs -> iRcs.addOutgoingMessage(
+                mThreadId, rcsMessageCreationParameters));
+
+        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(RcsMessageQueryParameters)}
+     *
+     * @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 {
+        RcsMessageQueryParameters queryParameters =
+                new RcsMessageQueryParameters.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
index feb2d4d..52e73ce 100644
--- a/telephony/java/android/telephony/ims/RcsThreadQueryParameters.aidl
+++ b/telephony/java/android/telephony/ims/RcsThreadQueryParameters.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/RcsThreadQueryParameters.java b/telephony/java/android/telephony/ims/RcsThreadQueryParameters.java
index f2c4ab1..4aa4207 100644
--- a/telephony/java/android/telephony/ims/RcsThreadQueryParameters.java
+++ b/telephony/java/android/telephony/ims/RcsThreadQueryParameters.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.
@@ -17,72 +17,133 @@
 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(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;
+    /**
+     * Bitmask flag to be used with {@link Builder#setThreadType(int)} to make
+     * {@link RcsMessageStore#getRcsThreads(RcsThreadQueryParameters)} 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(RcsThreadQueryParameters)} 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;
 
-    RcsThreadQueryParameters(boolean isGroup, Set<RcsParticipant> participants, int limit,
-            boolean isAscending) {
-        mIsGroup = isGroup;
-        mRcsParticipants = participants;
+    /**
+     * 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";
+
+    RcsThreadQueryParameters(int threadType, Set<RcsParticipant> participants,
+            int limit, int sortingProperty, boolean isAscending) {
+        mThreadType = threadType;
+        mRcsParticipantIds = convertParticipantSetToIdList(participants);
         mLimit = limit;
+        mSortingProperty = sortingProperty;
         mIsAscending = isAscending;
     }
 
-    /**
-     * Returns a new builder to build a query with.
-     * TODO - make public
-     */
-    public static Builder builder() {
-        return new Builder();
+    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 participants.
-     * @hide
+     * 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 Set<RcsParticipant> getRcsParticipants() {
-        return mRcsParticipants;
+    public List<Integer> getRcsParticipantsIds() {
+        return Collections.unmodifiableList(mRcsParticipantIds);
     }
 
     /**
-     * This is used in {@link com.android.internal.telephony.ims.RcsMessageStoreController} to get
-     * whether group threads should be queried
-     * @hide
+     * @return Returns the bitmask flag for types of {@link RcsThread}s that this query should
+     * return.
      */
-    public boolean isGroupThread() {
-        return mIsGroup;
+    public int getThreadType() {
+        return mThreadType;
     }
 
     /**
-     * This is used in {@link com.android.internal.telephony.ims.RcsMessageStoreController} to get
-     * the number of tuples the result query should be limited to.
+     * @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;
     }
 
     /**
-     * This is used in {@link com.android.internal.telephony.ims.RcsMessageStoreController} to
-     * determine the sort order.
+     * @return Returns the property that will be used to sort the result against.
+     * @see SortingProperty
      */
-    public boolean isAscending() {
+    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;
     }
 
@@ -90,64 +151,74 @@
      * A helper class to build the {@link RcsThreadQueryParameters}.
      */
     public static class Builder {
-        private boolean mIsGroupThread;
+        private int mThreadType;
         private Set<RcsParticipant> mParticipants;
         private int mLimit = 100;
+        private @SortingProperty int mSortingProperty;
         private boolean mIsAscending;
 
         /**
-         * Package private constructor for {@link RcsThreadQueryParameters.Builder}. To obtain this,
-         * {@link RcsThreadQueryParameters#builder()} needs to be called.
+         * Constructs a {@link RcsThreadQueryParameters.Builder} to help build an
+         * {@link RcsThreadQueryParameters}
          */
-        Builder() {
+        public Builder() {
             mParticipants = new HashSet<>();
         }
 
         /**
          * Limits the query to only return group threads.
-         * @param isGroupThread Whether to limit the query result to group threads.
+         *
+         * @param threadType Whether to limit the query result to group threads.
          * @return The same instance of the builder to chain parameters.
+         * @see RcsThreadQueryParameters#THREAD_TYPE_GROUP
+         * @see RcsThreadQueryParameters#THREAD_TYPE_1_TO_1
          */
         @CheckResult
-        public Builder isGroupThread(boolean isGroupThread) {
-            mIsGroupThread = isGroupThread;
+        public Builder setThreadType(int threadType) {
+            mThreadType = threadType;
             return this;
         }
 
         /**
-         * Limits the query to only return threads that contain the given participant.
+         * 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 withParticipant(RcsParticipant participant) {
+        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.
+         * 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 withParticipants(Iterable<RcsParticipant> participants) {
-            for (RcsParticipant participant : participants) {
-                mParticipants.add(participant);
-            }
+        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 limitResultsTo(int limit) throws InvalidParameterException {
+        public Builder setResultLimit(@IntRange(from = 0) int limit)
+                throws InvalidParameterException {
             if (limit < 0) {
                 throw new InvalidParameterException("The query limit must be non-negative");
             }
@@ -157,15 +228,26 @@
         }
 
         /**
-         * Sorts the results returned from the query via thread IDs.
+         * Sets the property where the results should be sorted against. Defaults to
+         * {@link SortingProperty#SORT_BY_CREATION_ORDER}
          *
-         * TODO - add sorting support for other fields
-         *
-         * @param isAscending whether to sort in ascending order or not
+         * @param sortingProperty whether to sort in ascending order or not
          * @return The same instance of the builder to chain parameters.
          */
         @CheckResult
-        public Builder sort(boolean isAscending) {
+        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;
         }
@@ -177,8 +259,8 @@
          * @return An instance of {@link RcsThreadQueryParameters} to use with the thread query.
          */
         public RcsThreadQueryParameters build() {
-            return new RcsThreadQueryParameters(
-                    mIsGroupThread, mParticipants, mLimit, mIsAscending);
+            return new RcsThreadQueryParameters(mThreadType, mParticipants, mLimit,
+                    mSortingProperty, mIsAscending);
         }
     }
 
@@ -186,14 +268,12 @@
      * Parcelable boilerplate below.
      */
     protected RcsThreadQueryParameters(Parcel in) {
-        mIsGroup = in.readBoolean();
-
-        ArrayList<RcsParticipant> participantArrayList = new ArrayList<>();
-        in.readTypedList(participantArrayList, RcsParticipant.CREATOR);
-        mRcsParticipants = new HashSet<>(participantArrayList);
-
+        mThreadType = in.readInt();
+        mRcsParticipantIds = new ArrayList<>();
+        in.readList(mRcsParticipantIds, Integer.class.getClassLoader());
         mLimit = in.readInt();
-        mIsAscending = in.readBoolean();
+        mSortingProperty = in.readInt();
+        mIsAscending = in.readByte() == 1;
     }
 
     public static final Creator<RcsThreadQueryParameters> CREATOR =
@@ -216,10 +296,10 @@
 
     @Override
     public void writeToParcel(Parcel dest, int flags) {
-        dest.writeBoolean(mIsGroup);
-        dest.writeTypedList(new ArrayList<>(mRcsParticipants));
+        dest.writeInt(mThreadType);
+        dest.writeList(mRcsParticipantIds);
         dest.writeInt(mLimit);
-        dest.writeBoolean(mIsAscending);
+        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..6515933 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(RcsThreadQueryParameters)}
  * 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
  */
 public class RcsThreadQueryResult implements Parcelable {
-    private RcsThreadQueryContinuationToken mContinuationToken;
-    private List<RcsThread> mRcsThreads;
+    // 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
+        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..a399786 100644
--- a/telephony/java/android/telephony/ims/aidl/IRcs.aidl
+++ b/telephony/java/android/telephony/ims/aidl/IRcs.aidl
@@ -16,9 +16,18 @@
 
 package android.telephony.ims.aidl;
 
-import android.telephony.ims.RcsParticipant;
-import android.telephony.ims.Rcs1To1Thread;
-import android.telephony.ims.RcsThreadQueryContinuationToken;
+import android.net.Uri;
+import android.telephony.ims.RcsEventQueryParameters;
+import android.telephony.ims.RcsEventQueryResult;
+import android.telephony.ims.RcsFileTransferCreationParameters;
+import android.telephony.ims.RcsIncomingMessageCreationParameters;
+import android.telephony.ims.RcsMessageCreationParameters;
+import android.telephony.ims.RcsMessageSnippet;
+import android.telephony.ims.RcsMessageQueryParameters;
+import android.telephony.ims.RcsMessageQueryResult;
+import android.telephony.ims.RcsParticipantQueryParameters;
+import android.telephony.ims.RcsParticipantQueryResult;
+import android.telephony.ims.RcsQueryContinuationToken;
 import android.telephony.ims.RcsThreadQueryParameters;
 import android.telephony.ims.RcsThreadQueryResult;
 
@@ -27,23 +36,231 @@
  * {@hide}
  */
 interface IRcs {
+    /////////////////////////
     // RcsMessageStore APIs
+    /////////////////////////
     RcsThreadQueryResult getRcsThreads(in RcsThreadQueryParameters queryParameters);
 
     RcsThreadQueryResult getRcsThreadsWithToken(
-        in RcsThreadQueryContinuationToken continuationToken);
+        in RcsQueryContinuationToken continuationToken);
 
-    void deleteThread(int threadId);
+    RcsParticipantQueryResult getParticipants(in RcsParticipantQueryParameters queryParameters);
 
-    Rcs1To1Thread createRcs1To1Thread(in RcsParticipant participant);
+    RcsParticipantQueryResult getParticipantsWithToken(
+        in RcsQueryContinuationToken continuationToken);
 
+    RcsMessageQueryResult getMessages(in RcsMessageQueryParameters queryParameters);
+
+    RcsMessageQueryResult getMessagesWithToken(
+        in RcsQueryContinuationToken continuationToken);
+
+    RcsEventQueryResult getEvents(in RcsEventQueryParameters queryParameters);
+
+    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 RcsIncomingMessageCreationParameters rcsIncomingMessageCreationParameters);
+
+    // Creates a new RcsOutgoingMessage on the given thread and returns its row ID
+    int addOutgoingMessage(int rcsThreadId,
+            in RcsMessageCreationParameters rcsMessageCreationParameters);
+
+    // 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 RcsFileTransferCreationParameters fileTransferCreationParameters);
+
+    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/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/RcsParticipantQueryParametersTest.java b/tests/RcsTests/src/com/android/tests/ims/RcsParticipantQueryParametersTest.java
new file mode 100644
index 0000000..b4bcb5d
--- /dev/null
+++ b/tests/RcsTests/src/com/android/tests/ims/RcsParticipantQueryParametersTest.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.RcsParticipantQueryParameters;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+public class RcsParticipantQueryParametersTest {
+
+    @Test
+    public void testCanUnparcel() {
+        RcsParticipantQueryParameters rcsParticipantQueryParameters =
+                new RcsParticipantQueryParameters.Builder()
+                        .setAliasLike("%alias_")
+                        .setCanonicalAddressLike("_canonical%")
+                        .setSortProperty(RcsParticipantQueryParameters.SORT_BY_CANONICAL_ADDRESS)
+                        .setSortDirection(true)
+                        .setResultLimit(432)
+                        .build();
+
+
+        Parcel parcel = Parcel.obtain();
+        rcsParticipantQueryParameters.writeToParcel(parcel,
+                rcsParticipantQueryParameters.describeContents());
+
+        parcel.setDataPosition(0);
+        rcsParticipantQueryParameters = RcsParticipantQueryParameters.CREATOR.createFromParcel(
+                parcel);
+
+        assertThat(rcsParticipantQueryParameters.getAliasLike()).isEqualTo("%alias_");
+        assertThat(rcsParticipantQueryParameters.getCanonicalAddressLike()).contains("_canonical%");
+        assertThat(rcsParticipantQueryParameters.getLimit()).isEqualTo(432);
+        assertThat(rcsParticipantQueryParameters.getSortingProperty()).isEqualTo(
+                RcsParticipantQueryParameters.SORT_BY_CANONICAL_ADDRESS);
+        assertThat(rcsParticipantQueryParameters.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
index a890a38..0a70eec 100644
--- a/tests/RcsTests/src/com/android/tests/ims/RcsThreadQueryParametersTest.java
+++ b/tests/RcsTests/src/com/android/tests/ims/RcsThreadQueryParametersTest.java
@@ -15,39 +15,44 @@
  */
 package com.android.tests.ims;
 
+import static android.telephony.ims.RcsThreadQueryParameters.SORT_BY_TIMESTAMP;
+import static android.telephony.ims.RcsThreadQueryParameters.THREAD_TYPE_GROUP;
+
 import static com.google.common.truth.Truth.assertThat;
 
-import android.os.Bundle;
+import android.os.Parcel;
 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)
+    public void testCanUnparcel() {
+        RcsParticipant rcsParticipant = new RcsParticipant(1);
+        RcsThreadQueryParameters rcsThreadQueryParameters = new RcsThreadQueryParameters.Builder()
+                .setThreadType(THREAD_TYPE_GROUP)
+                .setParticipant(rcsParticipant)
+                .setResultLimit(50)
+                .setSortProperty(SORT_BY_TIMESTAMP)
+                .setSortDirection(true)
                 .build();
 
-        Bundle bundle = new Bundle();
-        bundle.putParcelable(key, mRcsThreadQueryParameters);
-        mRcsThreadQueryParameters = bundle.getParcelable(key);
+        Parcel parcel = Parcel.obtain();
+        rcsThreadQueryParameters.writeToParcel(parcel, rcsThreadQueryParameters.describeContents());
 
-        assertThat(mRcsThreadQueryParameters.isGroupThread()).isTrue();
-        assertThat(mRcsThreadQueryParameters.getRcsParticipants()).contains(mMockParticipant);
-        assertThat(mRcsThreadQueryParameters.getLimit()).isEqualTo(50);
-        assertThat(mRcsThreadQueryParameters.isAscending()).isTrue();
+        parcel.setDataPosition(0);
+        rcsThreadQueryParameters = RcsThreadQueryParameters.CREATOR.createFromParcel(parcel);
+
+        assertThat(rcsThreadQueryParameters.getThreadType()).isEqualTo(THREAD_TYPE_GROUP);
+        assertThat(rcsThreadQueryParameters.getRcsParticipantsIds())
+                .contains(rcsParticipant.getId());
+        assertThat(rcsThreadQueryParameters.getLimit()).isEqualTo(50);
+        assertThat(rcsThreadQueryParameters.getSortingProperty()).isEqualTo(SORT_BY_TIMESTAMP);
+        assertThat(rcsThreadQueryParameters.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/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