Merge "Remove TODO which was already completed."
diff --git a/api/current.txt b/api/current.txt
index 2a26368..23cf2a3 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5480,7 +5480,7 @@
     method public int describeContents();
     method public boolean getAutoExpandBubble();
     method @Nullable public android.app.PendingIntent getDeleteIntent();
-    method public int getDesiredHeight();
+    method @Dimension(unit=android.annotation.Dimension.DP) public int getDesiredHeight();
     method @DimenRes public int getDesiredHeightResId();
     method @NonNull public android.graphics.drawable.Icon getIcon();
     method @NonNull public android.app.PendingIntent getIntent();
@@ -5494,7 +5494,7 @@
     method @NonNull public android.app.Notification.BubbleMetadata build();
     method @NonNull public android.app.Notification.BubbleMetadata.Builder setAutoExpandBubble(boolean);
     method @NonNull public android.app.Notification.BubbleMetadata.Builder setDeleteIntent(@Nullable android.app.PendingIntent);
-    method @NonNull public android.app.Notification.BubbleMetadata.Builder setDesiredHeight(int);
+    method @NonNull public android.app.Notification.BubbleMetadata.Builder setDesiredHeight(@Dimension(unit=android.annotation.Dimension.DP) int);
     method @NonNull public android.app.Notification.BubbleMetadata.Builder setDesiredHeightResId(@DimenRes int);
     method @NonNull public android.app.Notification.BubbleMetadata.Builder setIcon(@NonNull android.graphics.drawable.Icon);
     method @NonNull public android.app.Notification.BubbleMetadata.Builder setIntent(@NonNull android.app.PendingIntent);
@@ -11534,107 +11534,107 @@
 
   public abstract class PackageManager {
     ctor public PackageManager();
-    method @Deprecated public abstract void addPackageToPreferred(String);
-    method public abstract boolean addPermission(android.content.pm.PermissionInfo);
-    method public abstract boolean addPermissionAsync(android.content.pm.PermissionInfo);
-    method @Deprecated public abstract void addPreferredActivity(android.content.IntentFilter, int, android.content.ComponentName[], android.content.ComponentName);
+    method @Deprecated public abstract void addPackageToPreferred(@NonNull String);
+    method public abstract boolean addPermission(@NonNull android.content.pm.PermissionInfo);
+    method public abstract boolean addPermissionAsync(@NonNull android.content.pm.PermissionInfo);
+    method @Deprecated public abstract void addPreferredActivity(@NonNull android.content.IntentFilter, int, @Nullable android.content.ComponentName[], @NonNull android.content.ComponentName);
     method public abstract boolean canRequestPackageInstalls();
-    method public abstract String[] canonicalToCurrentPackageNames(String[]);
-    method @CheckResult public abstract int checkPermission(String, String);
-    method @CheckResult public abstract int checkSignatures(String, String);
+    method public abstract String[] canonicalToCurrentPackageNames(@NonNull String[]);
+    method @CheckResult public abstract int checkPermission(@NonNull String, @NonNull String);
+    method @CheckResult public abstract int checkSignatures(@NonNull String, @NonNull String);
     method @CheckResult public abstract int checkSignatures(int, int);
     method public abstract void clearInstantAppCookie();
-    method @Deprecated public abstract void clearPackagePreferredActivities(String);
-    method public abstract String[] currentToCanonicalPackageNames(String[]);
+    method @Deprecated public abstract void clearPackagePreferredActivities(@NonNull String);
+    method public abstract String[] currentToCanonicalPackageNames(@NonNull String[]);
     method public abstract void extendVerificationTimeout(int, int, long);
-    method public abstract android.graphics.drawable.Drawable getActivityBanner(android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public abstract android.graphics.drawable.Drawable getActivityBanner(android.content.Intent) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public abstract android.graphics.drawable.Drawable getActivityIcon(android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public abstract android.graphics.drawable.Drawable getActivityIcon(android.content.Intent) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public abstract android.content.pm.ActivityInfo getActivityInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public abstract android.graphics.drawable.Drawable getActivityLogo(android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public abstract android.graphics.drawable.Drawable getActivityLogo(android.content.Intent) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public abstract java.util.List<android.content.pm.PermissionGroupInfo> getAllPermissionGroups(int);
-    method public abstract android.graphics.drawable.Drawable getApplicationBanner(android.content.pm.ApplicationInfo);
-    method public abstract android.graphics.drawable.Drawable getApplicationBanner(String) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @Nullable public abstract android.graphics.drawable.Drawable getActivityBanner(@NonNull android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @Nullable public abstract android.graphics.drawable.Drawable getActivityBanner(@NonNull android.content.Intent) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @NonNull public abstract android.graphics.drawable.Drawable getActivityIcon(@NonNull android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @NonNull public abstract android.graphics.drawable.Drawable getActivityIcon(@NonNull android.content.Intent) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @NonNull public abstract android.content.pm.ActivityInfo getActivityInfo(@NonNull android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @Nullable public abstract android.graphics.drawable.Drawable getActivityLogo(@NonNull android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @Nullable public abstract android.graphics.drawable.Drawable getActivityLogo(@NonNull android.content.Intent) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @NonNull public abstract java.util.List<android.content.pm.PermissionGroupInfo> getAllPermissionGroups(int);
+    method @Nullable public abstract android.graphics.drawable.Drawable getApplicationBanner(@NonNull android.content.pm.ApplicationInfo);
+    method @Nullable public abstract android.graphics.drawable.Drawable getApplicationBanner(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract int getApplicationEnabledSetting(@NonNull String);
-    method public abstract android.graphics.drawable.Drawable getApplicationIcon(android.content.pm.ApplicationInfo);
-    method public abstract android.graphics.drawable.Drawable getApplicationIcon(String) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public abstract android.content.pm.ApplicationInfo getApplicationInfo(String, int) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public abstract CharSequence getApplicationLabel(android.content.pm.ApplicationInfo);
-    method public abstract android.graphics.drawable.Drawable getApplicationLogo(android.content.pm.ApplicationInfo);
-    method public abstract android.graphics.drawable.Drawable getApplicationLogo(String) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @NonNull public abstract android.graphics.drawable.Drawable getApplicationIcon(@NonNull android.content.pm.ApplicationInfo);
+    method @NonNull public abstract android.graphics.drawable.Drawable getApplicationIcon(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @NonNull public abstract android.content.pm.ApplicationInfo getApplicationInfo(@NonNull String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @NonNull public abstract CharSequence getApplicationLabel(@NonNull android.content.pm.ApplicationInfo);
+    method @Nullable public abstract android.graphics.drawable.Drawable getApplicationLogo(@NonNull android.content.pm.ApplicationInfo);
+    method @Nullable public abstract android.graphics.drawable.Drawable getApplicationLogo(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
     method @Nullable public abstract android.content.pm.ChangedPackages getChangedPackages(@IntRange(from=0) int);
     method public abstract int getComponentEnabledSetting(@NonNull android.content.ComponentName);
-    method public abstract android.graphics.drawable.Drawable getDefaultActivityIcon();
-    method public abstract android.graphics.drawable.Drawable getDrawable(String, @DrawableRes int, android.content.pm.ApplicationInfo);
-    method public abstract java.util.List<android.content.pm.ApplicationInfo> getInstalledApplications(int);
+    method @NonNull public abstract android.graphics.drawable.Drawable getDefaultActivityIcon();
+    method @Nullable public abstract android.graphics.drawable.Drawable getDrawable(@NonNull String, @DrawableRes int, @Nullable android.content.pm.ApplicationInfo);
+    method @NonNull public abstract java.util.List<android.content.pm.ApplicationInfo> getInstalledApplications(int);
     method @NonNull public java.util.List<android.content.pm.ModuleInfo> getInstalledModules(int);
-    method public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int);
-    method @Nullable public abstract String getInstallerPackageName(String);
+    method @NonNull public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int);
+    method @Nullable public abstract String getInstallerPackageName(@NonNull String);
     method @NonNull public abstract byte[] getInstantAppCookie();
     method public abstract int getInstantAppCookieMaxBytes();
-    method public abstract android.content.pm.InstrumentationInfo getInstrumentationInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @NonNull public abstract android.content.pm.InstrumentationInfo getInstrumentationInfo(@NonNull android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method @Nullable public abstract android.content.Intent getLaunchIntentForPackage(@NonNull String);
     method @Nullable public abstract android.content.Intent getLeanbackLaunchIntentForPackage(@NonNull String);
-    method public android.content.pm.ModuleInfo getModuleInfo(String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @NonNull public android.content.pm.ModuleInfo getModuleInfo(@NonNull String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method @Nullable public abstract String getNameForUid(int);
-    method public android.content.pm.PackageInfo getPackageArchiveInfo(String, int);
+    method @Nullable public android.content.pm.PackageInfo getPackageArchiveInfo(@NonNull String, int);
     method public abstract int[] getPackageGids(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public abstract int[] getPackageGids(String, int) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public abstract android.content.pm.PackageInfo getPackageInfo(String, int) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public abstract android.content.pm.PackageInfo getPackageInfo(android.content.pm.VersionedPackage, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public abstract int[] getPackageGids(@NonNull String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public abstract android.content.pm.PackageInfo getPackageInfo(@NonNull String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public abstract android.content.pm.PackageInfo getPackageInfo(@NonNull android.content.pm.VersionedPackage, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method @NonNull public abstract android.content.pm.PackageInstaller getPackageInstaller();
-    method public abstract int getPackageUid(String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public abstract int getPackageUid(@NonNull String, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method @Nullable public abstract String[] getPackagesForUid(int);
-    method public abstract java.util.List<android.content.pm.PackageInfo> getPackagesHoldingPermissions(String[], int);
-    method public abstract android.content.pm.PermissionGroupInfo getPermissionGroupInfo(String, int) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public abstract android.content.pm.PermissionInfo getPermissionInfo(String, int) throws android.content.pm.PackageManager.NameNotFoundException;
-    method @Deprecated public abstract int getPreferredActivities(@NonNull java.util.List<android.content.IntentFilter>, @NonNull java.util.List<android.content.ComponentName>, String);
-    method @Deprecated public abstract java.util.List<android.content.pm.PackageInfo> getPreferredPackages(int);
-    method public abstract android.content.pm.ProviderInfo getProviderInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public abstract android.content.pm.ActivityInfo getReceiverInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public abstract android.content.res.Resources getResourcesForActivity(android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public abstract android.content.res.Resources getResourcesForApplication(android.content.pm.ApplicationInfo) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public abstract android.content.res.Resources getResourcesForApplication(String) throws android.content.pm.PackageManager.NameNotFoundException;
-    method public abstract android.content.pm.ServiceInfo getServiceInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @NonNull public abstract java.util.List<android.content.pm.PackageInfo> getPackagesHoldingPermissions(@NonNull String[], int);
+    method @NonNull public abstract android.content.pm.PermissionGroupInfo getPermissionGroupInfo(@NonNull String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public abstract android.content.pm.PermissionInfo getPermissionInfo(@NonNull String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @Deprecated public abstract int getPreferredActivities(@NonNull java.util.List<android.content.IntentFilter>, @NonNull java.util.List<android.content.ComponentName>, @Nullable String);
+    method @Deprecated @NonNull public abstract java.util.List<android.content.pm.PackageInfo> getPreferredPackages(int);
+    method @NonNull public abstract android.content.pm.ProviderInfo getProviderInfo(@NonNull android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @NonNull public abstract android.content.pm.ActivityInfo getReceiverInfo(@NonNull android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @NonNull public abstract android.content.res.Resources getResourcesForActivity(@NonNull android.content.ComponentName) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @NonNull public abstract android.content.res.Resources getResourcesForApplication(@NonNull android.content.pm.ApplicationInfo) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @NonNull public abstract android.content.res.Resources getResourcesForApplication(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @NonNull public abstract android.content.pm.ServiceInfo getServiceInfo(@NonNull android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method @NonNull public abstract java.util.List<android.content.pm.SharedLibraryInfo> getSharedLibraries(int);
     method @Nullable public android.os.Bundle getSuspendedPackageAppExtras();
     method public boolean getSyntheticAppDetailsActivityEnabled(@NonNull String);
-    method public abstract android.content.pm.FeatureInfo[] getSystemAvailableFeatures();
-    method public abstract String[] getSystemSharedLibraryNames();
-    method public abstract CharSequence getText(String, @StringRes int, android.content.pm.ApplicationInfo);
-    method public abstract android.graphics.drawable.Drawable getUserBadgedDrawableForDensity(android.graphics.drawable.Drawable, android.os.UserHandle, android.graphics.Rect, int);
-    method public abstract android.graphics.drawable.Drawable getUserBadgedIcon(android.graphics.drawable.Drawable, android.os.UserHandle);
-    method public abstract CharSequence getUserBadgedLabel(CharSequence, android.os.UserHandle);
-    method public abstract android.content.res.XmlResourceParser getXml(String, @XmlRes int, android.content.pm.ApplicationInfo);
-    method public boolean hasSigningCertificate(String, byte[], int);
-    method public boolean hasSigningCertificate(int, byte[], int);
-    method public abstract boolean hasSystemFeature(String);
-    method public abstract boolean hasSystemFeature(String, int);
+    method @NonNull public abstract android.content.pm.FeatureInfo[] getSystemAvailableFeatures();
+    method @Nullable public abstract String[] getSystemSharedLibraryNames();
+    method @Nullable public abstract CharSequence getText(@NonNull String, @StringRes int, @Nullable android.content.pm.ApplicationInfo);
+    method @NonNull public abstract android.graphics.drawable.Drawable getUserBadgedDrawableForDensity(@NonNull android.graphics.drawable.Drawable, @NonNull android.os.UserHandle, @Nullable android.graphics.Rect, int);
+    method @NonNull public abstract android.graphics.drawable.Drawable getUserBadgedIcon(@NonNull android.graphics.drawable.Drawable, @NonNull android.os.UserHandle);
+    method @NonNull public abstract CharSequence getUserBadgedLabel(@NonNull CharSequence, @NonNull android.os.UserHandle);
+    method @Nullable public abstract android.content.res.XmlResourceParser getXml(@NonNull String, @XmlRes int, @Nullable android.content.pm.ApplicationInfo);
+    method public boolean hasSigningCertificate(@NonNull String, @NonNull byte[], int);
+    method public boolean hasSigningCertificate(int, @NonNull byte[], int);
+    method public abstract boolean hasSystemFeature(@NonNull String);
+    method public abstract boolean hasSystemFeature(@NonNull String, int);
     method public abstract boolean isInstantApp();
-    method public abstract boolean isInstantApp(String);
-    method public boolean isPackageSuspended(String) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public abstract boolean isInstantApp(@NonNull String);
+    method public boolean isPackageSuspended(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
     method public boolean isPackageSuspended();
     method @CheckResult public abstract boolean isPermissionRevokedByPolicy(@NonNull String, @NonNull String);
     method public abstract boolean isSafeMode();
-    method public abstract java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(android.content.Intent, int);
-    method public abstract java.util.List<android.content.pm.ProviderInfo> queryContentProviders(String, int, int);
-    method public abstract java.util.List<android.content.pm.InstrumentationInfo> queryInstrumentation(String, int);
-    method public abstract java.util.List<android.content.pm.ResolveInfo> queryIntentActivities(android.content.Intent, int);
-    method public abstract java.util.List<android.content.pm.ResolveInfo> queryIntentActivityOptions(@Nullable android.content.ComponentName, @Nullable android.content.Intent[], android.content.Intent, int);
-    method public abstract java.util.List<android.content.pm.ResolveInfo> queryIntentContentProviders(android.content.Intent, int);
-    method public abstract java.util.List<android.content.pm.ResolveInfo> queryIntentServices(android.content.Intent, int);
-    method public abstract java.util.List<android.content.pm.PermissionInfo> queryPermissionsByGroup(String, int) throws android.content.pm.PackageManager.NameNotFoundException;
-    method @Deprecated public abstract void removePackageFromPreferred(String);
-    method public abstract void removePermission(String);
-    method public abstract android.content.pm.ResolveInfo resolveActivity(android.content.Intent, int);
-    method public abstract android.content.pm.ProviderInfo resolveContentProvider(String, int);
-    method public abstract android.content.pm.ResolveInfo resolveService(android.content.Intent, int);
+    method @NonNull public abstract java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceivers(@NonNull android.content.Intent, int);
+    method @NonNull public abstract java.util.List<android.content.pm.ProviderInfo> queryContentProviders(@Nullable String, int, int);
+    method @NonNull public abstract java.util.List<android.content.pm.InstrumentationInfo> queryInstrumentation(@NonNull String, int);
+    method @Nullable public abstract java.util.List<android.content.pm.ResolveInfo> queryIntentActivities(@NonNull android.content.Intent, int);
+    method @NonNull public abstract java.util.List<android.content.pm.ResolveInfo> queryIntentActivityOptions(@Nullable android.content.ComponentName, @Nullable android.content.Intent[], @NonNull android.content.Intent, int);
+    method @NonNull public abstract java.util.List<android.content.pm.ResolveInfo> queryIntentContentProviders(@NonNull android.content.Intent, int);
+    method @NonNull public abstract java.util.List<android.content.pm.ResolveInfo> queryIntentServices(@NonNull android.content.Intent, int);
+    method @NonNull public abstract java.util.List<android.content.pm.PermissionInfo> queryPermissionsByGroup(@NonNull String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @Deprecated public abstract void removePackageFromPreferred(@NonNull String);
+    method public abstract void removePermission(@NonNull String);
+    method @Nullable public abstract android.content.pm.ResolveInfo resolveActivity(@NonNull android.content.Intent, int);
+    method @Nullable public abstract android.content.pm.ProviderInfo resolveContentProvider(@NonNull String, int);
+    method @Nullable public abstract android.content.pm.ResolveInfo resolveService(@NonNull android.content.Intent, int);
     method public abstract void setApplicationCategoryHint(@NonNull String, int);
     method @RequiresPermission(value=android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE, conditional=true) public abstract void setApplicationEnabledSetting(@NonNull String, int, int);
     method @RequiresPermission(value=android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE, conditional=true) public abstract void setComponentEnabledSetting(@NonNull android.content.ComponentName, int, int);
-    method public abstract void setInstallerPackageName(String, String);
+    method public abstract void setInstallerPackageName(@NonNull String, @Nullable String);
     method public abstract void updateInstantAppCookie(@Nullable byte[]);
     method public abstract void verifyPendingInstall(int, int);
     field public static final int CERT_INPUT_RAW_X509 = 0; // 0x0
@@ -14100,8 +14100,9 @@
   }
 
   public class ComposeShader extends android.graphics.Shader {
-    ctor public ComposeShader(@NonNull android.graphics.Shader, @NonNull android.graphics.Shader, @NonNull android.graphics.Xfermode);
-    ctor public ComposeShader(@NonNull android.graphics.Shader, @NonNull android.graphics.Shader, @NonNull android.graphics.PorterDuff.Mode);
+    ctor @Deprecated public ComposeShader(@NonNull android.graphics.Shader, @NonNull android.graphics.Shader, @NonNull android.graphics.Xfermode);
+    ctor @Deprecated public ComposeShader(@NonNull android.graphics.Shader, @NonNull android.graphics.Shader, @NonNull android.graphics.PorterDuff.Mode);
+    ctor public ComposeShader(@NonNull android.graphics.Shader, @NonNull android.graphics.Shader, @NonNull android.graphics.BlendMode);
   }
 
   public class CornerPathEffect extends android.graphics.PathEffect {
@@ -14795,37 +14796,37 @@
     field public float y;
   }
 
-  public class PorterDuff {
-    ctor public PorterDuff();
+  @Deprecated public class PorterDuff {
+    ctor @Deprecated public PorterDuff();
   }
 
-  public enum PorterDuff.Mode {
-    enum_constant public static final android.graphics.PorterDuff.Mode ADD;
-    enum_constant public static final android.graphics.PorterDuff.Mode CLEAR;
-    enum_constant public static final android.graphics.PorterDuff.Mode DARKEN;
-    enum_constant public static final android.graphics.PorterDuff.Mode DST;
-    enum_constant public static final android.graphics.PorterDuff.Mode DST_ATOP;
-    enum_constant public static final android.graphics.PorterDuff.Mode DST_IN;
-    enum_constant public static final android.graphics.PorterDuff.Mode DST_OUT;
-    enum_constant public static final android.graphics.PorterDuff.Mode DST_OVER;
-    enum_constant public static final android.graphics.PorterDuff.Mode LIGHTEN;
-    enum_constant public static final android.graphics.PorterDuff.Mode MULTIPLY;
-    enum_constant public static final android.graphics.PorterDuff.Mode OVERLAY;
-    enum_constant public static final android.graphics.PorterDuff.Mode SCREEN;
-    enum_constant public static final android.graphics.PorterDuff.Mode SRC;
-    enum_constant public static final android.graphics.PorterDuff.Mode SRC_ATOP;
-    enum_constant public static final android.graphics.PorterDuff.Mode SRC_IN;
-    enum_constant public static final android.graphics.PorterDuff.Mode SRC_OUT;
-    enum_constant public static final android.graphics.PorterDuff.Mode SRC_OVER;
-    enum_constant public static final android.graphics.PorterDuff.Mode XOR;
+  @Deprecated public enum PorterDuff.Mode {
+    enum_constant @Deprecated public static final android.graphics.PorterDuff.Mode ADD;
+    enum_constant @Deprecated public static final android.graphics.PorterDuff.Mode CLEAR;
+    enum_constant @Deprecated public static final android.graphics.PorterDuff.Mode DARKEN;
+    enum_constant @Deprecated public static final android.graphics.PorterDuff.Mode DST;
+    enum_constant @Deprecated public static final android.graphics.PorterDuff.Mode DST_ATOP;
+    enum_constant @Deprecated public static final android.graphics.PorterDuff.Mode DST_IN;
+    enum_constant @Deprecated public static final android.graphics.PorterDuff.Mode DST_OUT;
+    enum_constant @Deprecated public static final android.graphics.PorterDuff.Mode DST_OVER;
+    enum_constant @Deprecated public static final android.graphics.PorterDuff.Mode LIGHTEN;
+    enum_constant @Deprecated public static final android.graphics.PorterDuff.Mode MULTIPLY;
+    enum_constant @Deprecated public static final android.graphics.PorterDuff.Mode OVERLAY;
+    enum_constant @Deprecated public static final android.graphics.PorterDuff.Mode SCREEN;
+    enum_constant @Deprecated public static final android.graphics.PorterDuff.Mode SRC;
+    enum_constant @Deprecated public static final android.graphics.PorterDuff.Mode SRC_ATOP;
+    enum_constant @Deprecated public static final android.graphics.PorterDuff.Mode SRC_IN;
+    enum_constant @Deprecated public static final android.graphics.PorterDuff.Mode SRC_OUT;
+    enum_constant @Deprecated public static final android.graphics.PorterDuff.Mode SRC_OVER;
+    enum_constant @Deprecated public static final android.graphics.PorterDuff.Mode XOR;
   }
 
   @Deprecated public class PorterDuffColorFilter extends android.graphics.ColorFilter {
     ctor @Deprecated public PorterDuffColorFilter(@ColorInt int, @NonNull android.graphics.PorterDuff.Mode);
   }
 
-  public class PorterDuffXfermode extends android.graphics.Xfermode {
-    ctor public PorterDuffXfermode(android.graphics.PorterDuff.Mode);
+  @Deprecated public class PorterDuffXfermode extends android.graphics.Xfermode {
+    ctor @Deprecated public PorterDuffXfermode(android.graphics.PorterDuff.Mode);
   }
 
   public interface PostProcessor {
@@ -15387,7 +15388,8 @@
     method public boolean setState(@NonNull int[]);
     method public void setTint(@ColorInt int);
     method public void setTintList(@Nullable android.content.res.ColorStateList);
-    method public void setTintMode(@NonNull android.graphics.PorterDuff.Mode);
+    method @Deprecated public void setTintMode(@NonNull android.graphics.PorterDuff.Mode);
+    method public void setTintMode(@NonNull android.graphics.BlendMode);
     method public boolean setVisible(boolean, boolean);
     method public void unscheduleSelf(@NonNull Runnable);
   }
@@ -15545,7 +15547,8 @@
     method public void loadDrawableAsync(android.content.Context, android.graphics.drawable.Icon.OnDrawableLoadedListener, android.os.Handler);
     method public android.graphics.drawable.Icon setTint(@ColorInt int);
     method public android.graphics.drawable.Icon setTintList(android.content.res.ColorStateList);
-    method public android.graphics.drawable.Icon setTintMode(android.graphics.PorterDuff.Mode);
+    method @Deprecated @NonNull public android.graphics.drawable.Icon setTintMode(@NonNull android.graphics.PorterDuff.Mode);
+    method @NonNull public android.graphics.drawable.Icon setTintMode(@NonNull android.graphics.BlendMode);
     method public void writeToParcel(android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.graphics.drawable.Icon> CREATOR;
     field public static final int TYPE_ADAPTIVE_BITMAP = 5; // 0x5
@@ -23041,6 +23044,9 @@
     method public int getUsage();
     method public int getVolumeControlStream();
     method public void writeToParcel(android.os.Parcel, int);
+    field public static final int ALLOW_CAPTURE_BY_ALL = 1; // 0x1
+    field public static final int ALLOW_CAPTURE_BY_NONE = 3; // 0x3
+    field public static final int ALLOW_CAPTURE_BY_SYSTEM = 2; // 0x2
     field public static final int CONTENT_TYPE_MOVIE = 3; // 0x3
     field public static final int CONTENT_TYPE_MUSIC = 2; // 0x2
     field public static final int CONTENT_TYPE_SONIFICATION = 4; // 0x4
@@ -23072,7 +23078,7 @@
     ctor public AudioAttributes.Builder();
     ctor public AudioAttributes.Builder(android.media.AudioAttributes);
     method public android.media.AudioAttributes build();
-    method @NonNull public android.media.AudioAttributes.Builder setAllowCapture(boolean);
+    method @NonNull public android.media.AudioAttributes.Builder setAllowedCapturePolicy(int);
     method public android.media.AudioAttributes.Builder setContentType(int);
     method public android.media.AudioAttributes.Builder setFlags(int);
     method public android.media.AudioAttributes.Builder setLegacyStreamType(int);
@@ -23273,6 +23279,7 @@
     method @Deprecated public boolean registerRemoteController(android.media.RemoteController);
     method @Deprecated public int requestAudioFocus(android.media.AudioManager.OnAudioFocusChangeListener, int, int);
     method public int requestAudioFocus(@NonNull android.media.AudioFocusRequest);
+    method public void setAllowedCapturePolicy(int);
     method @Deprecated public void setBluetoothA2dpOn(boolean);
     method public void setBluetoothScoOn(boolean);
     method public void setMicrophoneMute(boolean);
@@ -25069,7 +25076,7 @@
     field public static final String KEY_LANGUAGE = "language";
     field public static final String KEY_LATENCY = "latency";
     field public static final String KEY_LEVEL = "level";
-    field public static final String KEY_MAX_BFRAMES = "max-bframes";
+    field public static final String KEY_MAX_B_FRAMES = "max-bframes";
     field public static final String KEY_MAX_FPS_TO_ENCODER = "max-fps-to-encoder";
     field public static final String KEY_MAX_HEIGHT = "max-height";
     field public static final String KEY_MAX_INPUT_SIZE = "max-input-size";
@@ -28749,6 +28756,7 @@
     method @NonNull public static android.net.DnsResolver getInstance();
     method public <T> void query(@Nullable android.net.Network, @NonNull byte[], int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.AnswerCallback<T>);
     method public <T> void query(@Nullable android.net.Network, @NonNull String, int, int, int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.AnswerCallback<T>);
+    method public void query(@Nullable android.net.Network, @NonNull String, int, @NonNull java.util.concurrent.Executor, @Nullable android.os.CancellationSignal, @NonNull android.net.DnsResolver.InetAddressAnswerCallback);
     field public static final int CLASS_IN = 1; // 0x1
     field public static final int FLAG_EMPTY = 0; // 0x0
     field public static final int FLAG_NO_CACHE_LOOKUP = 4; // 0x4
@@ -38851,6 +38859,7 @@
     field public static final String ACTION_APPLICATION_DETAILS_SETTINGS = "android.settings.APPLICATION_DETAILS_SETTINGS";
     field public static final String ACTION_APPLICATION_DEVELOPMENT_SETTINGS = "android.settings.APPLICATION_DEVELOPMENT_SETTINGS";
     field public static final String ACTION_APPLICATION_SETTINGS = "android.settings.APPLICATION_SETTINGS";
+    field public static final String ACTION_APP_NOTIFICATION_BUBBLE_SETTINGS = "android.settings.APP_NOTIFICATION_BUBBLE_SETTINGS";
     field public static final String ACTION_APP_NOTIFICATION_SETTINGS = "android.settings.APP_NOTIFICATION_SETTINGS";
     field public static final String ACTION_APP_SEARCH_SETTINGS = "android.settings.APP_SEARCH_SETTINGS";
     field public static final String ACTION_APP_USAGE_SETTINGS = "android.settings.action.APP_USAGE_SETTINGS";
@@ -49718,8 +49727,9 @@
     method public default CharSequence getContentDescription();
     method public int getGroupId();
     method public android.graphics.drawable.Drawable getIcon();
+    method @Nullable public default android.graphics.BlendMode getIconTintBlendMode();
     method @Nullable public default android.content.res.ColorStateList getIconTintList();
-    method @Nullable public default android.graphics.PorterDuff.Mode getIconTintMode();
+    method @Deprecated @Nullable public default android.graphics.PorterDuff.Mode getIconTintMode();
     method public android.content.Intent getIntent();
     method public int getItemId();
     method public android.view.ContextMenu.ContextMenuInfo getMenuInfo();
@@ -49748,7 +49758,8 @@
     method public android.view.MenuItem setIcon(android.graphics.drawable.Drawable);
     method public android.view.MenuItem setIcon(@DrawableRes int);
     method public default android.view.MenuItem setIconTintList(@Nullable android.content.res.ColorStateList);
-    method public default android.view.MenuItem setIconTintMode(@Nullable android.graphics.PorterDuff.Mode);
+    method @Deprecated @NonNull public default android.view.MenuItem setIconTintMode(@Nullable android.graphics.PorterDuff.Mode);
+    method @NonNull public default android.view.MenuItem setIconTintMode(@Nullable android.graphics.BlendMode);
     method public android.view.MenuItem setIntent(android.content.Intent);
     method public android.view.MenuItem setNumericShortcut(char);
     method public default android.view.MenuItem setNumericShortcut(char, int);
@@ -50401,8 +50412,9 @@
     method public int getAutofillType();
     method @Nullable public android.view.autofill.AutofillValue getAutofillValue();
     method public android.graphics.drawable.Drawable getBackground();
+    method @Nullable public android.graphics.BlendMode getBackgroundBlendMode();
     method @Nullable public android.content.res.ColorStateList getBackgroundTintList();
-    method @Nullable public android.graphics.PorterDuff.Mode getBackgroundTintMode();
+    method @Deprecated @Nullable public android.graphics.PorterDuff.Mode getBackgroundTintMode();
     method @android.view.ViewDebug.ExportedProperty(category="layout") public int getBaseline();
     method @android.view.ViewDebug.CapturedViewProperty public final int getBottom();
     method protected float getBottomFadingEdgeStrength();
@@ -50433,9 +50445,10 @@
     method public java.util.ArrayList<android.view.View> getFocusables(int);
     method public void getFocusedRect(android.graphics.Rect);
     method public android.graphics.drawable.Drawable getForeground();
+    method @Nullable public android.graphics.BlendMode getForegroundBlendMode();
     method public int getForegroundGravity();
     method @Nullable public android.content.res.ColorStateList getForegroundTintList();
-    method @Nullable public android.graphics.PorterDuff.Mode getForegroundTintMode();
+    method @Deprecated @Nullable public android.graphics.PorterDuff.Mode getForegroundTintMode();
     method public boolean getGlobalVisibleRect(android.graphics.Rect, android.graphics.Point);
     method public final boolean getGlobalVisibleRect(android.graphics.Rect);
     method public android.os.Handler getHandler();
@@ -50751,7 +50764,8 @@
     method @Deprecated public void setBackgroundDrawable(android.graphics.drawable.Drawable);
     method public void setBackgroundResource(@DrawableRes int);
     method public void setBackgroundTintList(@Nullable android.content.res.ColorStateList);
-    method public void setBackgroundTintMode(@Nullable android.graphics.PorterDuff.Mode);
+    method @Deprecated public void setBackgroundTintMode(@Nullable android.graphics.PorterDuff.Mode);
+    method public void setBackgroundTintMode(@Nullable android.graphics.BlendMode);
     method public final void setBottom(int);
     method public void setCameraDistance(float);
     method public void setClickable(boolean);
@@ -50778,7 +50792,8 @@
     method public void setForeground(android.graphics.drawable.Drawable);
     method public void setForegroundGravity(int);
     method public void setForegroundTintList(@Nullable android.content.res.ColorStateList);
-    method public void setForegroundTintMode(@Nullable android.graphics.PorterDuff.Mode);
+    method @Deprecated public void setForegroundTintMode(@Nullable android.graphics.PorterDuff.Mode);
+    method public void setForegroundTintMode(@Nullable android.graphics.BlendMode);
     method public void setHapticFeedbackEnabled(boolean);
     method public void setHasTransientState(boolean);
     method public void setHorizontalFadingEdgeEnabled(boolean);
@@ -52298,7 +52313,7 @@
     method public java.util.List<android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction> getActionList();
     method @Deprecated public int getActions();
     method public java.util.List<java.lang.String> getAvailableExtraData();
-    method public void getBoundsInParent(android.graphics.Rect);
+    method @Deprecated public void getBoundsInParent(android.graphics.Rect);
     method public void getBoundsInScreen(android.graphics.Rect);
     method public android.view.accessibility.AccessibilityNodeInfo getChild(int);
     method public int getChildCount();
@@ -52367,7 +52382,7 @@
     method public boolean removeChild(android.view.View, int);
     method public void setAccessibilityFocused(boolean);
     method public void setAvailableExtraData(java.util.List<java.lang.String>);
-    method public void setBoundsInParent(android.graphics.Rect);
+    method @Deprecated public void setBoundsInParent(android.graphics.Rect);
     method public void setBoundsInScreen(android.graphics.Rect);
     method public void setCanOpenPopup(boolean);
     method public void setCheckable(boolean);
diff --git a/api/system-current.txt b/api/system-current.txt
index d2c5844..8ee1e0a 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -49,6 +49,7 @@
     field @Deprecated public static final String BROADCAST_NETWORK_PRIVILEGED = "android.permission.BROADCAST_NETWORK_PRIVILEGED";
     field public static final String CAMERA_DISABLE_TRANSMIT_LED = "android.permission.CAMERA_DISABLE_TRANSMIT_LED";
     field public static final String CAPTURE_AUDIO_HOTWORD = "android.permission.CAPTURE_AUDIO_HOTWORD";
+    field public static final String CAPTURE_MEDIA_OUTPUT = "android.permission.CAPTURE_MEDIA_OUTPUT";
     field public static final String CAPTURE_TV_INPUT = "android.permission.CAPTURE_TV_INPUT";
     field public static final String CHANGE_APP_IDLE_STATE = "android.permission.CHANGE_APP_IDLE_STATE";
     field public static final String CHANGE_DEVICE_IDLE_TEMP_WHITELIST = "android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST";
@@ -564,7 +565,7 @@
     method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public byte[] getStatsMetadata() throws android.app.StatsManager.StatsUnavailableException;
     method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public void removeConfig(long) throws android.app.StatsManager.StatsUnavailableException;
     method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public boolean removeConfiguration(long);
-    method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public long[] setActiveConfigsChangedOperation(@Nullable android.app.PendingIntent) throws android.app.StatsManager.StatsUnavailableException;
+    method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) @NonNull public long[] setActiveConfigsChangedOperation(@Nullable android.app.PendingIntent) throws android.app.StatsManager.StatsUnavailableException;
     method @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public void setBroadcastSubscriber(android.app.PendingIntent, long, long) throws android.app.StatsManager.StatsUnavailableException;
     method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public boolean setBroadcastSubscriber(long, long, android.app.PendingIntent);
     method @Deprecated @RequiresPermission(allOf={android.Manifest.permission.DUMP, android.Manifest.permission.PACKAGE_USAGE_STATS}) public boolean setDataFetchOperation(long, android.app.PendingIntent);
@@ -1592,46 +1593,46 @@
   }
 
   public abstract class PackageManager {
-    method @RequiresPermission("android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS") public abstract void addOnPermissionsChangeListener(android.content.pm.PackageManager.OnPermissionsChangedListener);
+    method @RequiresPermission("android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS") public abstract void addOnPermissionsChangeListener(@NonNull android.content.pm.PackageManager.OnPermissionsChangedListener);
     method public abstract boolean arePermissionsIndividuallyControlled();
-    method public abstract java.util.List<android.content.IntentFilter> getAllIntentFilters(String);
+    method @NonNull public abstract java.util.List<android.content.IntentFilter> getAllIntentFilters(@NonNull String);
     method @NonNull @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public android.content.pm.ApplicationInfo getApplicationInfoAsUser(@NonNull String, int, @NonNull android.os.UserHandle) throws android.content.pm.PackageManager.NameNotFoundException;
     method @NonNull public android.content.pm.dex.ArtManager getArtManager();
     method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_SHARED_LIBRARIES) public java.util.List<android.content.pm.SharedLibraryInfo> getDeclaredSharedLibraries(@NonNull String, int);
-    method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public abstract String getDefaultBrowserPackageNameAsUser(int);
+    method @Nullable @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public abstract String getDefaultBrowserPackageNameAsUser(int);
     method @Nullable @RequiresPermission(android.Manifest.permission.SET_HARMFUL_APP_WARNINGS) public CharSequence getHarmfulAppWarning(@NonNull String);
     method @Nullable public String getIncidentReportApproverPackageName();
-    method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackagesAsUser(int, int);
+    method @NonNull @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackagesAsUser(int, int);
     method @Nullable @RequiresPermission(android.Manifest.permission.ACCESS_INSTANT_APPS) public abstract android.graphics.drawable.Drawable getInstantAppIcon(String);
-    method public abstract android.content.ComponentName getInstantAppInstallerComponent();
-    method public abstract android.content.ComponentName getInstantAppResolverSettingsComponent();
+    method @Nullable public abstract android.content.ComponentName getInstantAppInstallerComponent();
+    method @Nullable public abstract android.content.ComponentName getInstantAppResolverSettingsComponent();
     method @NonNull @RequiresPermission(android.Manifest.permission.ACCESS_INSTANT_APPS) public abstract java.util.List<android.content.pm.InstantAppInfo> getInstantApps();
-    method public abstract java.util.List<android.content.pm.IntentFilterVerificationInfo> getIntentFilterVerifications(String);
-    method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public abstract int getIntentVerificationStatusAsUser(String, int);
-    method @android.content.pm.PackageManager.PermissionFlags @RequiresPermission(anyOf={android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS, android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS, android.Manifest.permission.GET_RUNTIME_PERMISSIONS}) public abstract int getPermissionFlags(String, String, @NonNull android.os.UserHandle);
+    method @NonNull public abstract java.util.List<android.content.pm.IntentFilterVerificationInfo> getIntentFilterVerifications(@NonNull String);
+    method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public abstract int getIntentVerificationStatusAsUser(@NonNull String, int);
+    method @android.content.pm.PackageManager.PermissionFlags @RequiresPermission(anyOf={android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS, android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS, android.Manifest.permission.GET_RUNTIME_PERMISSIONS}) public abstract int getPermissionFlags(@NonNull String, @NonNull String, @NonNull android.os.UserHandle);
     method @NonNull @RequiresPermission(android.Manifest.permission.SUSPEND_APPS) public String[] getUnsuspendablePackages(@NonNull String[]);
     method @RequiresPermission(android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS) public abstract void grantRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle);
-    method @Deprecated public abstract int installExistingPackage(String) throws android.content.pm.PackageManager.NameNotFoundException;
-    method @Deprecated public abstract int installExistingPackage(String, int) throws android.content.pm.PackageManager.NameNotFoundException;
-    method @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceiversAsUser(android.content.Intent, int, android.os.UserHandle);
+    method @Deprecated public abstract int installExistingPackage(@NonNull String) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @Deprecated public abstract int installExistingPackage(@NonNull String, int) throws android.content.pm.PackageManager.NameNotFoundException;
+    method @NonNull @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public java.util.List<android.content.pm.ResolveInfo> queryBroadcastReceiversAsUser(@NonNull android.content.Intent, int, android.os.UserHandle);
     method @NonNull @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public java.util.List<android.content.pm.ResolveInfo> queryIntentActivitiesAsUser(@NonNull android.content.Intent, int, @NonNull android.os.UserHandle);
     method @NonNull @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public java.util.List<android.content.pm.ResolveInfo> queryIntentContentProvidersAsUser(@NonNull android.content.Intent, int, @NonNull android.os.UserHandle);
     method @NonNull @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS) public java.util.List<android.content.pm.ResolveInfo> queryIntentServicesAsUser(@NonNull android.content.Intent, int, @NonNull android.os.UserHandle);
-    method public abstract void registerDexModule(String, @Nullable android.content.pm.PackageManager.DexModuleRegisterCallback);
-    method @RequiresPermission("android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS") public abstract void removeOnPermissionsChangeListener(android.content.pm.PackageManager.OnPermissionsChangedListener);
+    method public abstract void registerDexModule(@NonNull String, @Nullable android.content.pm.PackageManager.DexModuleRegisterCallback);
+    method @RequiresPermission("android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS") public abstract void removeOnPermissionsChangeListener(@NonNull android.content.pm.PackageManager.OnPermissionsChangedListener);
     method @Deprecated public void replacePreferredActivity(@NonNull android.content.IntentFilter, int, @NonNull java.util.List<android.content.ComponentName>, @NonNull android.content.ComponentName);
     method @RequiresPermission(android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS) public abstract void revokeRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle);
     method public void sendDeviceCustomizationReadyBroadcast();
-    method @RequiresPermission(allOf={android.Manifest.permission.SET_PREFERRED_APPLICATIONS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public abstract boolean setDefaultBrowserPackageNameAsUser(String, int);
+    method @RequiresPermission(allOf={android.Manifest.permission.SET_PREFERRED_APPLICATIONS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public abstract boolean setDefaultBrowserPackageNameAsUser(@Nullable String, int);
     method @NonNull @RequiresPermission(android.Manifest.permission.SUSPEND_APPS) public String[] setDistractingPackageRestrictions(@NonNull String[], int);
     method @RequiresPermission(android.Manifest.permission.SET_HARMFUL_APP_WARNINGS) public void setHarmfulAppWarning(@NonNull String, @Nullable CharSequence);
     method @Deprecated @Nullable @RequiresPermission(android.Manifest.permission.SUSPEND_APPS) public String[] setPackagesSuspended(@Nullable String[], boolean, @Nullable android.os.PersistableBundle, @Nullable android.os.PersistableBundle, @Nullable String);
     method @Nullable @RequiresPermission(android.Manifest.permission.SUSPEND_APPS) public String[] setPackagesSuspended(@Nullable String[], boolean, @Nullable android.os.PersistableBundle, @Nullable android.os.PersistableBundle, @Nullable android.content.pm.SuspendDialogInfo);
     method @RequiresPermission(value=android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE, conditional=true) public void setSyntheticAppDetailsActivityEnabled(@NonNull String, boolean);
-    method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public abstract void setUpdateAvailable(String, boolean);
-    method @RequiresPermission(android.Manifest.permission.SET_PREFERRED_APPLICATIONS) public abstract boolean updateIntentVerificationStatusAsUser(String, int, int);
-    method @RequiresPermission(anyOf={android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS, android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS}) public abstract void updatePermissionFlags(String, String, @android.content.pm.PackageManager.PermissionFlags int, @android.content.pm.PackageManager.PermissionFlags int, @NonNull android.os.UserHandle);
-    method @RequiresPermission(android.Manifest.permission.INTENT_FILTER_VERIFICATION_AGENT) public abstract void verifyIntentFilter(int, int, java.util.List<java.lang.String>);
+    method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public abstract void setUpdateAvailable(@NonNull String, boolean);
+    method @RequiresPermission(android.Manifest.permission.SET_PREFERRED_APPLICATIONS) public abstract boolean updateIntentVerificationStatusAsUser(@NonNull String, int, int);
+    method @RequiresPermission(anyOf={android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS, android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS}) public abstract void updatePermissionFlags(@NonNull String, @NonNull String, @android.content.pm.PackageManager.PermissionFlags int, @android.content.pm.PackageManager.PermissionFlags int, @NonNull android.os.UserHandle);
+    method @RequiresPermission(android.Manifest.permission.INTENT_FILTER_VERIFICATION_AGENT) public abstract void verifyIntentFilter(int, int, @NonNull java.util.List<java.lang.String>);
     field public static final String ACTION_REQUEST_PERMISSIONS = "android.content.pm.action.REQUEST_PERMISSIONS";
     field public static final String EXTRA_REQUEST_PERMISSIONS_NAMES = "android.content.pm.extra.REQUEST_PERMISSIONS_NAMES";
     field public static final String EXTRA_REQUEST_PERMISSIONS_RESULTS = "android.content.pm.extra.REQUEST_PERMISSIONS_RESULTS";
@@ -3377,19 +3378,19 @@
 
   public class LocationManager {
     method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void flushGnssBatch();
+    method @Nullable public String getExtraLocationControllerPackage();
     method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public int getGnssBatchSize();
     method @Nullable public android.location.GnssCapabilities getGnssCapabilities();
-    method @Nullable public String getLocationControllerExtraPackage();
     method @RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION) public void injectGnssMeasurementCorrections(@NonNull android.location.GnssMeasurementCorrections);
-    method public boolean isLocationControllerExtraPackageEnabled();
+    method public boolean isExtraLocationControllerPackageEnabled();
     method public boolean isLocationEnabledForUser(@NonNull android.os.UserHandle);
     method public boolean isProviderEnabledForUser(@NonNull String, @NonNull android.os.UserHandle);
     method public boolean isProviderPackage(@NonNull String);
     method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public boolean registerGnssBatchedLocationCallback(long, boolean, @NonNull android.location.BatchedLocationCallback, @Nullable android.os.Handler);
     method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull android.location.LocationRequest, @NonNull android.location.LocationListener, @Nullable android.os.Looper);
     method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_COARSE_LOCATION, android.Manifest.permission.ACCESS_FINE_LOCATION}) public void requestLocationUpdates(@NonNull android.location.LocationRequest, @NonNull android.app.PendingIntent);
-    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void setLocationControllerExtraPackage(@NonNull String);
-    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void setLocationControllerExtraPackageEnabled(boolean);
+    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void setExtraLocationControllerPackage(@Nullable String);
+    method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void setExtraLocationControllerPackageEnabled(boolean);
     method @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public void setLocationEnabledForUser(boolean, @NonNull android.os.UserHandle);
     method @Deprecated @RequiresPermission(android.Manifest.permission.WRITE_SECURE_SETTINGS) public boolean setProviderEnabledForUser(@NonNull String, boolean, @NonNull android.os.UserHandle);
     method @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public boolean unregisterGnssBatchedLocationCallback(@NonNull android.location.BatchedLocationCallback);
@@ -3602,6 +3603,7 @@
     ctor public AudioMixingRule.Builder();
     method public android.media.audiopolicy.AudioMixingRule.Builder addMixRule(int, Object) throws java.lang.IllegalArgumentException;
     method public android.media.audiopolicy.AudioMixingRule.Builder addRule(android.media.AudioAttributes, int) throws java.lang.IllegalArgumentException;
+    method @NonNull public android.media.audiopolicy.AudioMixingRule.Builder allowPrivilegedPlaybackCapture(boolean);
     method public android.media.audiopolicy.AudioMixingRule build();
     method public android.media.audiopolicy.AudioMixingRule.Builder excludeMixRule(int, Object) throws java.lang.IllegalArgumentException;
     method public android.media.audiopolicy.AudioMixingRule.Builder excludeRule(android.media.AudioAttributes, int) throws java.lang.IllegalArgumentException;
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 9780d43..162f212 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -67,6 +67,8 @@
     method @Deprecated public boolean addGpsNavigationMessageListener(android.location.GpsNavigationMessageEvent.Listener);
     method @Deprecated public void removeGpsMeasurementListener(android.location.GpsMeasurementsEvent.Listener);
     method @Deprecated public void removeGpsNavigationMessageListener(android.location.GpsNavigationMessageEvent.Listener);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void setLocationControllerExtraPackage(String);
+    method @Deprecated @RequiresPermission(android.Manifest.permission.LOCATION_HARDWARE) public void setLocationControllerExtraPackageEnabled(boolean);
   }
 
 }
diff --git a/api/test-current.txt b/api/test-current.txt
index 6f8f310..7762baa 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -315,7 +315,9 @@
   }
 
   public final class NotificationChannel implements android.os.Parcelable {
+    method public boolean isImportanceLockedByCriticalDeviceFunction();
     method public boolean isImportanceLockedByOEM();
+    method public void setImportanceLockedByCriticalDeviceFunction(boolean);
     method public void setImportanceLockedByOEM(boolean);
   }
 
@@ -661,20 +663,20 @@
 
   public abstract class PackageManager {
     method public abstract boolean arePermissionsIndividuallyControlled();
-    method @RequiresPermission("android.permission.INTERACT_ACROSS_USERS_FULL") public abstract String getDefaultBrowserPackageNameAsUser(int);
+    method @Nullable @RequiresPermission("android.permission.INTERACT_ACROSS_USERS_FULL") public abstract String getDefaultBrowserPackageNameAsUser(int);
     method @Nullable public String getIncidentReportApproverPackageName();
-    method public abstract int getInstallReason(String, @NonNull android.os.UserHandle);
-    method public abstract java.util.List<android.content.pm.ApplicationInfo> getInstalledApplicationsAsUser(int, int);
-    method @RequiresPermission("android.permission.INTERACT_ACROSS_USERS_FULL") public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackagesAsUser(int, int);
+    method public abstract int getInstallReason(@NonNull String, @NonNull android.os.UserHandle);
+    method @NonNull public abstract java.util.List<android.content.pm.ApplicationInfo> getInstalledApplicationsAsUser(int, int);
+    method @NonNull @RequiresPermission("android.permission.INTERACT_ACROSS_USERS_FULL") public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackagesAsUser(int, int);
     method @Nullable public abstract String[] getNamesForUids(int[]);
-    method public abstract String getPermissionControllerPackageName();
-    method @RequiresPermission(anyOf={"android.permission.GRANT_RUNTIME_PERMISSIONS", "android.permission.REVOKE_RUNTIME_PERMISSIONS", "android.permission.GET_RUNTIME_PERMISSIONS"}) public abstract int getPermissionFlags(String, String, @NonNull android.os.UserHandle);
+    method @NonNull public abstract String getPermissionControllerPackageName();
+    method @RequiresPermission(anyOf={"android.permission.GRANT_RUNTIME_PERMISSIONS", "android.permission.REVOKE_RUNTIME_PERMISSIONS", "android.permission.GET_RUNTIME_PERMISSIONS"}) public abstract int getPermissionFlags(@NonNull String, @NonNull String, @NonNull android.os.UserHandle);
     method @NonNull public abstract String getServicesSystemSharedLibraryPackageName();
     method @NonNull public abstract String getSharedSystemSharedLibraryPackageName();
-    method public String getWellbeingPackageName();
+    method @Nullable public String getWellbeingPackageName();
     method @RequiresPermission("android.permission.GRANT_RUNTIME_PERMISSIONS") public abstract void grantRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle);
     method @RequiresPermission("android.permission.REVOKE_RUNTIME_PERMISSIONS") public abstract void revokeRuntimePermission(@NonNull String, @NonNull String, @NonNull android.os.UserHandle);
-    method @RequiresPermission(anyOf={"android.permission.GRANT_RUNTIME_PERMISSIONS", "android.permission.REVOKE_RUNTIME_PERMISSIONS"}) public abstract void updatePermissionFlags(String, String, int, int, @NonNull android.os.UserHandle);
+    method @RequiresPermission(anyOf={"android.permission.GRANT_RUNTIME_PERMISSIONS", "android.permission.REVOKE_RUNTIME_PERMISSIONS"}) public abstract void updatePermissionFlags(@NonNull String, @NonNull String, int, int, @NonNull android.os.UserHandle);
     field public static final String FEATURE_ADOPTABLE_STORAGE = "android.software.adoptable_storage";
     field public static final String FEATURE_FILE_BASED_ENCRYPTION = "android.software.file_based_encryption";
     field public static final int FLAG_PERMISSION_HIDDEN = 1024; // 0x400
diff --git a/cmds/incidentd/Android.bp b/cmds/incidentd/Android.bp
index 8ac11df..8f9a5f8 100644
--- a/cmds/incidentd/Android.bp
+++ b/cmds/incidentd/Android.bp
@@ -66,6 +66,13 @@
         "libplatformprotos",
     ],
 
+    product_variables: {
+        debuggable: {
+            cflags: ["-DALLOW_RESTRICTED_SECTIONS=1"],
+        },
+    },
+
+
     init_rc: ["incidentd.rc"],
 }
 
diff --git a/cmds/incidentd/src/FdBuffer.cpp b/cmds/incidentd/src/FdBuffer.cpp
index 685c067..b46c9e3 100644
--- a/cmds/incidentd/src/FdBuffer.cpp
+++ b/cmds/incidentd/src/FdBuffer.cpp
@@ -31,7 +31,7 @@
 namespace incidentd {
 
 const ssize_t BUFFER_SIZE = 16 * 1024;  // 16 KB
-const ssize_t MAX_BUFFER_COUNT = 256;   // 4 MB max
+const ssize_t MAX_BUFFER_COUNT = 1536;   // 24 MB max
 
 FdBuffer::FdBuffer()
         :mBuffer(new EncodedBuffer(BUFFER_SIZE)),
diff --git a/cmds/incidentd/src/Reporter.cpp b/cmds/incidentd/src/Reporter.cpp
index 7a08dd6..e773e74 100644
--- a/cmds/incidentd/src/Reporter.cpp
+++ b/cmds/incidentd/src/Reporter.cpp
@@ -26,7 +26,6 @@
 #include "section_list.h"
 
 #include <android-base/file.h>
-#include <android-base/properties.h>
 #include <android/os/DropBoxManager.h>
 #include <android/util/protobuf.h>
 #include <android/util/ProtoOutputStream.h>
@@ -467,8 +466,6 @@
 
     IncidentMetadata metadata;
     int persistedPrivacyPolicy = PRIVACY_POLICY_UNSET;
-    std::string buildType = android::base::GetProperty("ro.build.type", "");
-    const bool isUserdebugOrEng = buildType == "userdebug" || buildType == "eng";
 
     (*reportByteSize) = 0;
 
@@ -567,13 +564,6 @@
     for (const Section** section = SECTION_LIST; *section; section++) {
         const int sectionId = (*section)->id;
 
-        // If this section is too private for user builds, skip it.
-        if ((*section)->userdebugAndEngOnly && !isUserdebugOrEng) {
-            VLOG("Skipping incident report section %d '%s' because it's limited to userdebug/eng",
-                  sectionId, (*section)->name.string());
-            continue;
-        }
-
         // If nobody wants this section, skip it.
         if (!mBatch->containsSection(sectionId)) {
             continue;
diff --git a/cmds/incidentd/src/Section.cpp b/cmds/incidentd/src/Section.cpp
index 1e8261e..935a7c4 100644
--- a/cmds/incidentd/src/Section.cpp
+++ b/cmds/incidentd/src/Section.cpp
@@ -25,6 +25,7 @@
 #include <set>
 
 #include <android-base/file.h>
+#include <android-base/properties.h>
 #include <android-base/stringprintf.h>
 #include <android/util/protobuf.h>
 #include <android/util/ProtoOutputStream.h>
@@ -63,10 +64,10 @@
 }
 
 // ================================================================================
-Section::Section(int i, int64_t timeoutMs, bool userdebugAndEngOnly)
+Section::Section(int i, int64_t timeoutMs)
     : id(i),
-      timeoutMs(timeoutMs),
-      userdebugAndEngOnly(userdebugAndEngOnly) {}
+      timeoutMs(timeoutMs) {
+}
 
 Section::~Section() {}
 
@@ -74,7 +75,7 @@
 static inline bool isSysfs(const char* filename) { return strncmp(filename, "/sys/", 5) == 0; }
 
 FileSection::FileSection(int id, const char* filename, const int64_t timeoutMs)
-    : Section(id, timeoutMs, false), mFilename(filename) {
+    : Section(id, timeoutMs), mFilename(filename) {
     name = "file ";
     name += filename;
     mIsSysfs = isSysfs(filename);
@@ -236,8 +237,8 @@
 WorkerThreadData::~WorkerThreadData() {}
 
 // ================================================================================
-WorkerThreadSection::WorkerThreadSection(int id, const int64_t timeoutMs, bool userdebugAndEngOnly)
-    : Section(id, timeoutMs, userdebugAndEngOnly) {}
+WorkerThreadSection::WorkerThreadSection(int id, const int64_t timeoutMs)
+    : Section(id, timeoutMs) {}
 
 WorkerThreadSection::~WorkerThreadSection() {}
 
@@ -425,8 +426,8 @@
 }
 
 // ================================================================================
-DumpsysSection::DumpsysSection(int id, bool userdebugAndEngOnly, const char* service, ...)
-    : WorkerThreadSection(id, REMOTE_CALL_TIMEOUT_MS, userdebugAndEngOnly), mService(service) {
+DumpsysSection::DumpsysSection(int id, const char* service, ...)
+    : WorkerThreadSection(id, REMOTE_CALL_TIMEOUT_MS), mService(service) {
     name = "dumpsys ";
     name += service;
 
diff --git a/cmds/incidentd/src/Section.h b/cmds/incidentd/src/Section.h
index f89824c..cfe7e16 100644
--- a/cmds/incidentd/src/Section.h
+++ b/cmds/incidentd/src/Section.h
@@ -40,10 +40,9 @@
 public:
     const int id;
     const int64_t timeoutMs;  // each section must have a timeout
-    const bool userdebugAndEngOnly;
     String8 name;
 
-    Section(int id, int64_t timeoutMs = REMOTE_CALL_TIMEOUT_MS, bool userdebugAndEngOnly = false);
+    Section(int id, int64_t timeoutMs = REMOTE_CALL_TIMEOUT_MS);
     virtual ~Section();
 
     virtual status_t Execute(ReportWriter* writer) const = 0;
@@ -85,8 +84,7 @@
  */
 class WorkerThreadSection : public Section {
 public:
-    WorkerThreadSection(int id, int64_t timeoutMs = REMOTE_CALL_TIMEOUT_MS,
-                        bool userdebugAndEngOnly = false);
+    WorkerThreadSection(int id, int64_t timeoutMs = REMOTE_CALL_TIMEOUT_MS);
     virtual ~WorkerThreadSection();
 
     virtual status_t Execute(ReportWriter* writer) const;
@@ -116,7 +114,7 @@
  */
 class DumpsysSection : public WorkerThreadSection {
 public:
-    DumpsysSection(int id, bool userdebugAndEngOnly, const char* service, ...);
+    DumpsysSection(int id, const char* service, ...);
     virtual ~DumpsysSection();
 
     virtual status_t BlockingCall(int pipeWriteFd) const;
@@ -127,6 +125,21 @@
 };
 
 /**
+ * Section that calls dumpsys on a system service.
+ */
+class SystemPropertyDumpsysSection : public WorkerThreadSection {
+public:
+    SystemPropertyDumpsysSection(int id, const char* service, ...);
+    virtual ~SystemPropertyDumpsysSection();
+
+    virtual status_t BlockingCall(int pipeWriteFd) const;
+
+private:
+    String16 mService;
+    Vector<String16> mArgs;
+};
+
+/**
  * Section that reads from logd.
  */
 class LogSection : public WorkerThreadSection {
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index 8cd409e..017cb6d 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -81,7 +81,7 @@
         "src/external/StatsPullerManager.cpp",
         "src/external/puller_util.cpp",
         "src/logd/LogEvent.cpp",
-        "src/logd/LogListener.cpp",
+        "src/logd/LogEventQueue.cpp",
         "src/matchers/CombinationLogMatchingTracker.cpp",
         "src/matchers/EventMatcherWizard.cpp",
         "src/matchers/matcher_util.cpp",
@@ -226,6 +226,7 @@
         "tests/indexed_priority_queue_test.cpp",
         "tests/LogEntryMatcher_test.cpp",
         "tests/LogEvent_test.cpp",
+        "tests/log_event/LogEventQueue_test.cpp",
         "tests/MetricsManager_test.cpp",
         "tests/StatsLogProcessor_test.cpp",
         "tests/StatsService_test.cpp",
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index 52ecdc8..3bcebd9 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -65,8 +65,6 @@
 
 // for StatsDataDumpProto
 const int FIELD_ID_REPORTS_LIST = 1;
-// for TrainInfo experiment id serialization
-const int FIELD_ID_EXPERIMENT_ID = 1;
 
 static binder::Status ok() {
     return binder::Status::ok();
@@ -132,34 +130,36 @@
     }                                                             \
 }
 
-StatsService::StatsService(const sp<Looper>& handlerLooper)
-    : mAnomalyAlarmMonitor(new AlarmMonitor(MIN_DIFF_TO_UPDATE_REGISTERED_ALARM_SECS,
-       [](const sp<IStatsCompanionService>& sc, int64_t timeMillis) {
-           if (sc != nullptr) {
-               sc->setAnomalyAlarm(timeMillis);
-               StatsdStats::getInstance().noteRegisteredAnomalyAlarmChanged();
-           }
-       },
-       [](const sp<IStatsCompanionService>& sc) {
-           if (sc != nullptr) {
-               sc->cancelAnomalyAlarm();
-               StatsdStats::getInstance().noteRegisteredAnomalyAlarmChanged();
-           }
-       })),
-   mPeriodicAlarmMonitor(new AlarmMonitor(MIN_DIFF_TO_UPDATE_REGISTERED_ALARM_SECS,
-      [](const sp<IStatsCompanionService>& sc, int64_t timeMillis) {
-           if (sc != nullptr) {
-               sc->setAlarmForSubscriberTriggering(timeMillis);
-               StatsdStats::getInstance().noteRegisteredPeriodicAlarmChanged();
-           }
-      },
-      [](const sp<IStatsCompanionService>& sc) {
-           if (sc != nullptr) {
-               sc->cancelAlarmForSubscriberTriggering();
-               StatsdStats::getInstance().noteRegisteredPeriodicAlarmChanged();
-           }
-
-      }))  {
+StatsService::StatsService(const sp<Looper>& handlerLooper, shared_ptr<LogEventQueue> queue)
+    : mAnomalyAlarmMonitor(new AlarmMonitor(
+              MIN_DIFF_TO_UPDATE_REGISTERED_ALARM_SECS,
+              [](const sp<IStatsCompanionService>& sc, int64_t timeMillis) {
+                  if (sc != nullptr) {
+                      sc->setAnomalyAlarm(timeMillis);
+                      StatsdStats::getInstance().noteRegisteredAnomalyAlarmChanged();
+                  }
+              },
+              [](const sp<IStatsCompanionService>& sc) {
+                  if (sc != nullptr) {
+                      sc->cancelAnomalyAlarm();
+                      StatsdStats::getInstance().noteRegisteredAnomalyAlarmChanged();
+                  }
+              })),
+      mPeriodicAlarmMonitor(new AlarmMonitor(
+              MIN_DIFF_TO_UPDATE_REGISTERED_ALARM_SECS,
+              [](const sp<IStatsCompanionService>& sc, int64_t timeMillis) {
+                  if (sc != nullptr) {
+                      sc->setAlarmForSubscriberTriggering(timeMillis);
+                      StatsdStats::getInstance().noteRegisteredPeriodicAlarmChanged();
+                  }
+              },
+              [](const sp<IStatsCompanionService>& sc) {
+                  if (sc != nullptr) {
+                      sc->cancelAlarmForSubscriberTriggering();
+                      StatsdStats::getInstance().noteRegisteredPeriodicAlarmChanged();
+                  }
+              })),
+      mEventQueue(queue) {
     mUidMap = UidMap::getInstance();
     mPullerManager = new StatsPullerManager();
     StatsPuller::SetUidMap(mUidMap);
@@ -201,11 +201,33 @@
     mConfigManager->AddListener(mProcessor);
 
     init_system_properties();
+
+    if (mEventQueue != nullptr) {
+        std::thread pushedEventThread([this] { readLogs(); });
+        pushedEventThread.detach();
+    }
 }
 
 StatsService::~StatsService() {
 }
 
+/* Runs on a dedicated thread to process pushed events. */
+void StatsService::readLogs() {
+    // Read forever..... long live statsd
+    while (1) {
+        // Block until an event is available.
+        auto event = mEventQueue->waitPop();
+        // Pass it to StatsLogProcess to all configs/metrics
+        // At this point, the LogEventQueue is not blocked, so that the socketListener
+        // can read events from the socket and write to buffer to avoid data drop.
+        mProcessor->OnLogEvent(event.get());
+        // The ShellSubscriber is only used by shell for local debugging.
+        if (mShellSubscriber != nullptr) {
+            mShellSubscriber->onLogEvent(*event);
+        }
+    }
+}
+
 void StatsService::init_system_properties() {
     mEngBuild = false;
     const prop_info* buildType = __system_property_find("ro.build.type");
@@ -1009,6 +1031,7 @@
     }
 }
 
+// Test only interface!!!
 void StatsService::OnLogEvent(LogEvent* event) {
     mProcessor->OnLogEvent(event);
     if (mShellSubscriber != nullptr) {
@@ -1181,7 +1204,7 @@
 Status StatsService::sendBinaryPushStateChangedAtom(const android::String16& trainName,
                                                     int64_t trainVersionCode, int options,
                                                     int32_t state,
-                                                    const std::vector<int64_t>& experimentIds) {
+                                                    const std::vector<int64_t>& experimentIdsIn) {
     uid_t uid = IPCThreadState::self()->getCallingUid();
     // For testing
     if (uid == AID_ROOT || uid == AID_SYSTEM || uid == AID_SHELL) {
@@ -1201,7 +1224,7 @@
 
     bool readTrainInfoSuccess = false;
     InstallTrainInfo trainInfo;
-    if (trainVersionCode == -1 || experimentIds.empty() || trainName.size() == 0) {
+    if (trainVersionCode == -1 || experimentIdsIn.empty() || trainName.size() == 0) {
         readTrainInfoSuccess = StorageManager::readTrainInfo(trainInfo);
     }
 
@@ -1209,27 +1232,19 @@
         trainVersionCode = trainInfo.trainVersionCode;
     }
 
-    vector<uint8_t> experimentIdsProtoBuffer;
-    if (readTrainInfoSuccess && experimentIds.empty()) {
-        experimentIdsProtoBuffer = trainInfo.experimentIds;
+    // Find the right experiment IDs
+    std::vector<int64_t> experimentIds;
+    if (readTrainInfoSuccess && experimentIdsIn.empty()) {
+        experimentIds = trainInfo.experimentIds;
     } else {
-        ProtoOutputStream proto;
-        for (const auto& expId : experimentIds) {
-            proto.write(FIELD_TYPE_INT64 | FIELD_COUNT_REPEATED | FIELD_ID_EXPERIMENT_ID,
-                        (long long)expId);
-        }
-
-        experimentIdsProtoBuffer.resize(proto.size());
-        size_t pos = 0;
-        sp<ProtoReader> reader = proto.data();
-        while (reader->readBuffer() != NULL) {
-            size_t toRead = reader->currentToRead();
-            std::memcpy(&(experimentIdsProtoBuffer[pos]), reader->readBuffer(), toRead);
-            pos += toRead;
-            reader->move(toRead);
-        }
+        experimentIds = experimentIdsIn;
     }
 
+    // Flatten the experiment IDs to proto
+    vector<uint8_t> experimentIdsProtoBuffer;
+    writeExperimentIdsToProto(experimentIds, &experimentIdsProtoBuffer);
+
+    // Find the right train name
     std::string trainNameUtf8;
     if (readTrainInfoSuccess && trainName.size() == 0) {
         trainNameUtf8 = trainInfo.trainName;
@@ -1244,7 +1259,34 @@
     LogEvent event(trainNameUtf8, trainVersionCode, requiresStaging, rollbackEnabled,
                    requiresLowLatencyMonitor, state, experimentIdsProtoBuffer, userId);
     mProcessor->OnLogEvent(&event);
-    StorageManager::writeTrainInfo(trainVersionCode, trainNameUtf8, state, experimentIdsProtoBuffer);
+    StorageManager::writeTrainInfo(trainVersionCode, trainNameUtf8, state, experimentIds);
+    return Status::ok();
+}
+
+Status StatsService::getRegisteredExperimentIds(std::vector<int64_t>* experimentIdsOut) {
+    uid_t uid = IPCThreadState::self()->getCallingUid();
+
+    // Caller must be granted these permissions
+    if (!checkCallingPermission(String16(kPermissionDump))) {
+        return exception(binder::Status::EX_SECURITY,
+                         StringPrintf("UID %d lacks permission %s", uid, kPermissionDump));
+    }
+    if (!checkCallingPermission(String16(kPermissionUsage))) {
+        return exception(binder::Status::EX_SECURITY,
+                         StringPrintf("UID %d lacks permission %s", uid, kPermissionUsage));
+    }
+    // TODO: add verifier permission
+
+    // Read the latest train info
+    InstallTrainInfo trainInfo;
+    if (!StorageManager::readTrainInfo(trainInfo)) {
+        // No train info means no experiment IDs, return an empty list
+        experimentIdsOut->clear();
+        return Status::ok();
+    }
+
+    // Copy the experiment IDs to the out vector
+    experimentIdsOut->assign(trainInfo.experimentIds.begin(), trainInfo.experimentIds.end());
     return Status::ok();
 }
 
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index d24565a..929d260 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -22,7 +22,7 @@
 #include "anomaly/AlarmMonitor.h"
 #include "config/ConfigManager.h"
 #include "external/StatsPullerManager.h"
-#include "logd/LogListener.h"
+#include "logd/LogEventQueue.h"
 #include "packages/UidMap.h"
 #include "shell/ShellSubscriber.h"
 #include "statscompanion_util.h"
@@ -52,11 +52,10 @@
 using android::hardware::Return;
 
 class StatsService : public BnStatsManager,
-                     public LogListener,
                      public IStats,
                      public IBinder::DeathRecipient {
 public:
-    StatsService(const sp<Looper>& handlerLooper);
+    StatsService(const sp<Looper>& handlerLooper, std::shared_ptr<LogEventQueue> queue);
     virtual ~StatsService();
 
     /** The anomaly alarm registered with AlarmManager won't be updated by less than this. */
@@ -92,7 +91,7 @@
     void Terminate();
 
     /**
-     * Called by LogReader when there's a log event to process.
+     * Test ONLY interface. In real world, StatsService reads from LogEventQueue.
      */
     virtual void OnLogEvent(LogEvent* event);
 
@@ -194,6 +193,11 @@
             int32_t state, const std::vector<int64_t>& experimentIds) override;
 
     /**
+     * Binder call to get registered experiment IDs.
+     */
+    virtual Status getRegisteredExperimentIds(std::vector<int64_t>* expIdsOut);
+
+    /**
      * Binder call to get SpeakerImpedance atom.
      */
     virtual Return<void> reportSpeakerImpedance(const SpeakerImpedance& speakerImpedance) override;
@@ -278,6 +282,9 @@
      */
     void print_cmd_help(int out);
 
+    /* Runs on its dedicated thread to process pushed stats event from socket. */
+    void readLogs();
+
     /**
      * Trigger a broadcast.
      */
@@ -410,6 +417,8 @@
 
     sp<ShellSubscriber> mShellSubscriber;
 
+    std::shared_ptr<LogEventQueue> mEventQueue;
+
     FRIEND_TEST(StatsServiceTest, TestAddConfig_simple);
     FRIEND_TEST(StatsServiceTest, TestAddConfig_empty);
     FRIEND_TEST(StatsServiceTest, TestAddConfig_invalid);
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index c2b81e4..1ffde97 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -187,7 +187,7 @@
         WifiEnabledStateChanged wifi_enabled_state_changed = 113;
         WifiRunningStateChanged wifi_running_state_changed = 114;
         AppCompacted app_compacted = 115;
-        NetworkDnsEventReported network_dns_event_reported = 116;
+        NetworkDnsEventReported network_dns_event_reported = 116 [(log_from_module) = "resolv"];
         DocsUIPickerLaunchedFromReported docs_ui_picker_launched_from_reported = 117;
         DocsUIPickResultReported docs_ui_pick_result_reported = 118;
         DocsUISearchModeReported docs_ui_search_mode_reported = 119;
@@ -254,10 +254,11 @@
         PrivacyIndicatorsInteracted privacy_indicators_interacted = 180;
         AppInstallOnExternalStorageReported app_install_on_external_storage_reported = 181;
         NetworkStackReported network_stack_reported = 182;
+        AppMovedStorageReported app_moved_storage_reported = 183;
     }
 
     // Pulled events will start at field 10000.
-    // Next: 10057
+    // Next: 10058
     oneof pulled {
         WifiBytesTransfer wifi_bytes_transfer = 10000;
         WifiBytesTransferByFgBg wifi_bytes_transfer_by_fg_bg = 10001;
@@ -316,6 +317,7 @@
         GpuStatsGlobalInfo gpu_stats_global_info = 10054;
         GpuStatsAppInfo gpu_stats_app_info = 10055;
         SystemIonHeapSize system_ion_heap_size = 10056;
+        AppsOnExternalStorageInfo apps_on_external_storage_info = 10057;
     }
 
     // DO NOT USE field numbers above 100,000 in AOSP.
@@ -3445,6 +3447,30 @@
     optional string package_name = 2;
 }
 
+/**
+ * Logs information about a package that is moved from the internal to external storage and vice
+ * versa.
+ * It logs the package name, the type of the external storage where the package is installed
+ * (if moved to external storage, or UNKNOWN if moved to internal storage),
+ * and the move type: if it's from internal to external or the other way around.
+ *
+ * Logged from:
+        frameworks/base/services/core/java/com/android/server/pm/PackageManagerService.java
+ */
+message AppMovedStorageReported {
+    enum MoveType {
+        UNKNOWN = 0;
+        TO_EXTERNAL = 1;
+        TO_INTERNAL = 2;
+    }
+    // The type of the external storage.
+    optional android.stats.storage.ExternalStorageType external_storage_type = 1;
+    // The type of move.
+    optional MoveType move_type = 2;
+    // The name of the package that was moved.
+    optional string package_name = 3;
+}
+
 //////////////////////////////////////////////////////////////////////
 // Pulled atoms below this line //
 //////////////////////////////////////////////////////////////////////
@@ -5556,6 +5582,9 @@
     // Normalized screen position of the bubble stack. The range is between 0 and 1.
     optional float normalized_x_position = 7;
     optional float normalized_y_position = 8;
+
+    // Whether the bubble is unread. If it is unread, a dot is shown in the bubble stack icon.
+    optional bool is_unread = 9;
 }
 
 /**
@@ -5863,6 +5892,20 @@
  *     frameworks/base/packages/NetworkStack/
  */
 message NetworkStackReported {
-    optional int32 eventId = 1;
+    // The id that indicates the event reported from NetworkStack.
+    optional int32 event_id = 1;
+    // The data for the reported events.
     optional android.stats.connectivity.NetworkStackEventData network_stack_event = 2 [(log_mode) = MODE_BYTES];
 }
+
+/**
+ * Logs the apps that are installed on the external storage.
+ * Pulled from:
+ *   StatsCompanionService
+ */
+message AppsOnExternalStorageInfo {
+    // The type of the external storage.
+    optional android.stats.storage.ExternalStorageType external_storage_type = 1;
+    // The name of the package that is installed on the external storage.
+    optional string package_name = 2;
+}
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index 2abfc24..13eee5d 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -251,6 +251,9 @@
         // GpuStatsAppInfo
         {android::util::GPU_STATS_APP_INFO,
          {.puller = new GpuStatsPuller(android::util::GPU_STATS_APP_INFO)}},
+        // AppsOnExternalStorageInfo
+        {android::util::APPS_ON_EXTERNAL_STORAGE_INFO,
+         {.puller = new StatsCompanionServicePuller(android::util::APPS_ON_EXTERNAL_STORAGE_INFO)}},
 };
 
 StatsPullerManager::StatsPullerManager() : mNextPullTimeNs(NO_ALARM_UPDATE) {
diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp
index 24408fc..74a4c87 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.cpp
+++ b/cmds/statsd/src/guardrail/StatsdStats.cpp
@@ -50,6 +50,7 @@
 const int FIELD_ID_PERIODIC_ALARM_STATS = 12;
 const int FIELD_ID_SYSTEM_SERVER_RESTART = 15;
 const int FIELD_ID_LOGGER_ERROR_STATS = 16;
+const int FIELD_ID_OVERFLOW = 18;
 
 const int FIELD_ID_ATOM_STATS_TAG = 1;
 const int FIELD_ID_ATOM_STATS_COUNT = 2;
@@ -60,6 +61,13 @@
 const int FIELD_ID_LOG_LOSS_STATS_TIME = 1;
 const int FIELD_ID_LOG_LOSS_STATS_COUNT = 2;
 const int FIELD_ID_LOG_LOSS_STATS_ERROR = 3;
+const int FIELD_ID_LOG_LOSS_STATS_TAG = 4;
+const int FIELD_ID_LOG_LOSS_STATS_UID = 5;
+const int FIELD_ID_LOG_LOSS_STATS_PID = 6;
+
+const int FIELD_ID_OVERFLOW_COUNT = 1;
+const int FIELD_ID_OVERFLOW_MAX_HISTORY = 2;
+const int FIELD_ID_OVERFLOW_MIN_HISTORY = 3;
 
 const int FIELD_ID_CONFIG_STATS_UID = 1;
 const int FIELD_ID_CONFIG_STATS_ID = 2;
@@ -183,12 +191,13 @@
     noteConfigResetInternalLocked(key);
 }
 
-void StatsdStats::noteLogLost(int32_t wallClockTimeSec, int32_t count, int32_t lastError) {
+void StatsdStats::noteLogLost(int32_t wallClockTimeSec, int32_t count, int32_t lastError,
+                              int32_t lastTag, int32_t uid, int32_t pid) {
     lock_guard<std::mutex> lock(mLock);
     if (mLogLossStats.size() == kMaxLoggerErrors) {
         mLogLossStats.pop_front();
     }
-    mLogLossStats.emplace_back(wallClockTimeSec, count, lastError);
+    mLogLossStats.emplace_back(wallClockTimeSec, count, lastError, lastTag, uid, pid);
 }
 
 void StatsdStats::noteBroadcastSent(const ConfigKey& key) {
@@ -231,6 +240,22 @@
     noteDataDropped(key, totalBytes, getWallClockSec());
 }
 
+void StatsdStats::noteEventQueueOverflow(int64_t oldestEventTimestampNs) {
+    lock_guard<std::mutex> lock(mLock);
+
+    mOverflowCount++;
+
+    int64_t history = getElapsedRealtimeNs() - oldestEventTimestampNs;
+
+    if (history > mMaxQueueHistoryNs) {
+        mMaxQueueHistoryNs = history;
+    }
+
+    if (history < mMinQueueHistoryNs) {
+        mMinQueueHistoryNs = history;
+    }
+}
+
 void StatsdStats::noteDataDropped(const ConfigKey& key, const size_t totalBytes, int32_t timeSec) {
     lock_guard<std::mutex> lock(mLock);
     auto it = mConfigStats.find(key);
@@ -530,6 +555,9 @@
     mPeriodicAlarmRegisteredStats = 0;
     mSystemServerRestartSec.clear();
     mLogLossStats.clear();
+    mOverflowCount = 0;
+    mMinQueueHistoryNs = kInt64Max;
+    mMaxQueueHistoryNs = 0;
     for (auto& config : mConfigStats) {
         config.second->broadcast_sent_time_sec.clear();
         config.second->activation_time_sec.clear();
@@ -716,9 +744,15 @@
     }
 
     for (const auto& loss : mLogLossStats) {
-        dprintf(out, "Log loss: %lld (wall clock sec) - %d (count) %d (last error)\n",
-                (long long)loss.mWallClockSec, loss.mCount, loss.mLastError);
+        dprintf(out,
+                "Log loss: %lld (wall clock sec) - %d (count), %d (last error), %d (last tag), %d "
+                "(uid), %d (pid)\n",
+                (long long)loss.mWallClockSec, loss.mCount, loss.mLastError, loss.mLastTag,
+                loss.mUid, loss.mPid);
     }
+
+    dprintf(out, "Event queue overflow: %d; MaxHistoryNs: %lld; MinHistoryNs: %lld\n",
+            mOverflowCount, (long long)mMaxQueueHistoryNs, (long long)mMinQueueHistoryNs);
 }
 
 void addConfigStatsToProto(const ConfigStats& configStats, ProtoOutputStream* proto) {
@@ -891,6 +925,19 @@
         proto.write(FIELD_TYPE_INT32 | FIELD_ID_LOG_LOSS_STATS_TIME, error.mWallClockSec);
         proto.write(FIELD_TYPE_INT32 | FIELD_ID_LOG_LOSS_STATS_COUNT, error.mCount);
         proto.write(FIELD_TYPE_INT32 | FIELD_ID_LOG_LOSS_STATS_ERROR, error.mLastError);
+        proto.write(FIELD_TYPE_INT32 | FIELD_ID_LOG_LOSS_STATS_TAG, error.mLastTag);
+        proto.write(FIELD_TYPE_INT32 | FIELD_ID_LOG_LOSS_STATS_UID, error.mUid);
+        proto.write(FIELD_TYPE_INT32 | FIELD_ID_LOG_LOSS_STATS_PID, error.mPid);
+        proto.end(token);
+    }
+
+    if (mOverflowCount > 0) {
+        uint64_t token = proto.start(FIELD_TYPE_MESSAGE | FIELD_ID_OVERFLOW);
+        proto.write(FIELD_TYPE_INT32 | FIELD_ID_OVERFLOW_COUNT, (int32_t)mOverflowCount);
+        proto.write(FIELD_TYPE_INT64 | FIELD_ID_OVERFLOW_MAX_HISTORY,
+                    (long long)mMaxQueueHistoryNs);
+        proto.write(FIELD_TYPE_INT64 | FIELD_ID_OVERFLOW_MIN_HISTORY,
+                    (long long)mMinQueueHistoryNs);
         proto.end(token);
     }
 
diff --git a/cmds/statsd/src/guardrail/StatsdStats.h b/cmds/statsd/src/guardrail/StatsdStats.h
index 7c2d846..88ecccc 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.h
+++ b/cmds/statsd/src/guardrail/StatsdStats.h
@@ -160,6 +160,8 @@
     // Max platform atom tag number.
     static const int32_t kMaxPlatformAtomTag = 100000;
 
+    static const int64_t kInt64Max = 0x7fffffffffffffffLL;
+
     /**
      * Report a new config has been received and report the static stats about the config.
      *
@@ -336,7 +338,8 @@
     /**
      * Records statsd skipped an event.
      */
-    void noteLogLost(int32_t wallClockTimeSec, int32_t count, int lastError);
+    void noteLogLost(int32_t wallClockTimeSec, int32_t count, int32_t lastError,
+                     int32_t lastAtomTag, int32_t uid, int32_t pid);
 
     /**
      * Records that the pull of an atom has failed
@@ -418,6 +421,10 @@
      */
     void noteBucketUnknownCondition(int64_t metricId);
 
+    /* Reports one event has been dropped due to queue overflow, and the oldest event timestamp in
+     * the queue */
+    void noteEventQueueOverflow(int64_t oldestEventTimestampNs);
+
     /**
      * Reset the historical stats. Including all stats in icebox, and the tracked stats about
      * metrics, matchers, and atoms. The active configs will be kept and StatsdStats will continue
@@ -503,15 +510,35 @@
     std::map<int64_t, AtomMetricStats> mAtomMetricStats;
 
     struct LogLossStats {
-        LogLossStats(int32_t sec, int32_t count, int32_t error)
-            : mWallClockSec(sec), mCount(count), mLastError(error) {
+        LogLossStats(int32_t sec, int32_t count, int32_t error, int32_t tag, int32_t uid,
+                     int32_t pid)
+            : mWallClockSec(sec),
+              mCount(count),
+              mLastError(error),
+              mLastTag(tag),
+              mUid(uid),
+              mPid(pid) {
         }
         int32_t mWallClockSec;
         int32_t mCount;
         // error code defined in linux/errno.h
         int32_t mLastError;
+        int32_t mLastTag;
+        int32_t mUid;
+        int32_t mPid;
     };
 
+    // Max of {(now - oldestEventTimestamp) when overflow happens}.
+    // This number is helpful to understand how SLOW statsd can be.
+    int64_t mMaxQueueHistoryNs = 0;
+
+    // Min of {(now - oldestEventTimestamp) when overflow happens}.
+    // This number is helpful to understand how FAST the events floods to statsd.
+    int64_t mMinQueueHistoryNs = kInt64Max;
+
+    // Total number of events that are lost due to queue overflow.
+    int32_t mOverflowCount = 0;
+
     // Timestamps when we detect log loss, and the number of logs lost.
     std::list<LogLossStats> mLogLossStats;
 
diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp
index d9f5415..ca874b5 100644
--- a/cmds/statsd/src/logd/LogEvent.cpp
+++ b/cmds/statsd/src/logd/LogEvent.cpp
@@ -27,6 +27,9 @@
 namespace os {
 namespace statsd {
 
+// for TrainInfo experiment id serialization
+const int FIELD_ID_EXPERIMENT_ID = 1;
+
 using namespace android::util;
 using android::util::ProtoOutputStream;
 using std::string;
@@ -118,6 +121,7 @@
 
 LogEvent::LogEvent(int32_t tagId, int64_t wallClockTimestampNs, int64_t elapsedTimestampNs) {
     mLogdTimestampNs = wallClockTimestampNs;
+    mElapsedTimestampNs = elapsedTimestampNs;
     mTagId = tagId;
     mLogUid = 0;
     mContext = create_android_logger(1937006964); // the event tag shared by all stats logs
@@ -241,12 +245,15 @@
 
     mValues.push_back(
             FieldValue(Field(mTagId, getSimpleField(1)), Value(trainInfo.trainVersionCode)));
-    mValues.push_back(FieldValue(Field(mTagId, getSimpleField(2)), Value(trainInfo.experimentIds)));
+    std::vector<uint8_t> experimentIdsProto;
+    writeExperimentIdsToProto(trainInfo.experimentIds, &experimentIdsProto);
+    mValues.push_back(FieldValue(Field(mTagId, getSimpleField(2)), Value(experimentIdsProto)));
     mValues.push_back(FieldValue(Field(mTagId, getSimpleField(3)), Value(trainInfo.trainName)));
     mValues.push_back(FieldValue(Field(mTagId, getSimpleField(4)), Value(trainInfo.status)));
 }
 
-LogEvent::LogEvent(int32_t tagId, int64_t timestampNs) : LogEvent(tagId, timestampNs, 0) {}
+LogEvent::LogEvent(int32_t tagId, int64_t timestampNs) : LogEvent(tagId, timestampNs, timestampNs) {
+}
 
 LogEvent::LogEvent(int32_t tagId, int64_t timestampNs, int32_t uid) {
     mLogdTimestampNs = timestampNs;
@@ -671,6 +678,24 @@
     writeFieldValueTreeToStream(mTagId, getValues(), &protoOutput);
 }
 
+void writeExperimentIdsToProto(const std::vector<int64_t>& experimentIds, std::vector<uint8_t>* protoOut) {
+    ProtoOutputStream proto;
+    for (const auto& expId : experimentIds) {
+        proto.write(FIELD_TYPE_INT64 | FIELD_COUNT_REPEATED | FIELD_ID_EXPERIMENT_ID,
+                    (long long)expId);
+    }
+
+    protoOut->resize(proto.size());
+    size_t pos = 0;
+    sp<ProtoReader> reader = proto.data();
+    while (reader->readBuffer() != NULL) {
+        size_t toRead = reader->currentToRead();
+        std::memcpy(protoOut->data() + pos, reader->readBuffer(), toRead);
+        pos += toRead;
+        reader->move(toRead);
+    }
+}
+
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
diff --git a/cmds/statsd/src/logd/LogEvent.h b/cmds/statsd/src/logd/LogEvent.h
index 753a9a5..531ce29 100644
--- a/cmds/statsd/src/logd/LogEvent.h
+++ b/cmds/statsd/src/logd/LogEvent.h
@@ -60,8 +60,9 @@
     int64_t trainVersionCode;
     std::string trainName;
     int32_t status;
-    std::vector<uint8_t> experimentIds;
+    std::vector<int64_t> experimentIds;
 };
+
 /**
  * Wrapper for the log_msg structure.
  */
@@ -239,6 +240,8 @@
     uint32_t mLogUid;
 };
 
+void writeExperimentIdsToProto(const std::vector<int64_t>& experimentIds, std::vector<uint8_t>* protoOut);
+
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
diff --git a/cmds/statsd/src/logd/LogEventQueue.cpp b/cmds/statsd/src/logd/LogEventQueue.cpp
new file mode 100644
index 0000000..146464b
--- /dev/null
+++ b/cmds/statsd/src/logd/LogEventQueue.cpp
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+#define DEBUG false  // STOPSHIP if true
+#include "Log.h"
+
+#include "LogEventQueue.h"
+
+namespace android {
+namespace os {
+namespace statsd {
+
+using std::unique_lock;
+using std::unique_ptr;
+
+unique_ptr<LogEvent> LogEventQueue::waitPop() {
+    std::unique_lock<std::mutex> lock(mMutex);
+
+    if (mQueue.empty()) {
+        mCondition.wait(lock, [this] { return !this->mQueue.empty(); });
+    }
+
+    unique_ptr<LogEvent> item = std::move(mQueue.front());
+    mQueue.pop();
+
+    return item;
+}
+
+bool LogEventQueue::push(unique_ptr<LogEvent> item, int64_t* oldestTimestampNs) {
+    bool success;
+    {
+        std::unique_lock<std::mutex> lock(mMutex);
+        if (mQueue.size() < mQueueLimit) {
+            mQueue.push(std::move(item));
+            success = true;
+        } else {
+            // safe operation as queue must not be empty.
+            *oldestTimestampNs = mQueue.front()->GetElapsedTimestampNs();
+            success = false;
+        }
+    }
+
+    mCondition.notify_one();
+    return success;
+}
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
diff --git a/cmds/statsd/src/logd/LogEventQueue.h b/cmds/statsd/src/logd/LogEventQueue.h
new file mode 100644
index 0000000..b4fd63f
--- /dev/null
+++ b/cmds/statsd/src/logd/LogEventQueue.h
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "LogEvent.h"
+
+#include <condition_variable>
+#include <memory>
+#include <mutex>
+#include <queue>
+#include <thread>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+/**
+ * A zero copy thread safe queue buffer for producing and consuming LogEvent.
+ */
+class LogEventQueue {
+public:
+    explicit LogEventQueue(size_t maxSize) : mQueueLimit(maxSize){};
+
+    /**
+     * Blocking read one event from the queue.
+     */
+    std::unique_ptr<LogEvent> waitPop();
+
+    /**
+     * Puts a LogEvent ptr to the end of the queue.
+     * Returns false on failure when the queue is full, and output the oldest event timestamp
+     * in the queue.
+     */
+    bool push(std::unique_ptr<LogEvent> event, int64_t* oldestTimestampNs);
+
+private:
+    const size_t mQueueLimit;
+    std::condition_variable mCondition;
+    std::mutex mMutex;
+    std::queue<std::unique_ptr<LogEvent>> mQueue;
+};
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
diff --git a/cmds/statsd/src/logd/LogListener.h b/cmds/statsd/src/logd/LogListener.h
deleted file mode 100644
index d8b06e9..0000000
--- a/cmds/statsd/src/logd/LogListener.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include "logd/LogEvent.h"
-
-#include <utils/RefBase.h>
-
-namespace android {
-namespace os {
-namespace statsd {
-
-/**
- * Callback for LogReader
- */
-class LogListener : public virtual android::RefBase {
-public:
-    LogListener();
-    virtual ~LogListener();
-
-    virtual void OnLogEvent(LogEvent* msg) = 0;
-};
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
diff --git a/cmds/statsd/src/main.cpp b/cmds/statsd/src/main.cpp
index eddc86e..68082c2 100644
--- a/cmds/statsd/src/main.cpp
+++ b/cmds/statsd/src/main.cpp
@@ -80,8 +80,11 @@
 
     ::android::hardware::configureRpcThreadpool(1 /*threads*/, false /*willJoin*/);
 
+    std::shared_ptr<LogEventQueue> eventQueue =
+            std::make_shared<LogEventQueue>(2000 /*buffer limit. Buffer is NOT pre-allocated*/);
+
     // Create the service
-    gStatsService = new StatsService(looper);
+    gStatsService = new StatsService(looper, eventQueue);
     if (defaultServiceManager()->addService(String16("stats"), gStatsService, false,
                 IServiceManager::DUMP_FLAG_PRIORITY_NORMAL | IServiceManager::DUMP_FLAG_PROTO)
             != 0) {
@@ -101,13 +104,13 @@
 
     gStatsService->Startup();
 
-    sp<StatsSocketListener> socketListener = new StatsSocketListener(gStatsService);
+    sp<StatsSocketListener> socketListener = new StatsSocketListener(eventQueue);
 
-        ALOGI("using statsd socket");
-        // Backlog and /proc/sys/net/unix/max_dgram_qlen set to large value
-        if (socketListener->startListener(600)) {
-            exit(1);
-        }
+    ALOGI("Statsd starts to listen to socket.");
+    // Backlog and /proc/sys/net/unix/max_dgram_qlen set to large value
+    if (socketListener->startListener(600)) {
+        exit(1);
+    }
 
     // Loop forever -- the reports run on this thread in a handler, and the
     // binder calls remain responsive in their pool of one thread.
diff --git a/cmds/statsd/src/socket/StatsSocketListener.cpp b/cmds/statsd/src/socket/StatsSocketListener.cpp
index 6bb8cda..92200f9 100755
--- a/cmds/statsd/src/socket/StatsSocketListener.cpp
+++ b/cmds/statsd/src/socket/StatsSocketListener.cpp
@@ -41,8 +41,8 @@
 
 static const int kLogMsgHeaderSize = 28;
 
-StatsSocketListener::StatsSocketListener(const sp<LogListener>& listener)
-    : SocketListener(getLogSocket(), false /*start listen*/), mListener(listener) {
+StatsSocketListener::StatsSocketListener(std::shared_ptr<LogEventQueue> queue)
+    : SocketListener(getLogSocket(), false /*start listen*/), mQueue(queue) {
 }
 
 StatsSocketListener::~StatsSocketListener() {
@@ -106,13 +106,21 @@
     // Note that all normal stats logs are in the format of event_list, so there won't be confusion.
     //
     // TODO(b/80538532): In addition to log it in StatsdStats, we should properly reset the config.
-    if (n == sizeof(android_log_event_int_t)) {
-        android_log_event_int_t* int_event = reinterpret_cast<android_log_event_int_t*>(ptr);
-        if (int_event->payload.type == EVENT_TYPE_INT) {
-            ALOGE("Found dropped events: %d error %d", int_event->payload.data,
-                  int_event->header.tag);
-            StatsdStats::getInstance().noteLogLost((int32_t)getWallClockSec(),
-                                                   int_event->payload.data, int_event->header.tag);
+    if (n == sizeof(android_log_event_long_t)) {
+        android_log_event_long_t* long_event = reinterpret_cast<android_log_event_long_t*>(ptr);
+        if (long_event->payload.type == EVENT_TYPE_LONG) {
+            int64_t composed_long = long_event->payload.data;
+
+            // format:
+            // |last_tag|dropped_count|
+            int32_t dropped_count = (int32_t)(0xffffffff & composed_long);
+            int32_t last_atom_tag = (int32_t)((0xffffffff00000000 & (uint64_t)composed_long) >> 32);
+
+            ALOGE("Found dropped events: %d error %d last atom tag %d from uid %d", dropped_count,
+                  long_event->header.tag, last_atom_tag, cred->uid);
+            StatsdStats::getInstance().noteLogLost((int32_t)getWallClockSec(), dropped_count,
+                                                   long_event->header.tag, last_atom_tag, cred->uid,
+                                                   cred->pid);
             return true;
         }
     }
@@ -126,10 +134,11 @@
     msg.entry.uid = cred->uid;
 
     memcpy(msg.buf + kLogMsgHeaderSize, ptr, n + 1);
-    LogEvent event(msg);
 
-    // Call the listener
-    mListener->OnLogEvent(&event);
+    int64_t oldestTimestamp;
+    if (!mQueue->push(std::make_unique<LogEvent>(msg), &oldestTimestamp)) {
+        StatsdStats::getInstance().noteEventQueueOverflow(oldestTimestamp);
+    }
 
     return true;
 }
diff --git a/cmds/statsd/src/socket/StatsSocketListener.h b/cmds/statsd/src/socket/StatsSocketListener.h
index b8185d2..2167a56 100644
--- a/cmds/statsd/src/socket/StatsSocketListener.h
+++ b/cmds/statsd/src/socket/StatsSocketListener.h
@@ -17,7 +17,7 @@
 
 #include <sysutils/SocketListener.h>
 #include <utils/RefBase.h>
-#include "logd/LogListener.h"
+#include "logd/LogEventQueue.h"
 
 // DEFAULT_OVERFLOWUID is defined in linux/highuid.h, which is not part of
 // the uapi headers for userspace to use.  This value is filled in on the
@@ -35,7 +35,7 @@
 
 class StatsSocketListener : public SocketListener, public virtual android::RefBase {
 public:
-    explicit StatsSocketListener(const sp<LogListener>& listener);
+    explicit StatsSocketListener(std::shared_ptr<LogEventQueue> queue);
 
     virtual ~StatsSocketListener();
 
@@ -47,7 +47,7 @@
     /**
      * Who is going to get the events when they're read.
      */
-    sp<LogListener> mListener;
+    std::shared_ptr<LogEventQueue> mQueue;
 };
 }  // namespace statsd
 }  // namespace os
diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto
index 166e087..1dfc433 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -455,8 +455,19 @@
         optional int32 detected_time_sec = 1;
         optional int32 count = 2;
         optional int32 last_error = 3;
+        optional int32 last_tag = 4;
+        optional int32 uid = 5;
+        optional int32 pid = 6;
     }
     repeated LogLossStats detected_log_loss = 16;
+
+    message EventQueueOverflow {
+        optional int32 count = 1;
+        optional int64 max_queue_history_ns = 2;
+        optional int64 min_queue_history_ns = 3;
+    }
+
+    optional EventQueueOverflow queue_overflow = 18;
 }
 
 message AlertTriggerDetails {
diff --git a/cmds/statsd/src/storage/StorageManager.cpp b/cmds/statsd/src/storage/StorageManager.cpp
index 65b183c..cf8b974 100644
--- a/cmds/statsd/src/storage/StorageManager.cpp
+++ b/cmds/statsd/src/storage/StorageManager.cpp
@@ -36,9 +36,17 @@
 using android::util::FIELD_TYPE_MESSAGE;
 using std::map;
 
+/**
+ * NOTE: these directories are protected by SELinux, any changes here must also update
+ * the SELinux policies.
+ */
 #define STATS_DATA_DIR "/data/misc/stats-data"
 #define STATS_SERVICE_DIR "/data/misc/stats-service"
 #define TRAIN_INFO_DIR "/data/misc/train-info"
+#define TRAIN_INFO_PATH "/data/misc/train-info/train-info.bin"
+
+// Magic word at the start of the train info file, change this if changing the file format
+const uint32_t TRAIN_INFO_FILE_MAGIC = 0xff7447ff;
 
 // for ConfigMetricsReportList
 const int FIELD_ID_REPORTS = 2;
@@ -96,27 +104,42 @@
 }
 
 bool StorageManager::writeTrainInfo(int64_t trainVersionCode, const std::string& trainName,
-                                    int32_t status, const std::vector<uint8_t>& experimentIds) {
+                                    int32_t status, const std::vector<int64_t>& experimentIds) {
     std::lock_guard<std::mutex> lock(sTrainInfoMutex);
 
     deleteAllFiles(TRAIN_INFO_DIR);
 
-    string file_name = StringPrintf("%s/%lld", TRAIN_INFO_DIR, (long long)trainVersionCode);
-
-    int fd = open(file_name.c_str(), O_WRONLY | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR);
+    int fd = open(TRAIN_INFO_PATH, O_WRONLY | O_CREAT | O_CLOEXEC, S_IRUSR | S_IWUSR);
     if (fd == -1) {
-        VLOG("Attempt to access %s but failed", file_name.c_str());
+        VLOG("Attempt to access %s but failed", TRAIN_INFO_PATH);
         return false;
     }
 
     size_t result;
 
+    // Write the magic word
+    result = write(fd, &TRAIN_INFO_FILE_MAGIC, sizeof(TRAIN_INFO_FILE_MAGIC));
+    if (result != sizeof(TRAIN_INFO_FILE_MAGIC)) {
+        VLOG("Failed to wrtie train info magic");
+        close(fd);
+        return false;
+    }
+
+    // Write the train version
+    const size_t trainVersionCodeByteCount = sizeof(trainVersionCode);
+    result = write(fd, &trainVersionCode, trainVersionCodeByteCount);
+    if (result != trainVersionCodeByteCount) {
+        VLOG("Failed to wrtie train version code");
+        close(fd);
+        return false;
+    }
+
     // Write # of bytes in trainName to file
     const size_t trainNameSize = trainName.size();
     const size_t trainNameSizeByteCount = sizeof(trainNameSize);
     result = write(fd, (uint8_t*)&trainNameSize, trainNameSizeByteCount);
     if (result != trainNameSizeByteCount) {
-        VLOG("Failed to write train name size for %s", file_name.c_str());
+        VLOG("Failed to write train name size");
         close(fd);
         return false;
     }
@@ -124,7 +147,7 @@
     // Write trainName to file
     result = write(fd, trainName.c_str(), trainNameSize);
     if (result != trainNameSize) {
-        VLOG("Failed to write train name for%s", file_name.c_str());
+        VLOG("Failed to write train name");
         close(fd);
         return false;
     }
@@ -133,34 +156,38 @@
     const size_t statusByteCount = sizeof(status);
     result = write(fd, (uint8_t*)&status, statusByteCount);
     if (result != statusByteCount) {
-        VLOG("Failed to write status for %s", file_name.c_str());
+        VLOG("Failed to write status");
         close(fd);
         return false;
     }
 
-    // Write experiment id size to file.
-    const size_t experimentIdSize = experimentIds.size();
-    const size_t experimentIdsSizeByteCount = sizeof(experimentIdSize);
-    result = write(fd, (uint8_t*) &experimentIdSize, experimentIdsSizeByteCount);
-    if (result != experimentIdsSizeByteCount) {
-        VLOG("Failed to write experiment id size for %s", file_name.c_str());
+    // Write experiment id count to file.
+    const size_t experimentIdsCount = experimentIds.size();
+    const size_t experimentIdsCountByteCount = sizeof(experimentIdsCount);
+    result = write(fd, (uint8_t*) &experimentIdsCount, experimentIdsCountByteCount);
+    if (result != experimentIdsCountByteCount) {
+        VLOG("Failed to write experiment id count");
         close(fd);
         return false;
     }
 
     // Write experimentIds to file
-    result = write(fd, experimentIds.data(), experimentIds.size());
-    if (result == experimentIds.size()) {
-        VLOG("Successfully wrote %s", file_name.c_str());
-    } else {
-        VLOG("Failed to write experiment ids for %s", file_name.c_str());
-        close(fd);
-        return false;
+    for (size_t i = 0; i < experimentIdsCount; i++) {
+        const int64_t experimentId = experimentIds[i];
+        const size_t experimentIdByteCount = sizeof(experimentId);
+        result = write(fd, &experimentId, experimentIdByteCount);
+        if (result == experimentIdByteCount) {
+            VLOG("Successfully wrote experiment IDs");
+        } else {
+            VLOG("Failed to write experiment ids");
+            close(fd);
+            return false;
+        }
     }
 
     result = fchown(fd, AID_STATSD, AID_STATSD);
     if (result) {
-        VLOG("Failed to chown %s to statsd", file_name.c_str());
+        VLOG("Failed to chown train info file to statsd");
         close(fd);
         return false;
     }
@@ -172,88 +199,96 @@
 bool StorageManager::readTrainInfo(InstallTrainInfo& trainInfo) {
     std::lock_guard<std::mutex> lock(sTrainInfoMutex);
 
-    unique_ptr<DIR, decltype(&closedir)> dir(opendir(TRAIN_INFO_DIR), closedir);
-
-    if (dir == NULL) {
-        VLOG("Directory does not exist: %s", TRAIN_INFO_DIR);
+    int fd = open(TRAIN_INFO_PATH, O_RDONLY | O_CLOEXEC);
+    if (fd == -1) {
+        VLOG("Failed to open train-info.bin");
         return false;
     }
 
-    dirent* de;
-    while ((de = readdir(dir.get()))) {
-        char* name = de->d_name;
-        if (name[0] == '.') {
-            continue;
-        }
-
-        size_t result;
-
-        trainInfo.trainVersionCode = StrToInt64(name);
-        string fullPath = StringPrintf("%s/%s", TRAIN_INFO_DIR, name);
-        int fd = open(fullPath.c_str(), O_RDONLY | O_CLOEXEC);
-        if (fd == -1) {
-            return false;
-        }
-
-        // Read # of bytes taken by trainName in the file.
-        size_t trainNameSize;
-        result = read(fd, &trainNameSize, sizeof(size_t));
-        if (result != sizeof(size_t)) {
-            VLOG("Failed to read train name size from file %s", fullPath.c_str());
-            close(fd);
-            return false;
-        }
-
-        // Read trainName
-        trainInfo.trainName.resize(trainNameSize);
-        result = read(fd, trainInfo.trainName.data(), trainNameSize);
-        if (result != trainNameSize) {
-            VLOG("Failed to read train name from file %s", fullPath.c_str());
-            close(fd);
-            return false;
-        }
-
-        // Read status
-        const size_t statusByteCount = sizeof(trainInfo.status);
-        result = read(fd, &trainInfo.status, statusByteCount);
-        if (result != statusByteCount) {
-            VLOG("Failed to read train status from file %s", fullPath.c_str());
-            close(fd);
-            return false;
-        }
-
-        // Read experiment ids size.
-        size_t experimentIdSize;
-        result = read(fd, &experimentIdSize, sizeof(size_t));
-        if (result != sizeof(size_t)) {
-            VLOG("Failed to read train experiment id size from file %s", fullPath.c_str());
-            close(fd);
-            return false;
-        }
-
-        // Read experimentIds
-        trainInfo.experimentIds.resize(experimentIdSize);
-        result = read(fd, trainInfo.experimentIds.data(), experimentIdSize);
-        if (result != experimentIdSize) {
-            VLOG("Failed to read train experiment ids from file %s", fullPath.c_str());
-            close(fd);
-            return false;
-        }
-
-        // Expect to be at EOF.
-        char c;
-        result = read(fd, &c, 1);
-        if (result != 0) {
-            VLOG("Failed to read train info from file %s. Did not get expected EOF.", fullPath.c_str());
-            close(fd);
-            return false;
-        }
-
-        VLOG("Read train info file successful: %s", fullPath.c_str());
+    // Read the magic word
+    uint32_t magic;
+    size_t result = read(fd, &magic, sizeof(magic));
+    if (result != sizeof(magic)) {
+        VLOG("Failed to read train info magic");
         close(fd);
-        return true;
+        return false;
     }
-    return false;
+
+    if (magic != TRAIN_INFO_FILE_MAGIC) {
+        VLOG("Train info magic was 0x%08x, expected 0x%08x", magic, TRAIN_INFO_FILE_MAGIC);
+        close(fd);
+        return false;
+    }
+
+    // Read the train version code
+    const size_t trainVersionCodeByteCount(sizeof(trainInfo.trainVersionCode));
+    result = read(fd, &trainInfo.trainVersionCode, trainVersionCodeByteCount);
+    if (result != trainVersionCodeByteCount) {
+        VLOG("Failed to read train version code from train info file");
+        close(fd);
+        return false;
+    }
+
+    // Read # of bytes taken by trainName in the file.
+    size_t trainNameSize;
+    result = read(fd, &trainNameSize, sizeof(size_t));
+    if (result != sizeof(size_t)) {
+        VLOG("Failed to read train name size from train info file");
+        close(fd);
+        return false;
+    }
+
+    // Read trainName
+    trainInfo.trainName.resize(trainNameSize);
+    result = read(fd, trainInfo.trainName.data(), trainNameSize);
+    if (result != trainNameSize) {
+        VLOG("Failed to read train name from train info file");
+        close(fd);
+        return false;
+    }
+
+    // Read status
+    const size_t statusByteCount = sizeof(trainInfo.status);
+    result = read(fd, &trainInfo.status, statusByteCount);
+    if (result != statusByteCount) {
+        VLOG("Failed to read train status from train info file");
+        close(fd);
+        return false;
+    }
+
+    // Read experiment ids count.
+    size_t experimentIdsCount;
+    result = read(fd, &experimentIdsCount, sizeof(size_t));
+    if (result != sizeof(size_t)) {
+        VLOG("Failed to read train experiment id count from train info file");
+        close(fd);
+        return false;
+    }
+
+    // Read experimentIds
+    for (size_t i = 0; i < experimentIdsCount; i++) {
+        int64_t experimentId;
+        result = read(fd, &experimentId, sizeof(experimentId));
+        if (result != sizeof(experimentId)) {
+            VLOG("Failed to read train experiment id from train info file");
+            close(fd);
+            return false;
+        }
+        trainInfo.experimentIds.push_back(experimentId);
+    }
+
+    // Expect to be at EOF.
+    char c;
+    result = read(fd, &c, 1);
+    if (result != 0) {
+        VLOG("Failed to read train info from file. Did not get expected EOF.");
+        close(fd);
+        return false;
+    }
+
+    VLOG("Read train info file successful");
+    close(fd);
+    return true;
 }
 
 void StorageManager::deleteFile(const char* file) {
diff --git a/cmds/statsd/src/storage/StorageManager.h b/cmds/statsd/src/storage/StorageManager.h
index 88280cf..dfcea65 100644
--- a/cmds/statsd/src/storage/StorageManager.h
+++ b/cmds/statsd/src/storage/StorageManager.h
@@ -29,11 +29,6 @@
 
 using android::util::ProtoOutputStream;
 
-struct TrainInfo {
-    int64_t trainVersionCode;
-    std::vector<uint8_t> experimentIds;
-};
-
 class StorageManager : public virtual RefBase {
 public:
     /**
@@ -45,7 +40,7 @@
      * Writes train info.
      */
     static bool writeTrainInfo(int64_t trainVersionCode, const std::string& trainName,
-                               int32_t status, const std::vector<uint8_t>& experimentIds);
+                               int32_t status, const std::vector<int64_t>& experimentIds);
 
     /**
      * Reads train info.
diff --git a/cmds/statsd/tests/LogEvent_test.cpp b/cmds/statsd/tests/LogEvent_test.cpp
index b03517e..504ee22 100644
--- a/cmds/statsd/tests/LogEvent_test.cpp
+++ b/cmds/statsd/tests/LogEvent_test.cpp
@@ -645,6 +645,22 @@
     EXPECT_EQ(orig_str, result_str);
 }
 
+TEST(LogEventTest, TestWriteExperimentIdsToProto) {
+    std::vector<int64_t> expIds;
+    expIds.push_back(5038);
+    std::vector<uint8_t> proto;
+
+    writeExperimentIdsToProto(expIds, &proto);
+
+    EXPECT_EQ(proto.size(), 3);
+    // Proto wire format for field ID 1, varint
+    EXPECT_EQ(proto[0], 0x08);
+    // varint of 5038, 2 bytes long
+    EXPECT_EQ(proto[1], 0xae);
+    EXPECT_EQ(proto[2], 0x27);
+}
+
+
 }  // namespace statsd
 }  // namespace os
 }  // namespace android
diff --git a/cmds/statsd/tests/StatsService_test.cpp b/cmds/statsd/tests/StatsService_test.cpp
index 560fb9f..7c00531 100644
--- a/cmds/statsd/tests/StatsService_test.cpp
+++ b/cmds/statsd/tests/StatsService_test.cpp
@@ -33,7 +33,7 @@
 #ifdef __ANDROID__
 
 TEST(StatsServiceTest, TestAddConfig_simple) {
-    StatsService service(nullptr);
+    StatsService service(nullptr, nullptr);
     StatsdConfig config;
     config.set_id(12345);
     string serialized = config.SerializeAsString();
@@ -43,7 +43,7 @@
 }
 
 TEST(StatsServiceTest, TestAddConfig_empty) {
-    StatsService service(nullptr);
+    StatsService service(nullptr, nullptr);
     string serialized = "";
 
     EXPECT_TRUE(
@@ -51,7 +51,7 @@
 }
 
 TEST(StatsServiceTest, TestAddConfig_invalid) {
-    StatsService service(nullptr);
+    StatsService service(nullptr, nullptr);
     string serialized = "Invalid config!";
 
     EXPECT_FALSE(
@@ -69,7 +69,7 @@
 
     int32_t uid;
 
-    StatsService service(nullptr);
+    StatsService service(nullptr, nullptr);
     service.mEngBuild = true;
 
     // "-1"
diff --git a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
index 3dff7f5..309d251 100644
--- a/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/PartialBucket_e2e_test.cpp
@@ -111,7 +111,7 @@
 }
 
 TEST(PartialBucketE2eTest, TestCountMetricWithoutSplit) {
-    StatsService service(nullptr);
+    StatsService service(nullptr, nullptr);
     SendConfig(service, MakeConfig());
     int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
                                              // initialized with.
@@ -126,7 +126,7 @@
 }
 
 TEST(PartialBucketE2eTest, TestCountMetricNoSplitOnNewApp) {
-    StatsService service(nullptr);
+    StatsService service(nullptr, nullptr);
     SendConfig(service, MakeConfig());
     int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
                                              // initialized with.
@@ -146,7 +146,7 @@
 }
 
 TEST(PartialBucketE2eTest, TestCountMetricSplitOnUpgrade) {
-    StatsService service(nullptr);
+    StatsService service(nullptr, nullptr);
     SendConfig(service, MakeConfig());
     int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
                                              // initialized with.
@@ -171,7 +171,7 @@
 }
 
 TEST(PartialBucketE2eTest, TestCountMetricSplitOnRemoval) {
-    StatsService service(nullptr);
+    StatsService service(nullptr, nullptr);
     SendConfig(service, MakeConfig());
     int64_t start = getElapsedRealtimeNs();  // This is the start-time the metrics producers are
                                              // initialized with.
@@ -195,7 +195,7 @@
 }
 
 TEST(PartialBucketE2eTest, TestValueMetricWithoutMinPartialBucket) {
-    StatsService service(nullptr);
+    StatsService service(nullptr, nullptr);
     // Partial buckets don't occur when app is first installed.
     service.mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1, String16("v1"), String16(""));
     SendConfig(service, MakeValueMetricConfig(0));
@@ -213,7 +213,7 @@
 }
 
 TEST(PartialBucketE2eTest, TestValueMetricWithMinPartialBucket) {
-    StatsService service(nullptr);
+    StatsService service(nullptr, nullptr);
     // Partial buckets don't occur when app is first installed.
     service.mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1, String16("v1"), String16(""));
     SendConfig(service, MakeValueMetricConfig(60 * NS_PER_SEC /* One minute */));
@@ -237,7 +237,7 @@
 }
 
 TEST(PartialBucketE2eTest, TestGaugeMetricWithoutMinPartialBucket) {
-    StatsService service(nullptr);
+    StatsService service(nullptr, nullptr);
     // Partial buckets don't occur when app is first installed.
     service.mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1, String16("v1"), String16(""));
     SendConfig(service, MakeGaugeMetricConfig(0));
@@ -255,7 +255,7 @@
 }
 
 TEST(PartialBucketE2eTest, TestGaugeMetricWithMinPartialBucket) {
-    StatsService service(nullptr);
+    StatsService service(nullptr, nullptr);
     // Partial buckets don't occur when app is first installed.
     service.mUidMap->updateApp(1, String16(kApp1.c_str()), 1, 1, String16("v1"), String16(""));
     SendConfig(service, MakeGaugeMetricConfig(60 * NS_PER_SEC /* One minute */));
diff --git a/cmds/statsd/tests/log_event/LogEventQueue_test.cpp b/cmds/statsd/tests/log_event/LogEventQueue_test.cpp
new file mode 100644
index 0000000..f27d129
--- /dev/null
+++ b/cmds/statsd/tests/log_event/LogEventQueue_test.cpp
@@ -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.
+
+#include "logd/LogEventQueue.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <thread>
+
+#include <stdio.h>
+
+namespace android {
+namespace os {
+namespace statsd {
+
+using namespace android;
+using namespace testing;
+
+using std::unique_ptr;
+
+#ifdef __ANDROID__
+TEST(LogEventQueue_test, TestGoodConsumer) {
+    LogEventQueue queue(50);
+    int64_t timeBaseNs = 100;
+    std::thread writer([&queue, timeBaseNs] {
+        for (int i = 0; i < 100; i++) {
+            int64_t oldestEventNs;
+            bool success = queue.push(std::make_unique<LogEvent>(10, timeBaseNs + i * 1000),
+                                      &oldestEventNs);
+            EXPECT_TRUE(success);
+            std::this_thread::sleep_for(std::chrono::milliseconds(1));
+        }
+    });
+
+    std::thread reader([&queue, timeBaseNs] {
+        for (int i = 0; i < 100; i++) {
+            auto event = queue.waitPop();
+            EXPECT_TRUE(event != nullptr);
+            // All events are in right order.
+            EXPECT_EQ(timeBaseNs + i * 1000, event->GetElapsedTimestampNs());
+        }
+    });
+
+    reader.join();
+    writer.join();
+}
+
+TEST(LogEventQueue_test, TestSlowConsumer) {
+    LogEventQueue queue(50);
+    int64_t timeBaseNs = 100;
+    std::thread writer([&queue, timeBaseNs] {
+        int failure_count = 0;
+        int64_t oldestEventNs;
+        for (int i = 0; i < 100; i++) {
+            bool success = queue.push(std::make_unique<LogEvent>(10, timeBaseNs + i * 1000),
+                                      &oldestEventNs);
+            if (!success) failure_count++;
+            std::this_thread::sleep_for(std::chrono::milliseconds(1));
+        }
+
+        // There is some remote chance that reader thread not get chance to run before writer thread
+        // ends. That's why the following comparison is not "==".
+        // There will be at least 45 events lost due to overflow.
+        EXPECT_TRUE(failure_count >= 45);
+        // The oldest event must be at least the 6th event.
+        EXPECT_TRUE(oldestEventNs <= (100 + 5 * 1000));
+    });
+
+    std::thread reader([&queue, timeBaseNs] {
+        // The consumer quickly processed 5 events, then it got stuck (not reading anymore).
+        for (int i = 0; i < 5; i++) {
+            auto event = queue.waitPop();
+            EXPECT_TRUE(event != nullptr);
+            // All events are in right order.
+            EXPECT_EQ(timeBaseNs + i * 1000, event->GetElapsedTimestampNs());
+        }
+    });
+
+    reader.join();
+    writer.join();
+}
+
+#else
+GTEST_LOG_(INFO) << "This test does nothing.\n";
+#endif
+
+}  // namespace statsd
+}  // namespace os
+}  // namespace android
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index 2ef0856..8ec5e3a 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -27,6 +27,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.Insets;
+import android.graphics.Region;
 import android.hardware.display.DisplayManager;
 import android.hardware.display.VirtualDisplay;
 import android.hardware.input.InputManager;
@@ -46,6 +47,7 @@
 import android.view.SurfaceView;
 import android.view.View;
 import android.view.ViewGroup;
+import android.view.ViewParent;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
 
@@ -81,6 +83,9 @@
     // Temp container to store view coordinates in window.
     private final int[] mLocationInWindow = new int[2];
 
+    // The latest tap exclude region that we've sent to WM.
+    private final Region mTapExcludeRegion = new Region();
+
     private TaskStackListener mTaskStackListener;
 
     private final CloseGuard mGuard = CloseGuard.get();
@@ -279,11 +284,11 @@
     }
 
     /**
-     * Triggers an update of {@link ActivityView}'s location in window to properly set touch exclude
+     * Triggers an update of {@link ActivityView}'s location in window to properly set tap exclude
      * regions and avoid focus switches by touches on this view.
      */
     public void onLocationChanged() {
-        updateLocation();
+        updateTapExcludeRegion();
     }
 
     @Override
@@ -291,15 +296,38 @@
         mSurfaceView.layout(0 /* left */, 0 /* top */, r - l /* right */, b - t /* bottom */);
     }
 
-    /** Send current location and size to the WM to set tap exclude region for this view. */
-    private void updateLocation() {
+    @Override
+    public boolean gatherTransparentRegion(Region region) {
+        // The tap exclude region may be affected by any view on top of it, so we detect the
+        // possible change by monitoring this function.
+        updateTapExcludeRegion();
+        return super.gatherTransparentRegion(region);
+    }
+
+    /** Compute and send current tap exclude region to WM for this view. */
+    private void updateTapExcludeRegion() {
         if (!isAttachedToWindow()) {
             return;
         }
+        if (!canReceivePointerEvents()) {
+            cleanTapExcludeRegion();
+            return;
+        }
         try {
             getLocationInWindow(mLocationInWindow);
+            final int x = mLocationInWindow[0];
+            final int y = mLocationInWindow[1];
+            mTapExcludeRegion.set(x, y, x + getWidth(), y + getHeight());
+
+            // There might be views on top of us. We need to subtract those areas from the tap
+            // exclude region.
+            final ViewParent parent = getParent();
+            if (parent instanceof ViewGroup) {
+                ((ViewGroup) parent).subtractObscuredTouchableRegion(mTapExcludeRegion, this);
+            }
+
             WindowManagerGlobal.getWindowSession().updateTapExcludeRegion(getWindow(), hashCode(),
-                    mLocationInWindow[0], mLocationInWindow[1], getWidth(), getHeight());
+                    mTapExcludeRegion);
         } catch (RemoteException e) {
             e.rethrowAsRuntimeException();
         }
@@ -322,7 +350,7 @@
                 mVirtualDisplay.setDisplayState(true);
             }
 
-            updateLocation();
+            updateTapExcludeRegion();
         }
 
         @Override
@@ -330,7 +358,7 @@
             if (mVirtualDisplay != null) {
                 mVirtualDisplay.resize(width, height, getBaseDisplayDensity());
             }
-            updateLocation();
+            updateTapExcludeRegion();
         }
 
         @Override
@@ -460,13 +488,14 @@
 
     /** Report to server that tap exclude region on hosting display should be cleared. */
     private void cleanTapExcludeRegion() {
-        if (!isAttachedToWindow()) {
+        if (!isAttachedToWindow() || mTapExcludeRegion.isEmpty()) {
             return;
         }
-        // Update tap exclude region with an empty rect to clean the state on server.
+        // Update tap exclude region with a null region to clean the state on server.
         try {
             WindowManagerGlobal.getWindowSession().updateTapExcludeRegion(getWindow(), hashCode(),
-                    0 /* left */, 0 /* top */, 0 /* width */, 0 /* height */);
+                    null /* region */);
+            mTapExcludeRegion.setEmpty();
         } catch (RemoteException e) {
             e.rethrowAsRuntimeException();
         }
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 16fe7db..65f1080 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -346,6 +346,9 @@
     void unregisterUserSwitchObserver(in IUserSwitchObserver observer);
     int[] getRunningUserIds();
 
+    // Request a heap dump for the system server.
+    void requestSystemServerHeapDump();
+
     // Deprecated - This method is only used by a few internal components and it will soon be
     // replaced by a proper bug report API (which will be restricted to a few, pre-defined apps).
     // No new code should be calling it.
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index d634aa5..11fa343 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -16,12 +16,14 @@
 
 package android.app;
 
+import static android.annotation.Dimension.DP;
 import static android.graphics.drawable.Icon.TYPE_BITMAP;
 
 import static com.android.internal.util.ContrastColorUtil.satisfiesTextContrast;
 
 import android.annotation.ColorInt;
 import android.annotation.DimenRes;
+import android.annotation.Dimension;
 import android.annotation.DrawableRes;
 import android.annotation.IdRes;
 import android.annotation.IntDef;
@@ -615,6 +617,13 @@
      */
     public static final int FLAG_CAN_COLORIZE = 0x00000800;
 
+    /**
+     * Bit to be bitswised-ored into the {@link #flags} field that should be
+     * set if this notification can be shown as a bubble.
+     * @hide
+     */
+    public static final int FLAG_BUBBLE = 0x00001000;
+
     public int flags;
 
     /** @hide */
@@ -6241,6 +6250,15 @@
         return false;
     }
 
+    /**
+     * @return true if this is a notification that can show as a bubble.
+     *
+     * @hide
+     */
+    public boolean isBubbleNotification() {
+        return (flags & Notification.FLAG_BUBBLE) != 0;
+    }
+
     private boolean hasLargeIcon() {
         return mLargeIcon != null || largeIcon != null;
     }
@@ -8594,15 +8612,18 @@
 
         /**
          * @return the ideal height, in DPs, for the floating window that app content defined by
-         * {@link #getIntent()} for this bubble.
+         * {@link #getIntent()} for this bubble. A value of 0 indicates a desired height has not
+         * been set.
          */
+        @Dimension(unit = DP)
         public int getDesiredHeight() {
             return mDesiredHeight;
         }
 
         /**
          * @return the resId of ideal height for the floating window that app content defined by
-         * {@link #getIntent()} for this bubble.
+         * {@link #getIntent()} for this bubble. A value of 0 indicates a res value has not
+         * been provided for the desired height.
          */
         @DimenRes
         public int getDesiredHeightResId() {
@@ -8733,7 +8754,7 @@
              * be used instead.
              */
             @NonNull
-            public BubbleMetadata.Builder setDesiredHeight(int height) {
+            public BubbleMetadata.Builder setDesiredHeight(@Dimension(unit = DP) int height) {
                 mDesiredHeight = Math.max(height, 0);
                 mDesiredHeightResId = 0;
                 return this;
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index 5cdf85a..69ec831 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -170,6 +170,7 @@
     private boolean mBlockableSystem = false;
     private boolean mAllowBubbles = DEFAULT_ALLOW_BUBBLE;
     private boolean mImportanceLockedByOEM;
+    private boolean mImportanceLockedDefaultApp;
 
     /**
      * Creates a notification channel.
@@ -656,11 +657,27 @@
      * @hide
      */
     @TestApi
+    public void setImportanceLockedByCriticalDeviceFunction(boolean locked) {
+        mImportanceLockedDefaultApp = locked;
+    }
+
+    /**
+     * @hide
+     */
+    @TestApi
     public boolean isImportanceLockedByOEM() {
         return mImportanceLockedByOEM;
     }
 
     /**
+     * @hide
+     */
+    @TestApi
+    public boolean isImportanceLockedByCriticalDeviceFunction() {
+        return mImportanceLockedDefaultApp;
+    }
+
+    /**
      * Returns whether the user has chosen the importance of this channel, either to affirm the
      * initial selection from the app, or changed it to be higher or lower.
      * @see #getImportance()
@@ -834,6 +851,9 @@
             out.attribute(null, ATT_ALLOW_BUBBLE, Boolean.toString(canBubble()));
         }
 
+        // mImportanceLockedDefaultApp and mImportanceLockedByOEM have a different source of
+        // truth and so aren't written to this xml file
+
         out.endTag(null, TAG_CHANNEL);
     }
 
@@ -942,7 +962,8 @@
         return sb.toString();
     }
 
-    public static final @android.annotation.NonNull Creator<NotificationChannel> CREATOR = new Creator<NotificationChannel>() {
+    public static final @android.annotation.NonNull Creator<NotificationChannel> CREATOR =
+            new Creator<NotificationChannel>() {
         @Override
         public NotificationChannel createFromParcel(Parcel in) {
             return new NotificationChannel(in);
@@ -983,7 +1004,8 @@
                 && Arrays.equals(mVibration, that.mVibration)
                 && Objects.equals(getGroup(), that.getGroup())
                 && Objects.equals(getAudioAttributes(), that.getAudioAttributes())
-                && mImportanceLockedByOEM == that.mImportanceLockedByOEM;
+                && mImportanceLockedByOEM == that.mImportanceLockedByOEM
+                && mImportanceLockedDefaultApp == that.mImportanceLockedDefaultApp;
     }
 
     @Override
@@ -993,7 +1015,7 @@
                 getUserLockedFields(),
                 isFgServiceShown(), mVibrationEnabled, mShowBadge, isDeleted(), getGroup(),
                 getAudioAttributes(), isBlockableSystem(), mAllowBubbles,
-                mImportanceLockedByOEM);
+                mImportanceLockedByOEM, mImportanceLockedDefaultApp);
         result = 31 * result + Arrays.hashCode(mVibration);
         return result;
     }
@@ -1022,6 +1044,7 @@
                 + ", mBlockableSystem=" + mBlockableSystem
                 + ", mAllowBubbles=" + mAllowBubbles
                 + ", mImportanceLockedByOEM=" + mImportanceLockedByOEM
+                + ", mImportanceLockedDefaultApp=" + mImportanceLockedDefaultApp
                 + '}';
         pw.println(prefix + output);
     }
@@ -1049,6 +1072,7 @@
                 + ", mBlockableSystem=" + mBlockableSystem
                 + ", mAllowBubbles=" + mAllowBubbles
                 + ", mImportanceLockedByOEM=" + mImportanceLockedByOEM
+                + ", mImportanceLockedDefaultApp=" + mImportanceLockedDefaultApp
                 + '}';
     }
 
diff --git a/core/java/android/app/StatsManager.java b/core/java/android/app/StatsManager.java
index 7746148..2e14d03 100644
--- a/core/java/android/app/StatsManager.java
+++ b/core/java/android/app/StatsManager.java
@@ -18,6 +18,7 @@
 import static android.Manifest.permission.DUMP;
 import static android.Manifest.permission.PACKAGE_USAGE_STATS;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
@@ -295,7 +296,7 @@
      * @throws StatsUnavailableException if unsuccessful due to failing to connect to stats service
      */
     @RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
-    public long[] setActiveConfigsChangedOperation(@Nullable PendingIntent pendingIntent)
+    public @NonNull long[] setActiveConfigsChangedOperation(@Nullable PendingIntent pendingIntent)
             throws StatsUnavailableException {
         synchronized (this) {
             try {
@@ -410,6 +411,36 @@
     }
 
     /**
+     * Returns the experiments IDs registered with statsd, or an empty array if there aren't any.
+     *
+     * @throws StatsUnavailableException if unsuccessful due to failing to connect to stats service
+     * @hide
+     */
+    @RequiresPermission(allOf = {DUMP, PACKAGE_USAGE_STATS})
+    public long[] getRegisteredExperimentIds()
+            throws StatsUnavailableException {
+        synchronized (this) {
+            try {
+                IStatsManager service = getIStatsManagerLocked();
+                if (service == null) {
+                    if (DEBUG) {
+                        Slog.d(TAG, "Failed to find statsd when getting experiment IDs");
+                    }
+                    return new long[0];
+                }
+                return service.getRegisteredExperimentIds();
+            } catch (RemoteException e) {
+                if (DEBUG) {
+                    Slog.d(TAG,
+                            "Failed to connect to StatsCompanionService when getting "
+                                    + "registered experiment IDs");
+                }
+                return new long[0];
+            }
+        }
+    }
+
+    /**
      * Registers a callback for an atom when that atom is to be pulled. The stats service will
      * invoke pullData in the callback when the stats service determines that this atom needs to be
      * pulled. Currently, this only works for atoms with tags above 100,000 that do not have a uid.
diff --git a/core/java/android/app/usage/EventList.java b/core/java/android/app/usage/EventList.java
index aaae57e5..8c03405 100644
--- a/core/java/android/app/usage/EventList.java
+++ b/core/java/android/app/usage/EventList.java
@@ -103,4 +103,18 @@
         }
         return result;
     }
+
+    /**
+     * Merge the {@link UsageEvents.Event events} in the given {@link EventList list} into this
+     * list while keeping the list sorted based on the event {@link
+     * UsageEvents.Event#mTimeStamp timestamps}.
+     *
+     * @param events The event list to merge
+     */
+    public void merge(EventList events) {
+        final int size = events.size();
+        for (int i = 0; i < size; i++) {
+            insert(events.get(i));
+        }
+    }
 }
diff --git a/core/java/android/content/ContentCaptureOptions.java b/core/java/android/content/ContentCaptureOptions.java
index 1727d34..76c4fb8 100644
--- a/core/java/android/content/ContentCaptureOptions.java
+++ b/core/java/android/content/ContentCaptureOptions.java
@@ -136,13 +136,18 @@
     @Override
     public String toString() {
         if (lite) {
-            return "ContentCaptureOptions [(lite) loggingLevel=" + loggingLevel + "]";
+            return "ContentCaptureOptions [loggingLevel=" + loggingLevel + " (lite)]";
         }
-        return "ContentCaptureOptions [loggingLevel=" + loggingLevel + ", maxBufferSize="
-                + maxBufferSize + ", idleFlushingFrequencyMs=" + idleFlushingFrequencyMs
-                + ", textChangeFlushingFrequencyMs=" + textChangeFlushingFrequencyMs
-                + ", logHistorySize=" + logHistorySize + ", whitelistedComponents="
-                + whitelistedComponents + "]";
+        final StringBuilder string = new StringBuilder("ContentCaptureOptions [");
+        string.append("loggingLevel=").append(loggingLevel)
+            .append(", maxBufferSize=").append(maxBufferSize)
+            .append(", idleFlushingFrequencyMs=").append(idleFlushingFrequencyMs)
+            .append(", textChangeFlushingFrequencyMs=").append(textChangeFlushingFrequencyMs)
+            .append(", logHistorySize=").append(logHistorySize);
+        if (whitelistedComponents != null) {
+            string.append(", whitelisted=").append(whitelistedComponents);
+        }
+        return string.append(']').toString();
     }
 
     /** @hide */
diff --git a/core/java/android/content/LocusId.java b/core/java/android/content/LocusId.java
index c67ff7c..283cea0 100644
--- a/core/java/android/content/LocusId.java
+++ b/core/java/android/content/LocusId.java
@@ -18,19 +18,50 @@
 import android.annotation.NonNull;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.view.contentcapture.ContentCaptureManager;
 
 import com.android.internal.util.Preconditions;
 
 import java.io.PrintWriter;
 
 /**
- * Identifier for an unique state in the application.
+ * An identifier for an unique state (locus) in the application. Should be stable across reboots and
+ * backup / restore.
  *
- * <p>Should be stable across reboots and backup / restore.
+ * <p>Locus is a new concept introduced on
+ * {@link android.os.Build.VERSION_CODES#Q Android Q} and it lets the intelligence service provided
+ * by the Android System to correlate state between different subsystems such as content capture,
+ * shortcuts, and notifications.
  *
- * <p>For example, a chat app could use the context to resume a conversation between 2 users.
+ * <p>For example, if your app provides an activiy representing a chat between 2 users
+ * (say {@code A} and {@code B}, this chat state could be represented by:
+ *
+ * <pre><code>
+ * LocusId chatId = new LocusId("Chat_A_B");
+ * </code></pre>
+ *
+ * <p>And then you should use that {@code chatId} by:
+ *
+ * <ul>
+ *   <li>Setting it in the chat notification (through
+ *   {@link android.app.Notification.Builder#setLocusId(LocusId)
+ *   Notification.Builder.setLocusId(chatId)}).
+ *   <li>Setting it into the {@link android.content.pm.ShortcutInfo} (through
+ *   {@link android.content.pm.ShortcutInfo.Builder#setLocusId(LocusId)
+ *   ShortcutInfo.Builder.setLocusId(chatId)}), if you provide a launcher shortcut for that chat
+ *   conversation.
+ *   <li>Associating it with the {@link android.view.contentcapture.ContentCaptureContext} of the
+ *   root view of the chat conversation activity (through
+ *   {@link android.view.View#getContentCaptureSession()}, then
+ *   {@link android.view.contentcapture.ContentCaptureContext.Builder
+ *   new ContentCaptureContext.Builder(chatId).build()} and
+ *   {@link android.view.contentcapture.ContentCaptureSession#setContentCaptureContext(
+ *   android.view.contentcapture.ContentCaptureContext)} - see {@link ContentCaptureManager}
+ *   for more info about content capture).
+ *   <li>Configuring your app to launch the chat conversation through the
+ *   {@link Intent#ACTION_VIEW_LOCUS} intent.
+ * </ul>
  */
-// TODO(b/123577059): make sure this is well documented and understandable
 public final class LocusId implements Parcelable {
 
     private final String mId;
@@ -45,7 +76,7 @@
     }
 
     /**
-     * Gets the {@code id} associated with the locus.
+     * Gets the canonical {@code id} associated with the locus.
      */
     @NonNull
     public String getId() {
@@ -100,7 +131,7 @@
         parcel.writeString(mId);
     }
 
-    public static final @android.annotation.NonNull Parcelable.Creator<LocusId> CREATOR =
+    public static final @NonNull Parcelable.Creator<LocusId> CREATOR =
             new Parcelable.Creator<LocusId>() {
 
         @NonNull
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index b190b34..cf2ae7d 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -3214,7 +3214,8 @@
      * @throws NameNotFoundException if a package with the given name cannot be
      *             found on the system.
      */
-    public abstract PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags)
+    public abstract PackageInfo getPackageInfo(@NonNull String packageName,
+            @PackageInfoFlags int flags)
             throws NameNotFoundException;
 
     /**
@@ -3239,7 +3240,7 @@
      * @throws NameNotFoundException if a package with the given name cannot be
      *             found on the system.
      */
-    public abstract PackageInfo getPackageInfo(VersionedPackage versionedPackage,
+    public abstract PackageInfo getPackageInfo(@NonNull VersionedPackage versionedPackage,
             @PackageInfoFlags int flags) throws NameNotFoundException;
 
     /**
@@ -3263,25 +3264,25 @@
      */
     @RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS)
     @UnsupportedAppUsage
-    public abstract PackageInfo getPackageInfoAsUser(String packageName,
+    public abstract PackageInfo getPackageInfoAsUser(@NonNull String packageName,
             @PackageInfoFlags int flags, @UserIdInt int userId) throws NameNotFoundException;
 
     /**
      * Map from the current package names in use on the device to whatever
      * the current canonical name of that package is.
-     * @param names Array of current names to be mapped.
+     * @param packageNames Array of current names to be mapped.
      * @return Returns an array of the same size as the original, containing
      * the canonical name for each package.
      */
-    public abstract String[] currentToCanonicalPackageNames(String[] names);
+    public abstract String[] currentToCanonicalPackageNames(@NonNull String[] packageNames);
 
     /**
      * Map from a packages canonical name to the current name in use on the device.
-     * @param names Array of new names to be mapped.
+     * @param packageNames Array of new names to be mapped.
      * @return Returns an array of the same size as the original, containing
      * the current name for each package.
      */
-    public abstract String[] canonicalToCurrentPackageNames(String[] names);
+    public abstract String[] canonicalToCurrentPackageNames(@NonNull String[] packageNames);
 
     /**
      * Returns a "good" intent to launch a front-door activity in a package.
@@ -3360,7 +3361,7 @@
      * @throws NameNotFoundException if a package with the given name cannot be
      *             found on the system.
      */
-    public abstract int[] getPackageGids(String packageName, @PackageInfoFlags int flags)
+    public abstract int[] getPackageGids(@NonNull String packageName, @PackageInfoFlags int flags)
             throws NameNotFoundException;
 
     /**
@@ -3375,7 +3376,7 @@
      * @throws NameNotFoundException if a package with the given name can not be
      *             found on the system.
      */
-    public abstract int getPackageUid(String packageName, @PackageInfoFlags int flags)
+    public abstract int getPackageUid(@NonNull String packageName, @PackageInfoFlags int flags)
             throws NameNotFoundException;
 
     /**
@@ -3393,7 +3394,7 @@
      * @hide
      */
     @UnsupportedAppUsage
-    public abstract int getPackageUidAsUser(String packageName, @UserIdInt int userId)
+    public abstract int getPackageUidAsUser(@NonNull String packageName, @UserIdInt int userId)
             throws NameNotFoundException;
 
     /**
@@ -3411,13 +3412,13 @@
      * @hide
      */
     @UnsupportedAppUsage
-    public abstract int getPackageUidAsUser(String packageName, @PackageInfoFlags int flags,
-            @UserIdInt int userId) throws NameNotFoundException;
+    public abstract int getPackageUidAsUser(@NonNull String packageName,
+            @PackageInfoFlags int flags, @UserIdInt int userId) throws NameNotFoundException;
 
     /**
      * Retrieve all of the information we know about a particular permission.
      *
-     * @param name The fully qualified name (i.e. com.google.permission.LOGIN)
+     * @param permissionName The fully qualified name (i.e. com.google.permission.LOGIN)
      *            of the permission you are interested in.
      * @param flags Additional option flags to modify the data returned.
      * @return Returns a {@link PermissionInfo} containing information about the
@@ -3425,13 +3426,13 @@
      * @throws NameNotFoundException if a package with the given name cannot be
      *             found on the system.
      */
-    public abstract PermissionInfo getPermissionInfo(String name, @PermissionInfoFlags int flags)
-            throws NameNotFoundException;
+    public abstract PermissionInfo getPermissionInfo(@NonNull String permissionName,
+            @PermissionInfoFlags int flags) throws NameNotFoundException;
 
     /**
      * Query for all of the permissions associated with a particular group.
      *
-     * @param group The fully qualified name (i.e. com.google.permission.LOGIN)
+     * @param permissionGroup The fully qualified name (i.e. com.google.permission.LOGIN)
      *            of the permission group you are interested in. Use null to
      *            find all of the permissions not associated with a group.
      * @param flags Additional option flags to modify the data returned.
@@ -3440,7 +3441,8 @@
      * @throws NameNotFoundException if a package with the given name cannot be
      *             found on the system.
      */
-    public abstract List<PermissionInfo> queryPermissionsByGroup(String group,
+    @NonNull
+    public abstract List<PermissionInfo> queryPermissionsByGroup(@NonNull String permissionGroup,
             @PermissionInfoFlags int flags) throws NameNotFoundException;
 
     /**
@@ -3465,7 +3467,7 @@
      * Retrieve all of the information we know about a particular group of
      * permissions.
      *
-     * @param name The fully qualified name (i.e.
+     * @param permissionName The fully qualified name (i.e.
      *            com.google.permission_group.APPS) of the permission you are
      *            interested in.
      * @param flags Additional option flags to modify the data returned.
@@ -3474,7 +3476,8 @@
      * @throws NameNotFoundException if a package with the given name cannot be
      *             found on the system.
      */
-    public abstract PermissionGroupInfo getPermissionGroupInfo(String name,
+    @NonNull
+    public abstract PermissionGroupInfo getPermissionGroupInfo(@NonNull String permissionName,
             @PermissionGroupInfoFlags int flags) throws NameNotFoundException;
 
     /**
@@ -3484,6 +3487,7 @@
      * @return Returns a list of {@link PermissionGroupInfo} containing
      *         information about all of the known permission groups.
      */
+    @NonNull
     public abstract List<PermissionGroupInfo> getAllPermissionGroups(
             @PermissionGroupInfoFlags int flags);
 
@@ -3504,12 +3508,14 @@
      * @throws NameNotFoundException if a package with the given name cannot be
      *             found on the system.
      */
-    public abstract ApplicationInfo getApplicationInfo(String packageName,
+    @NonNull
+    public abstract ApplicationInfo getApplicationInfo(@NonNull String packageName,
             @ApplicationInfoFlags int flags) throws NameNotFoundException;
 
     /** {@hide} */
+    @NonNull
     @UnsupportedAppUsage
-    public abstract ApplicationInfo getApplicationInfoAsUser(String packageName,
+    public abstract ApplicationInfo getApplicationInfoAsUser(@NonNull String packageName,
             @ApplicationInfoFlags int flags, @UserIdInt int userId) throws NameNotFoundException;
 
     /**
@@ -3552,7 +3558,8 @@
      * @throws NameNotFoundException if a package with the given name cannot be
      *             found on the system.
      */
-    public abstract ActivityInfo getActivityInfo(ComponentName component,
+    @NonNull
+    public abstract ActivityInfo getActivityInfo(@NonNull ComponentName component,
             @ComponentInfoFlags int flags) throws NameNotFoundException;
 
     /**
@@ -3568,7 +3575,8 @@
      * @throws NameNotFoundException if a package with the given name cannot be
      *             found on the system.
      */
-    public abstract ActivityInfo getReceiverInfo(ComponentName component,
+    @NonNull
+    public abstract ActivityInfo getReceiverInfo(@NonNull ComponentName component,
             @ComponentInfoFlags int flags) throws NameNotFoundException;
 
     /**
@@ -3583,7 +3591,8 @@
      * @throws NameNotFoundException if a package with the given name cannot be
      *             found on the system.
      */
-    public abstract ServiceInfo getServiceInfo(ComponentName component,
+    @NonNull
+    public abstract ServiceInfo getServiceInfo(@NonNull ComponentName component,
             @ComponentInfoFlags int flags) throws NameNotFoundException;
 
     /**
@@ -3599,7 +3608,8 @@
      * @throws NameNotFoundException if a package with the given name cannot be
      *             found on the system.
      */
-    public abstract ProviderInfo getProviderInfo(ComponentName component,
+    @NonNull
+    public abstract ProviderInfo getProviderInfo(@NonNull ComponentName component,
             @ComponentInfoFlags int flags) throws NameNotFoundException;
 
     /**
@@ -3612,7 +3622,8 @@
      * @throws NameNotFoundException if a module with the given name cannot be
      *             found on the system.
      */
-    public ModuleInfo getModuleInfo(String packageName, @ModuleInfoFlags int flags)
+    @NonNull
+    public ModuleInfo getModuleInfo(@NonNull String packageName, @ModuleInfoFlags int flags)
             throws NameNotFoundException {
         throw new UnsupportedOperationException(
                 "getModuleInfo not implemented in subclass");
@@ -3626,7 +3637,8 @@
      *         module, containing information about the module. In the unlikely case
      *         there are no installed modules, an empty list is returned.
      */
-    public @NonNull List<ModuleInfo> getInstalledModules(@ModuleInfoFlags int flags) {
+    @NonNull
+    public List<ModuleInfo> getInstalledModules(@ModuleInfoFlags int flags) {
         throw new UnsupportedOperationException(
                 "getInstalledModules not implemented in subclass");
     }
@@ -3644,6 +3656,7 @@
      *         applications with data directory i.e. applications which had been
      *         deleted with {@code DONT_DELETE_DATA} flag set).
      */
+    @NonNull
     public abstract List<PackageInfo> getInstalledPackages(@PackageInfoFlags int flags);
 
     /**
@@ -3661,8 +3674,9 @@
      *         applications with data directory i.e. applications which had been
      *         deleted with {@code DONT_DELETE_DATA} flag set).
      */
+    @NonNull
     public abstract List<PackageInfo> getPackagesHoldingPermissions(
-            String[] permissions, @PackageInfoFlags int flags);
+            @NonNull String[] permissions, @PackageInfoFlags int flags);
 
     /**
      * Return a List of all packages that are installed on the device, for a
@@ -3680,6 +3694,7 @@
      *         deleted with {@code DONT_DELETE_DATA} flag set).
      * @hide
      */
+    @NonNull
     @TestApi
     @SystemApi
     @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL)
@@ -3690,8 +3705,8 @@
      * Check whether a particular package has been granted a particular
      * permission.
      *
-     * @param permName The name of the permission you are checking for.
-     * @param pkgName The name of the package you are checking against.
+     * @param permissionName The name of the permission you are checking for.
+     * @param packageName The name of the package you are checking against.
      *
      * @return If the package has the permission, PERMISSION_GRANTED is
      * returned.  If it does not have the permission, PERMISSION_DENIED
@@ -3701,7 +3716,9 @@
      * @see #PERMISSION_DENIED
      */
     @CheckResult
-    public abstract @PermissionResult int checkPermission(String permName, String pkgName);
+    @PermissionResult
+    public abstract int checkPermission(@NonNull String permissionName,
+            @NonNull String packageName);
 
     /**
      * Checks whether a particular permissions has been revoked for a
@@ -3710,14 +3727,14 @@
      * permissions, hence the only way for an app to get such a permission
      * is by a policy change.
      *
-     * @param permName The name of the permission you are checking for.
-     * @param pkgName The name of the package you are checking against.
+     * @param permissionName The name of the permission you are checking for.
+     * @param packageName The name of the package you are checking against.
      *
      * @return Whether the permission is restricted by policy.
      */
     @CheckResult
-    public abstract boolean isPermissionRevokedByPolicy(@NonNull String permName,
-            @NonNull String pkgName);
+    public abstract boolean isPermissionRevokedByPolicy(@NonNull String permissionName,
+            @NonNull String packageName);
 
     /**
      * Gets the package name of the component controlling runtime permissions.
@@ -3726,6 +3743,7 @@
      *
      * @hide
      */
+    @NonNull
     @TestApi
     public abstract String getPermissionControllerPackageName();
 
@@ -3761,7 +3779,7 @@
      *
      * @see #removePermission(String)
      */
-    public abstract boolean addPermission(PermissionInfo info);
+    public abstract boolean addPermission(@NonNull PermissionInfo info);
 
     /**
      * Like {@link #addPermission(PermissionInfo)} but asynchronously
@@ -3770,7 +3788,7 @@
      * expense of no guarantee the added permission will be retained if
      * the device is rebooted before it is written.
      */
-    public abstract boolean addPermissionAsync(PermissionInfo info);
+    public abstract boolean addPermissionAsync(@NonNull PermissionInfo info);
 
     /**
      * Removes a permission that was previously added with
@@ -3778,14 +3796,14 @@
      * -- you are only allowed to remove permissions that you are allowed
      * to add.
      *
-     * @param name The name of the permission to remove.
+     * @param permissionName The name of the permission to remove.
      *
      * @throws SecurityException if you are not allowed to remove the
      * given permission name.
      *
      * @see #addPermission(PermissionInfo)
      */
-    public abstract void removePermission(String name);
+    public abstract void removePermission(@NonNull String permissionName);
 
     /**
      * Permission flags set when granting or revoking a permission.
@@ -3880,8 +3898,9 @@
             android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS,
             android.Manifest.permission.GET_RUNTIME_PERMISSIONS
     })
-    public abstract @PermissionFlags int getPermissionFlags(String permissionName,
-            String packageName, @NonNull UserHandle user);
+    @PermissionFlags
+    public abstract int getPermissionFlags(@NonNull String permissionName,
+            @NonNull String packageName, @NonNull UserHandle user);
 
     /**
      * Updates the flags associated with a permission by replacing the flags in
@@ -3901,9 +3920,9 @@
             android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS,
             android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS
     })
-    public abstract void updatePermissionFlags(String permissionName,
-            String packageName, @PermissionFlags int flagMask, @PermissionFlags int flagValues,
-            @NonNull UserHandle user);
+    public abstract void updatePermissionFlags(@NonNull String permissionName,
+            @NonNull String packageName, @PermissionFlags int flagMask,
+            @PermissionFlags int flagValues, @NonNull UserHandle user);
 
     /**
      * Gets whether you should show UI with rationale for requesting a permission.
@@ -3911,13 +3930,13 @@
      * which the permission is requested does not clearly communicate to the user
      * what would be the benefit from grating this permission.
      *
-     * @param permission A permission your app wants to request.
+     * @param permissionName A permission your app wants to request.
      * @return Whether you can show permission rationale UI.
      *
      * @hide
      */
     @UnsupportedAppUsage
-    public abstract boolean shouldShowRequestPermissionRationale(String permission);
+    public abstract boolean shouldShowRequestPermissionRationale(@NonNull String permissionName);
 
     /**
      * Returns an {@link android.content.Intent} suitable for passing to
@@ -3928,6 +3947,7 @@
      *
      * @hide
      */
+    @NonNull
     @UnsupportedAppUsage
     public Intent buildRequestPermissionsIntent(@NonNull String[] permissions) {
         if (ArrayUtils.isEmpty(permissions)) {
@@ -3946,8 +3966,8 @@
      * with each other: they can share the same user-id, run instrumentation
      * against each other, etc.
      *
-     * @param pkg1 First package name whose signature will be compared.
-     * @param pkg2 Second package name whose signature will be compared.
+     * @param packageName1 First package name whose signature will be compared.
+     * @param packageName2 Second package name whose signature will be compared.
      *
      * @return Returns an integer indicating whether all signatures on the
      * two packages match. The value is >= 0 ({@link #SIGNATURE_MATCH}) if
@@ -3957,7 +3977,9 @@
      * @see #checkSignatures(int, int)
      */
     @CheckResult
-    public abstract @SignatureResult int checkSignatures(String pkg1, String pkg2);
+    @SignatureResult
+    public abstract int checkSignatures(@NonNull String packageName1,
+            @NonNull String packageName2);
 
     /**
      * Like {@link #checkSignatures(String, String)}, but takes UIDs of
@@ -4030,7 +4052,7 @@
      * @hide
      */
     @UnsupportedAppUsage
-    public abstract int getUidForSharedUser(String sharedUserName)
+    public abstract int getUidForSharedUser(@NonNull String sharedUserName)
             throws NameNotFoundException;
 
     /**
@@ -4049,6 +4071,7 @@
      *         applications with data directory i.e. applications which had been
      *         deleted with {@code DONT_DELETE_DATA} flag set).
      */
+    @NonNull
     public abstract List<ApplicationInfo> getInstalledApplications(@ApplicationInfoFlags int flags);
 
     /**
@@ -4071,6 +4094,7 @@
      *         deleted with {@code DONT_DELETE_DATA} flag set).
      * @hide
      */
+    @NonNull
     @TestApi
     public abstract List<ApplicationInfo> getInstalledApplicationsAsUser(
             @ApplicationInfoFlags int flags, @UserIdInt int userId);
@@ -4121,7 +4145,7 @@
      * @see #getInstantAppCookieMaxBytes()
      * @see #clearInstantAppCookie()
      */
-    public abstract boolean isInstantApp(String packageName);
+    public abstract boolean isInstantApp(@NonNull String packageName);
 
     /**
      * Gets the maximum size in bytes of the cookie data an instant app
@@ -4208,6 +4232,7 @@
      * available on the system, or null if none are installed.
      *
      */
+    @Nullable
     public abstract String[] getSystemSharedLibraryNames();
 
     /**
@@ -4296,6 +4321,7 @@
      * @return An array of FeatureInfo classes describing the features
      * that are available on the system, or null if there are none(!!).
      */
+    @NonNull
     public abstract FeatureInfo[] getSystemAvailableFeatures();
 
     /**
@@ -4306,7 +4332,7 @@
      *
      * @return Returns true if the devices supports the feature, else false.
      */
-    public abstract boolean hasSystemFeature(String name);
+    public abstract boolean hasSystemFeature(@NonNull String featureName);
 
     /**
      * Check whether the given feature name and version is one of the available
@@ -4317,7 +4343,7 @@
      *
      * @return Returns true if the devices supports the feature, else false.
      */
-    public abstract boolean hasSystemFeature(String name, int version);
+    public abstract boolean hasSystemFeature(@NonNull String featureName, int version);
 
     /**
      * Determine the best action to perform for a given Intent. This is how
@@ -4345,7 +4371,9 @@
      *         found and there is no default set, returns a ResolveInfo object
      *         containing something else, such as the activity resolver.
      */
-    public abstract ResolveInfo resolveActivity(Intent intent, @ResolveInfoFlags int flags);
+    @Nullable
+    public abstract ResolveInfo resolveActivity(@NonNull Intent intent,
+            @ResolveInfoFlags int flags);
 
     /**
      * Determine the best action to perform for a given Intent for a given user.
@@ -4375,9 +4403,10 @@
      *         containing something else, such as the activity resolver.
      * @hide
      */
+    @Nullable
     @UnsupportedAppUsage
-    public abstract ResolveInfo resolveActivityAsUser(Intent intent, @ResolveInfoFlags int flags,
-            @UserIdInt int userId);
+    public abstract ResolveInfo resolveActivityAsUser(@NonNull Intent intent,
+            @ResolveInfoFlags int flags, @UserIdInt int userId);
 
     /**
      * Retrieve all activities that can be performed for the given intent.
@@ -4394,7 +4423,8 @@
      *         {@link #resolveActivity}. If there are no matching activities, an
      *         empty list is returned.
      */
-    public abstract List<ResolveInfo> queryIntentActivities(Intent intent,
+    @Nullable
+    public abstract List<ResolveInfo> queryIntentActivities(@NonNull Intent intent,
             @ResolveInfoFlags int flags);
 
     /**
@@ -4414,8 +4444,9 @@
      *         empty list is returned.
      * @hide
      */
+    @Nullable
     @UnsupportedAppUsage
-    public abstract List<ResolveInfo> queryIntentActivitiesAsUser(Intent intent,
+    public abstract List<ResolveInfo> queryIntentActivitiesAsUser(@NonNull Intent intent,
             @ResolveInfoFlags int flags, @UserIdInt int userId);
 
     /**
@@ -4469,8 +4500,9 @@
      *         included by one of the <var>specifics</var> intents. If there are
      *         no matching activities, an empty list is returned.
      */
+    @NonNull
     public abstract List<ResolveInfo> queryIntentActivityOptions(@Nullable ComponentName caller,
-            @Nullable Intent[] specifics, Intent intent, @ResolveInfoFlags int flags);
+            @Nullable Intent[] specifics, @NonNull Intent intent, @ResolveInfoFlags int flags);
 
     /**
      * Retrieve all receivers that can handle a broadcast of the given intent.
@@ -4481,7 +4513,8 @@
      *         each matching receiver, ordered from best to worst. If there are
      *         no matching receivers, an empty list or null is returned.
      */
-    public abstract List<ResolveInfo> queryBroadcastReceivers(Intent intent,
+    @NonNull
+    public abstract List<ResolveInfo> queryBroadcastReceivers(@NonNull Intent intent,
             @ResolveInfoFlags int flags);
 
     /**
@@ -4496,9 +4529,10 @@
      *         no matching receivers, an empty list or null is returned.
      * @hide
      */
+    @NonNull
     @SystemApi
     @RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS)
-    public List<ResolveInfo> queryBroadcastReceiversAsUser(Intent intent,
+    public List<ResolveInfo> queryBroadcastReceiversAsUser(@NonNull Intent intent,
             @ResolveInfoFlags int flags, UserHandle userHandle) {
         return queryBroadcastReceiversAsUser(intent, flags, userHandle.getIdentifier());
     }
@@ -4506,15 +4540,17 @@
     /**
      * @hide
      */
+    @NonNull
     @UnsupportedAppUsage
-    public abstract List<ResolveInfo> queryBroadcastReceiversAsUser(Intent intent,
+    public abstract List<ResolveInfo> queryBroadcastReceiversAsUser(@NonNull Intent intent,
             @ResolveInfoFlags int flags, @UserIdInt int userId);
 
 
-    /** {@hide} */
+    /** @deprecated @hide */
+    @NonNull
     @Deprecated
     @UnsupportedAppUsage
-    public List<ResolveInfo> queryBroadcastReceivers(Intent intent,
+    public List<ResolveInfo> queryBroadcastReceivers(@NonNull Intent intent,
             @ResolveInfoFlags int flags, @UserIdInt int userId) {
         final String msg = "Shame on you for calling the hidden API "
                 + "queryBroadcastReceivers(). Shame!";
@@ -4536,13 +4572,15 @@
      *         that was determined to be the best action. Returns null if no
      *         matching service was found.
      */
-    public abstract ResolveInfo resolveService(Intent intent, @ResolveInfoFlags int flags);
+    @Nullable
+    public abstract ResolveInfo resolveService(@NonNull Intent intent, @ResolveInfoFlags int flags);
 
     /**
      * @hide
      */
-    public abstract ResolveInfo resolveServiceAsUser(Intent intent, @ResolveInfoFlags int flags,
-            @UserIdInt int userId);
+    @Nullable
+    public abstract ResolveInfo resolveServiceAsUser(@NonNull Intent intent,
+            @ResolveInfoFlags int flags, @UserIdInt int userId);
 
     /**
      * Retrieve all services that can match the given intent.
@@ -4555,7 +4593,8 @@
      *         {@link #resolveService}. If there are no matching services, an
      *         empty list or null is returned.
      */
-    public abstract List<ResolveInfo> queryIntentServices(Intent intent,
+    @NonNull
+    public abstract List<ResolveInfo> queryIntentServices(@NonNull Intent intent,
             @ResolveInfoFlags int flags);
 
     /**
@@ -4571,8 +4610,9 @@
      *         empty list or null is returned.
      * @hide
      */
+    @NonNull
     @UnsupportedAppUsage
-    public abstract List<ResolveInfo> queryIntentServicesAsUser(Intent intent,
+    public abstract List<ResolveInfo> queryIntentServicesAsUser(@NonNull Intent intent,
             @ResolveInfoFlags int flags, @UserIdInt int userId);
 
     /**
@@ -4608,9 +4648,10 @@
      *         no matching services, an empty list or null is returned.
      * @hide
      */
+    @NonNull
     @UnsupportedAppUsage
     public abstract List<ResolveInfo> queryIntentContentProvidersAsUser(
-            Intent intent, @ResolveInfoFlags int flags, @UserIdInt int userId);
+            @NonNull Intent intent, @ResolveInfoFlags int flags, @UserIdInt int userId);
 
     /**
      * Retrieve all providers that can match the given intent.
@@ -4642,7 +4683,8 @@
      *         each matching provider, ordered from best to worst. If there are
      *         no matching services, an empty list or null is returned.
      */
-    public abstract List<ResolveInfo> queryIntentContentProviders(Intent intent,
+    @NonNull
+    public abstract List<ResolveInfo> queryIntentContentProviders(@NonNull Intent intent,
             @ResolveInfoFlags int flags);
 
     /**
@@ -4659,21 +4701,23 @@
      * @return A {@link ProviderInfo} object containing information about the
      *         provider. If a provider was not found, returns null.
      */
-    public abstract ProviderInfo resolveContentProvider(String authority,
+    @Nullable
+    public abstract ProviderInfo resolveContentProvider(@NonNull String authority,
             @ComponentInfoFlags int flags);
 
     /**
      * Find a single content provider by its base path name.
      *
-     * @param name The name of the provider to find.
+     * @param providerName The name of the provider to find.
      * @param flags Additional option flags to modify the data returned.
      * @param userId The user id.
      * @return A {@link ProviderInfo} object containing information about the
      *         provider. If a provider was not found, returns null.
      * @hide
      */
+    @Nullable
     @UnsupportedAppUsage
-    public abstract ProviderInfo resolveContentProviderAsUser(String name,
+    public abstract ProviderInfo resolveContentProviderAsUser(@NonNull String providerName,
             @ComponentInfoFlags int flags, @UserIdInt int userId);
 
     /**
@@ -4693,8 +4737,9 @@
      *         <var>processName</var> is null, all known content providers.
      *         <em>If there are no matching providers, null is returned.</em>
      */
+    @NonNull
     public abstract List<ProviderInfo> queryContentProviders(
-            String processName, int uid, @ComponentInfoFlags int flags);
+            @Nullable String processName, int uid, @ComponentInfoFlags int flags);
 
     /**
      * Same as {@link #queryContentProviders}, except when {@code metaDataKey} is not null,
@@ -4711,8 +4756,9 @@
      *
      * @hide
      */
-    public List<ProviderInfo> queryContentProviders(
-            String processName, int uid, @ComponentInfoFlags int flags, String metaDataKey) {
+    @NonNull
+    public List<ProviderInfo> queryContentProviders(@Nullable String processName,
+            int uid, @ComponentInfoFlags int flags, String metaDataKey) {
         // Provide the default implementation for mocks.
         return queryContentProviders(processName, uid, flags);
     }
@@ -4730,7 +4776,8 @@
      * @throws NameNotFoundException if a package with the given name cannot be
      *             found on the system.
      */
-    public abstract InstrumentationInfo getInstrumentationInfo(ComponentName className,
+    @NonNull
+    public abstract InstrumentationInfo getInstrumentationInfo(@NonNull ComponentName className,
             @InstrumentationInfoFlags int flags) throws NameNotFoundException;
 
     /**
@@ -4745,7 +4792,8 @@
      *         entry for each matching instrumentation. If there are no
      *         instrumentation available, returns an empty list.
      */
-    public abstract List<InstrumentationInfo> queryInstrumentation(String targetPackage,
+    @NonNull
+    public abstract List<InstrumentationInfo> queryInstrumentation(@NonNull String targetPackage,
             @InstrumentationInfoFlags int flags);
 
     /**
@@ -4765,8 +4813,9 @@
      * @return Returns a Drawable holding the requested image.  Returns null if
      * an image could not be found for any reason.
      */
-    public abstract Drawable getDrawable(String packageName, @DrawableRes int resid,
-            ApplicationInfo appInfo);
+    @Nullable
+    public abstract Drawable getDrawable(@NonNull String packageName, @DrawableRes int resid,
+            @Nullable ApplicationInfo appInfo);
 
     /**
      * Retrieve the icon associated with an activity.  Given the full name of
@@ -4783,7 +4832,8 @@
      *
      * @see #getActivityIcon(Intent)
      */
-    public abstract Drawable getActivityIcon(ComponentName activityName)
+    @NonNull
+    public abstract Drawable getActivityIcon(@NonNull ComponentName activityName)
             throws NameNotFoundException;
 
     /**
@@ -4803,7 +4853,8 @@
      *
      * @see #getActivityIcon(ComponentName)
      */
-    public abstract Drawable getActivityIcon(Intent intent)
+    @NonNull
+    public abstract Drawable getActivityIcon(@NonNull Intent intent)
             throws NameNotFoundException;
 
     /**
@@ -4819,7 +4870,8 @@
      *             activity could not be loaded.
      * @see #getActivityBanner(Intent)
      */
-    public abstract Drawable getActivityBanner(ComponentName activityName)
+    @Nullable
+    public abstract Drawable getActivityBanner(@NonNull ComponentName activityName)
             throws NameNotFoundException;
 
     /**
@@ -4837,7 +4889,8 @@
      *             matching the given intent could not be loaded.
      * @see #getActivityBanner(ComponentName)
      */
-    public abstract Drawable getActivityBanner(Intent intent)
+    @Nullable
+    public abstract Drawable getActivityBanner(@NonNull Intent intent)
             throws NameNotFoundException;
 
     /**
@@ -4846,6 +4899,7 @@
      *
      * @return Drawable Image of the icon.
      */
+    @NonNull
     public abstract Drawable getDefaultActivityIcon();
 
     /**
@@ -4859,7 +4913,8 @@
      *
      * @see #getApplicationIcon(String)
      */
-    public abstract Drawable getApplicationIcon(ApplicationInfo info);
+    @NonNull
+    public abstract Drawable getApplicationIcon(@NonNull ApplicationInfo info);
 
     /**
      * Retrieve the icon associated with an application.  Given the name of the
@@ -4877,7 +4932,8 @@
      *
      * @see #getApplicationIcon(ApplicationInfo)
      */
-    public abstract Drawable getApplicationIcon(String packageName)
+    @NonNull
+    public abstract Drawable getApplicationIcon(@NonNull String packageName)
             throws NameNotFoundException;
 
     /**
@@ -4888,7 +4944,8 @@
      *         banner specified.
      * @see #getApplicationBanner(String)
      */
-    public abstract Drawable getApplicationBanner(ApplicationInfo info);
+    @Nullable
+    public abstract Drawable getApplicationBanner(@NonNull ApplicationInfo info);
 
     /**
      * Retrieve the banner associated with an application. Given the name of the
@@ -4904,7 +4961,8 @@
      *             application could not be loaded.
      * @see #getApplicationBanner(ApplicationInfo)
      */
-    public abstract Drawable getApplicationBanner(String packageName)
+    @Nullable
+    public abstract Drawable getApplicationBanner(@NonNull String packageName)
             throws NameNotFoundException;
 
     /**
@@ -4920,7 +4978,8 @@
      *             activity could not be loaded.
      * @see #getActivityLogo(Intent)
      */
-    public abstract Drawable getActivityLogo(ComponentName activityName)
+    @Nullable
+    public abstract Drawable getActivityLogo(@NonNull ComponentName activityName)
             throws NameNotFoundException;
 
     /**
@@ -4941,7 +5000,8 @@
      *
      * @see #getActivityLogo(ComponentName)
      */
-    public abstract Drawable getActivityLogo(Intent intent)
+    @Nullable
+    public abstract Drawable getActivityLogo(@NonNull Intent intent)
             throws NameNotFoundException;
 
     /**
@@ -4955,7 +5015,8 @@
      *
      * @see #getApplicationLogo(String)
      */
-    public abstract Drawable getApplicationLogo(ApplicationInfo info);
+    @Nullable
+    public abstract Drawable getApplicationLogo(@NonNull ApplicationInfo info);
 
     /**
      * Retrieve the logo associated with an application.  Given the name of the
@@ -4974,7 +5035,8 @@
      *
      * @see #getApplicationLogo(ApplicationInfo)
      */
-    public abstract Drawable getApplicationLogo(String packageName)
+    @Nullable
+    public abstract Drawable getApplicationLogo(@NonNull String packageName)
             throws NameNotFoundException;
 
     /**
@@ -4988,12 +5050,14 @@
      * is performed in place and the original drawable is returned.
      * </p>
      *
-     * @param icon The icon to badge.
+     * @param drawable The drawable to badge.
      * @param user The target user.
      * @return A drawable that combines the original icon and a badge as
      *         determined by the system.
      */
-    public abstract Drawable getUserBadgedIcon(Drawable icon, UserHandle user);
+    @NonNull
+    public abstract Drawable getUserBadgedIcon(@NonNull Drawable drawable,
+            @NonNull UserHandle user);
 
     /**
      * If the target user is a managed profile of the calling user or the caller
@@ -5019,8 +5083,9 @@
      * @return A drawable that combines the original drawable and a badge as
      *         determined by the system.
      */
-    public abstract Drawable getUserBadgedDrawableForDensity(Drawable drawable,
-            UserHandle user, Rect badgeLocation, int badgeDensity);
+    @NonNull
+    public abstract Drawable getUserBadgedDrawableForDensity(@NonNull Drawable drawable,
+            @NonNull UserHandle user, @Nullable Rect badgeLocation, int badgeDensity);
 
     /**
      * If the target user is a managed profile of the calling user or the caller
@@ -5034,8 +5099,9 @@
      * @return the drawable or null if no drawable is required.
      * @hide
      */
+    @Nullable
     @UnsupportedAppUsage
-    public abstract Drawable getUserBadgeForDensity(UserHandle user, int density);
+    public abstract Drawable getUserBadgeForDensity(@NonNull UserHandle user, int density);
 
     /**
      * If the target user is a managed profile of the calling user or the caller
@@ -5051,8 +5117,10 @@
      * @return the drawable or null if no drawable is required.
      * @hide
      */
+    @Nullable
     @UnsupportedAppUsage
-    public abstract Drawable getUserBadgeForDensityNoBackground(UserHandle user, int density);
+    public abstract Drawable getUserBadgeForDensityNoBackground(@NonNull UserHandle user,
+            int density);
 
     /**
      * If the target user is a managed profile of the calling user or the caller
@@ -5065,7 +5133,9 @@
      * @return A label that combines the original label and a badge as
      *         determined by the system.
      */
-    public abstract CharSequence getUserBadgedLabel(CharSequence label, UserHandle user);
+    @NonNull
+    public abstract CharSequence getUserBadgedLabel(@NonNull CharSequence label,
+            @NonNull UserHandle user);
 
     /**
      * Retrieve text from a package.  This is a low-level API used by
@@ -5084,8 +5154,9 @@
      * @return Returns a CharSequence holding the requested text.  Returns null
      * if the text could not be found for any reason.
      */
-    public abstract CharSequence getText(String packageName, @StringRes int resid,
-            ApplicationInfo appInfo);
+    @Nullable
+    public abstract CharSequence getText(@NonNull String packageName, @StringRes int resid,
+            @Nullable ApplicationInfo appInfo);
 
     /**
      * Retrieve an XML file from a package.  This is a low-level API used to
@@ -5103,8 +5174,9 @@
      * data.  Returns null if the xml resource could not be found for any
      * reason.
      */
-    public abstract XmlResourceParser getXml(String packageName, @XmlRes int resid,
-            ApplicationInfo appInfo);
+    @Nullable
+    public abstract XmlResourceParser getXml(@NonNull String packageName, @XmlRes int resid,
+            @Nullable ApplicationInfo appInfo);
 
     /**
      * Return the label to use for this application.
@@ -5113,7 +5185,8 @@
      * it could not be found for any reason.
      * @param info The application to get the label of.
      */
-    public abstract CharSequence getApplicationLabel(ApplicationInfo info);
+    @NonNull
+    public abstract CharSequence getApplicationLabel(@NonNull ApplicationInfo info);
 
     /**
      * Retrieve the resources associated with an activity.  Given the full
@@ -5130,7 +5203,8 @@
      *
      * @see #getResourcesForApplication(ApplicationInfo)
      */
-    public abstract Resources getResourcesForActivity(ComponentName activityName)
+    @NonNull
+    public abstract Resources getResourcesForActivity(@NonNull ComponentName activityName)
             throws NameNotFoundException;
 
     /**
@@ -5143,7 +5217,8 @@
      * @throws NameNotFoundException Thrown if the resources for the given
      * application could not be loaded (most likely because it was uninstalled).
      */
-    public abstract Resources getResourcesForApplication(ApplicationInfo app)
+    @NonNull
+    public abstract Resources getResourcesForApplication(@NonNull ApplicationInfo app)
             throws NameNotFoundException;
 
     /**
@@ -5152,7 +5227,7 @@
      * calls getResources() to return its application's resources.  If the
      * appPackageName cannot be found, NameNotFoundException is thrown.
      *
-     * @param appPackageName Package name of the application whose resources
+     * @param packageName Package name of the application whose resources
      *                       are to be retrieved.
      *
      * @return Returns the application's Resources.
@@ -5161,12 +5236,14 @@
      *
      * @see #getResourcesForApplication(ApplicationInfo)
      */
-    public abstract Resources getResourcesForApplication(String appPackageName)
+    @NonNull
+    public abstract Resources getResourcesForApplication(@NonNull String packageName)
             throws NameNotFoundException;
 
     /** @hide */
+    @NonNull
     @UnsupportedAppUsage
-    public abstract Resources getResourcesForApplicationAsUser(String appPackageName,
+    public abstract Resources getResourcesForApplicationAsUser(@NonNull String packageName,
             @UserIdInt int userId) throws NameNotFoundException;
 
     /**
@@ -5178,7 +5255,9 @@
      * @return A PackageInfo object containing information about the package
      *         archive. If the package could not be parsed, returns null.
      */
-    public PackageInfo getPackageArchiveInfo(String archiveFilePath, @PackageInfoFlags int flags) {
+    @Nullable
+    public PackageInfo getPackageArchiveInfo(@NonNull String archiveFilePath,
+            @PackageInfoFlags int flags) {
         final PackageParser parser = new PackageParser();
         parser.setCallback(new PackageParser.CallbackImpl(this));
         final File apkFile = new File(archiveFilePath);
@@ -5212,7 +5291,8 @@
      */
     @Deprecated
     @SystemApi
-    public abstract int installExistingPackage(String packageName) throws NameNotFoundException;
+    public abstract int installExistingPackage(@NonNull String packageName)
+            throws NameNotFoundException;
 
     /**
      * If there is already an application with the given package name installed
@@ -5223,8 +5303,8 @@
      */
     @Deprecated
     @SystemApi
-    public abstract int installExistingPackage(String packageName, @InstallReason int installReason)
-            throws NameNotFoundException;
+    public abstract int installExistingPackage(@NonNull String packageName,
+            @InstallReason int installReason) throws NameNotFoundException;
 
     /**
      * If there is already an application with the given package name installed
@@ -5239,8 +5319,8 @@
             Manifest.permission.INSTALL_PACKAGES,
             Manifest.permission.INTERACT_ACROSS_USERS_FULL})
     @UnsupportedAppUsage
-    public abstract int installExistingPackageAsUser(String packageName, @UserIdInt int userId)
-            throws NameNotFoundException;
+    public abstract int installExistingPackageAsUser(@NonNull String packageName,
+            @UserIdInt int userId) throws NameNotFoundException;
 
     /**
      * Allows a package listening to the
@@ -5316,7 +5396,7 @@
     @SystemApi
     @RequiresPermission(android.Manifest.permission.INTENT_FILTER_VERIFICATION_AGENT)
     public abstract void verifyIntentFilter(int verificationId, int verificationCode,
-            List<String> failedDomains);
+            @NonNull List<String> failedDomains);
 
     /**
      * Get the status of a Domain Verification Result for an IntentFilter. This is
@@ -5340,7 +5420,8 @@
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL)
-    public abstract int getIntentVerificationStatusAsUser(String packageName, @UserIdInt int userId);
+    public abstract int getIntentVerificationStatusAsUser(@NonNull String packageName,
+            @UserIdInt int userId);
 
     /**
      * Allow to change the status of a Intent Verification status for all IntentFilter of an App.
@@ -5364,8 +5445,8 @@
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.SET_PREFERRED_APPLICATIONS)
-    public abstract boolean updateIntentVerificationStatusAsUser(String packageName, int status,
-            @UserIdInt int userId);
+    public abstract boolean updateIntentVerificationStatusAsUser(@NonNull String packageName,
+            int status, @UserIdInt int userId);
 
     /**
      * Get the list of IntentFilterVerificationInfo for a specific package and User.
@@ -5379,9 +5460,10 @@
      *
      * @hide
      */
+    @NonNull
     @SystemApi
     public abstract List<IntentFilterVerificationInfo> getIntentFilterVerifications(
-            String packageName);
+            @NonNull String packageName);
 
     /**
      * Get the list of IntentFilter for a specific package.
@@ -5394,8 +5476,9 @@
      *
      * @hide
      */
+    @NonNull
     @SystemApi
-    public abstract List<IntentFilter> getAllIntentFilters(String packageName);
+    public abstract List<IntentFilter> getAllIntentFilters(@NonNull String packageName);
 
     /**
      * Get the default Browser package name for a specific user.
@@ -5407,6 +5490,7 @@
      *
      * @hide
      */
+    @Nullable
     @TestApi
     @SystemApi
     @RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL)
@@ -5428,7 +5512,7 @@
     @RequiresPermission(allOf = {
             Manifest.permission.SET_PREFERRED_APPLICATIONS,
             Manifest.permission.INTERACT_ACROSS_USERS_FULL})
-    public abstract boolean setDefaultBrowserPackageNameAsUser(String packageName,
+    public abstract boolean setDefaultBrowserPackageNameAsUser(@Nullable String packageName,
             @UserIdInt int userId);
 
     /**
@@ -5446,13 +5530,13 @@
      * @param installerPackageName The package name of the new installer.  May be
      * null to clear the association.
      */
-    public abstract void setInstallerPackageName(String targetPackage,
-            String installerPackageName);
+    public abstract void setInstallerPackageName(@NonNull String targetPackage,
+            @Nullable String installerPackageName);
 
     /** @hide */
     @SystemApi
     @RequiresPermission(Manifest.permission.INSTALL_PACKAGES)
-    public abstract void setUpdateAvailable(String packageName, boolean updateAvaialble);
+    public abstract void setUpdateAvailable(@NonNull String packageName, boolean updateAvaialble);
 
     /**
      * Attempts to delete a package. Since this may take a little while, the
@@ -5472,8 +5556,8 @@
      */
     @RequiresPermission(Manifest.permission.DELETE_PACKAGES)
     @UnsupportedAppUsage
-    public abstract void deletePackage(String packageName, IPackageDeleteObserver observer,
-            @DeleteFlags int flags);
+    public abstract void deletePackage(@NonNull String packageName,
+            @Nullable IPackageDeleteObserver observer, @DeleteFlags int flags);
 
     /**
      * Attempts to delete a package. Since this may take a little while, the
@@ -5495,7 +5579,8 @@
             Manifest.permission.INTERACT_ACROSS_USERS_FULL})
     @UnsupportedAppUsage
     public abstract void deletePackageAsUser(@NonNull String packageName,
-            IPackageDeleteObserver observer, @DeleteFlags int flags, @UserIdInt int userId);
+            @Nullable IPackageDeleteObserver observer, @DeleteFlags int flags,
+            @UserIdInt int userId);
 
     /**
      * Retrieve the package name of the application that installed a package. This identifies
@@ -5505,7 +5590,7 @@
      * @throws IllegalArgumentException if the given package name is not installed
      */
     @Nullable
-    public abstract String getInstallerPackageName(String packageName);
+    public abstract String getInstallerPackageName(@NonNull String packageName);
 
     /**
      * Attempts to clear the user data directory of an application.
@@ -5522,8 +5607,8 @@
      * @hide
      */
     @UnsupportedAppUsage
-    public abstract void clearApplicationUserData(String packageName,
-            IPackageDataObserver observer);
+    public abstract void clearApplicationUserData(@NonNull String packageName,
+            @Nullable IPackageDataObserver observer);
     /**
      * Attempts to delete the cache files associated with an application.
      * Since this may take a little while, the result will
@@ -5541,8 +5626,8 @@
      * @hide
      */
     @UnsupportedAppUsage
-    public abstract void deleteApplicationCacheFiles(String packageName,
-            IPackageDataObserver observer);
+    public abstract void deleteApplicationCacheFiles(@NonNull String packageName,
+            @Nullable IPackageDataObserver observer);
 
     /**
      * Attempts to delete the cache files associated with an application for a given user. Since
@@ -5563,8 +5648,8 @@
      * @hide
      */
     @UnsupportedAppUsage
-    public abstract void deleteApplicationCacheFilesAsUser(String packageName, int userId,
-            IPackageDataObserver observer);
+    public abstract void deleteApplicationCacheFilesAsUser(@NonNull String packageName,
+            @UserIdInt int userId, @Nullable IPackageDataObserver observer);
 
     /**
      * Free storage by deleting LRU sorted list of cache files across
@@ -5589,14 +5674,15 @@
      * @hide
      */
     @UnsupportedAppUsage
-    public void freeStorageAndNotify(long freeStorageSize, IPackageDataObserver observer) {
+    public void freeStorageAndNotify(long freeStorageSize,
+            @Nullable IPackageDataObserver observer) {
         freeStorageAndNotify(null, freeStorageSize, observer);
     }
 
     /** {@hide} */
     @UnsupportedAppUsage
-    public abstract void freeStorageAndNotify(String volumeUuid, long freeStorageSize,
-            IPackageDataObserver observer);
+    public abstract void freeStorageAndNotify(@Nullable String volumeUuid, long freeStorageSize,
+            @Nullable IPackageDataObserver observer);
 
     /**
      * Free storage by deleting LRU sorted list of cache files across
@@ -5622,13 +5708,14 @@
      * @hide
      */
     @UnsupportedAppUsage
-    public void freeStorage(long freeStorageSize, IntentSender pi) {
+    public void freeStorage(long freeStorageSize, @Nullable IntentSender pi) {
         freeStorage(null, freeStorageSize, pi);
     }
 
     /** {@hide} */
     @UnsupportedAppUsage
-    public abstract void freeStorage(String volumeUuid, long freeStorageSize, IntentSender pi);
+    public abstract void freeStorage(@Nullable String volumeUuid, long freeStorageSize,
+            @Nullable IntentSender pi);
 
     /**
      * Retrieve the size information for a package.
@@ -5651,8 +5738,8 @@
      */
     @Deprecated
     @UnsupportedAppUsage
-    public abstract void getPackageSizeInfoAsUser(String packageName, @UserIdInt int userId,
-            IPackageStatsObserver observer);
+    public abstract void getPackageSizeInfoAsUser(@NonNull String packageName,
+            @UserIdInt int userId, @Nullable IPackageStatsObserver observer);
 
     /**
      * Like {@link #getPackageSizeInfoAsUser(String, int, IPackageStatsObserver)}, but
@@ -5663,7 +5750,7 @@
      */
     @Deprecated
     @UnsupportedAppUsage
-    public void getPackageSizeInfo(String packageName, IPackageStatsObserver observer) {
+    public void getPackageSizeInfo(@NonNull String packageName, IPackageStatsObserver observer) {
         getPackageSizeInfoAsUser(packageName, getUserId(), observer);
     }
 
@@ -5676,7 +5763,7 @@
      * holders, see {@link android.app.role.RoleManager}.
      */
     @Deprecated
-    public abstract void addPackageToPreferred(String packageName);
+    public abstract void addPackageToPreferred(@NonNull String packageName);
 
     /**
      * @deprecated This function no longer does anything. It is the platform's
@@ -5687,7 +5774,7 @@
      * holders, see {@link android.app.role.RoleManager}.
      */
     @Deprecated
-    public abstract void removePackageFromPreferred(String packageName);
+    public abstract void removePackageFromPreferred(@NonNull String packageName);
 
     /**
      * Retrieve the list of all currently configured preferred packages. The
@@ -5705,6 +5792,7 @@
      * an app to be responsible for a particular role and to check current role
      * holders, see {@link android.app.role.RoleManager}.
      */
+    @NonNull
     @Deprecated
     public abstract List<PackageInfo> getPreferredPackages(@PackageInfoFlags int flags);
 
@@ -5731,8 +5819,8 @@
      * holders, see {@link android.app.role.RoleManager}.
      */
     @Deprecated
-    public abstract void addPreferredActivity(IntentFilter filter, int match,
-            ComponentName[] set, ComponentName activity);
+    public abstract void addPreferredActivity(@NonNull IntentFilter filter, int match,
+            @Nullable ComponentName[] set, @NonNull ComponentName activity);
 
     /**
      * Same as {@link #addPreferredActivity(IntentFilter, int,
@@ -5749,8 +5837,8 @@
      */
     @Deprecated
     @UnsupportedAppUsage
-    public void addPreferredActivityAsUser(IntentFilter filter, int match,
-            ComponentName[] set, ComponentName activity, @UserIdInt int userId) {
+    public void addPreferredActivityAsUser(@NonNull IntentFilter filter, int match,
+            @Nullable ComponentName[] set, @NonNull ComponentName activity, @UserIdInt int userId) {
         throw new RuntimeException("Not implemented. Must override in a subclass.");
     }
 
@@ -5781,8 +5869,8 @@
      */
     @Deprecated
     @UnsupportedAppUsage
-    public abstract void replacePreferredActivity(IntentFilter filter, int match,
-            ComponentName[] set, ComponentName activity);
+    public abstract void replacePreferredActivity(@NonNull IntentFilter filter, int match,
+            @Nullable ComponentName[] set, @NonNull ComponentName activity);
 
     /**
      * Replaces an existing preferred activity mapping to the system, and if that were not present
@@ -5826,8 +5914,8 @@
      */
     @Deprecated
     @UnsupportedAppUsage
-    public void replacePreferredActivityAsUser(IntentFilter filter, int match,
-           ComponentName[] set, ComponentName activity, @UserIdInt int userId) {
+    public void replacePreferredActivityAsUser(@NonNull IntentFilter filter, int match,
+            @Nullable ComponentName[] set, @NonNull ComponentName activity, @UserIdInt int userId) {
         throw new RuntimeException("Not implemented. Must override in a subclass.");
     }
 
@@ -5848,7 +5936,7 @@
      * holders, see {@link android.app.role.RoleManager}.
      */
     @Deprecated
-    public abstract void clearPackagePreferredActivities(String packageName);
+    public abstract void clearPackagePreferredActivities(@NonNull String packageName);
 
     /**
      * Retrieve all preferred activities, previously added with
@@ -5876,15 +5964,16 @@
      */
     @Deprecated
     public abstract int getPreferredActivities(@NonNull List<IntentFilter> outFilters,
-            @NonNull List<ComponentName> outActivities, String packageName);
+            @NonNull List<ComponentName> outActivities, @Nullable String packageName);
 
     /**
      * Ask for the set of available 'home' activities and the current explicit
      * default, if any.
      * @hide
      */
+    @Nullable
     @UnsupportedAppUsage
-    public abstract ComponentName getHomeActivities(List<ResolveInfo> outActivities);
+    public abstract ComponentName getHomeActivities(@NonNull List<ResolveInfo> outActivities);
 
     /**
      * Set the enabled setting for a package component (activity, receiver, service, provider).
@@ -5984,7 +6073,7 @@
      * @hide
      */
     @UnsupportedAppUsage
-    public abstract void flushPackageRestrictionsAsUser(int userId);
+    public abstract void flushPackageRestrictionsAsUser(@UserIdInt int userId);
 
     /**
      * Puts the package in a hidden state, which is almost like an uninstalled state,
@@ -5994,8 +6083,8 @@
      * @hide
      */
     @UnsupportedAppUsage
-    public abstract boolean setApplicationHiddenSettingAsUser(String packageName, boolean hidden,
-            UserHandle userHandle);
+    public abstract boolean setApplicationHiddenSettingAsUser(@NonNull String packageName,
+            boolean hidden, @NonNull UserHandle userHandle);
 
     /**
      * Returns the hidden state of a package.
@@ -6003,8 +6092,8 @@
      * @hide
      */
     @UnsupportedAppUsage
-    public abstract boolean getApplicationHiddenSettingAsUser(String packageName,
-            UserHandle userHandle);
+    public abstract boolean getApplicationHiddenSettingAsUser(@NonNull String packageName,
+            @NonNull UserHandle userHandle);
 
     /**
      * Return whether the device has been booted into safe mode.
@@ -6020,7 +6109,8 @@
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS)
-    public abstract void addOnPermissionsChangeListener(OnPermissionsChangedListener listener);
+    public abstract void addOnPermissionsChangeListener(
+            @NonNull OnPermissionsChangedListener listener);
 
     /**
      * Remvoes a listener for permission changes for installed packages.
@@ -6031,7 +6121,8 @@
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS)
-    public abstract void removeOnPermissionsChangeListener(OnPermissionsChangedListener listener);
+    public abstract void removeOnPermissionsChangeListener(
+            @NonNull OnPermissionsChangedListener listener);
 
     /**
      * Return the {@link KeySet} associated with the String alias for this
@@ -6041,14 +6132,16 @@
      *        application's AndroidManifest.xml.
      * @hide
      */
+    @NonNull
     @UnsupportedAppUsage
-    public abstract KeySet getKeySetByAlias(String packageName, String alias);
+    public abstract KeySet getKeySetByAlias(@NonNull String packageName, @NonNull String alias);
 
     /** Return the signing {@link KeySet} for this application.
      * @hide
      */
+    @NonNull
     @UnsupportedAppUsage
-    public abstract KeySet getSigningKeySet(String packageName);
+    public abstract KeySet getSigningKeySet(@NonNull String packageName);
 
     /**
      * Return whether the package denoted by packageName has been signed by all
@@ -6058,7 +6151,7 @@
      * @hide
      */
     @UnsupportedAppUsage
-    public abstract boolean isSignedBy(String packageName, KeySet ks);
+    public abstract boolean isSignedBy(@NonNull String packageName, @NonNull KeySet ks);
 
     /**
      * Return whether the package denoted by packageName has been signed by all
@@ -6067,7 +6160,7 @@
      * @hide
      */
     @UnsupportedAppUsage
-    public abstract boolean isSignedByExactly(String packageName, KeySet ks);
+    public abstract boolean isSignedByExactly(@NonNull String packageName, @NonNull KeySet ks);
 
     /**
      * Flag to denote no restrictions. This should be used to clear any restrictions that may have
@@ -6284,7 +6377,7 @@
      * @hide
      */
     @UnsupportedAppUsage
-    public abstract boolean isPackageSuspendedForUser(String packageName, int userId);
+    public abstract boolean isPackageSuspendedForUser(@NonNull String packageName, int userId);
 
     /**
      * Query if an app is currently suspended.
@@ -6294,7 +6387,7 @@
      *
      * @see #isPackageSuspended()
      */
-    public boolean isPackageSuspended(String packageName) throws NameNotFoundException {
+    public boolean isPackageSuspended(@NonNull String packageName) throws NameNotFoundException {
         throw new UnsupportedOperationException("isPackageSuspended not implemented");
     }
 
@@ -6378,23 +6471,26 @@
 
     /** {@hide} */
     @UnsupportedAppUsage
-    public abstract void registerMoveCallback(MoveCallback callback, Handler handler);
+    public abstract void registerMoveCallback(@NonNull MoveCallback callback,
+            @NonNull Handler handler);
     /** {@hide} */
     @UnsupportedAppUsage
-    public abstract void unregisterMoveCallback(MoveCallback callback);
+    public abstract void unregisterMoveCallback(@NonNull MoveCallback callback);
 
     /** {@hide} */
     @UnsupportedAppUsage
-    public abstract int movePackage(String packageName, VolumeInfo vol);
+    public abstract int movePackage(@NonNull String packageName, @NonNull VolumeInfo vol);
     /** {@hide} */
     @UnsupportedAppUsage
-    public abstract @Nullable VolumeInfo getPackageCurrentVolume(ApplicationInfo app);
+    public abstract @Nullable VolumeInfo getPackageCurrentVolume(@NonNull ApplicationInfo app);
     /** {@hide} */
+    @NonNull
     @UnsupportedAppUsage
-    public abstract @NonNull List<VolumeInfo> getPackageCandidateVolumes(ApplicationInfo app);
+    public abstract List<VolumeInfo> getPackageCandidateVolumes(
+            @NonNull ApplicationInfo app);
 
     /** {@hide} */
-    public abstract int movePrimaryStorage(VolumeInfo vol);
+    public abstract int movePrimaryStorage(@NonNull VolumeInfo vol);
     /** {@hide} */
     public abstract @Nullable VolumeInfo getPrimaryStorageCurrentVolume();
     /** {@hide} */
@@ -6407,6 +6503,7 @@
      * @return identity that uniquely identifies current device
      * @hide
      */
+    @NonNull
     public abstract VerifierDeviceIdentity getVerifierDeviceIdentity();
 
     /**
@@ -6437,8 +6534,8 @@
      * @hide
      */
     @UnsupportedAppUsage
-    public abstract void addCrossProfileIntentFilter(IntentFilter filter, int sourceUserId,
-            int targetUserId, int flags);
+    public abstract void addCrossProfileIntentFilter(@NonNull IntentFilter filter,
+            @UserIdInt int sourceUserId, @UserIdInt int targetUserId, int flags);
 
     /**
      * Clearing {@code CrossProfileIntentFilter}s which have the specified user
@@ -6448,27 +6545,32 @@
      * @hide
      */
     @UnsupportedAppUsage
-    public abstract void clearCrossProfileIntentFilters(int sourceUserId);
+    public abstract void clearCrossProfileIntentFilters(@UserIdInt int sourceUserId);
 
     /**
      * @hide
      */
+    @NonNull
     @UnsupportedAppUsage
-    public abstract Drawable loadItemIcon(PackageItemInfo itemInfo, ApplicationInfo appInfo);
+    public abstract Drawable loadItemIcon(@NonNull PackageItemInfo itemInfo,
+            @Nullable ApplicationInfo appInfo);
 
     /**
      * @hide
      */
+    @NonNull
     @UnsupportedAppUsage
-    public abstract Drawable loadUnbadgedItemIcon(PackageItemInfo itemInfo, ApplicationInfo appInfo);
+    public abstract Drawable loadUnbadgedItemIcon(@NonNull PackageItemInfo itemInfo,
+            @Nullable ApplicationInfo appInfo);
 
     /** {@hide} */
     @UnsupportedAppUsage
-    public abstract boolean isPackageAvailable(String packageName);
+    public abstract boolean isPackageAvailable(@NonNull String packageName);
 
     /** {@hide} */
+    @NonNull
     @UnsupportedAppUsage
-    public static String installStatusToString(int status, String msg) {
+    public static String installStatusToString(int status, @Nullable String msg) {
         final String str = installStatusToString(status);
         if (msg != null) {
             return str + ": " + msg;
@@ -6478,6 +6580,7 @@
     }
 
     /** {@hide} */
+    @NonNull
     @UnsupportedAppUsage
     public static String installStatusToString(int status) {
         switch (status) {
@@ -6582,7 +6685,8 @@
     }
 
     /** {@hide} */
-    public static String deleteStatusToString(int status, String msg) {
+    @NonNull
+    public static String deleteStatusToString(int status, @Nullable String msg) {
         final String str = deleteStatusToString(status);
         if (msg != null) {
             return str + ": " + msg;
@@ -6592,6 +6696,7 @@
     }
 
     /** {@hide} */
+    @NonNull
     @UnsupportedAppUsage
     public static String deleteStatusToString(int status) {
         switch (status) {
@@ -6621,6 +6726,7 @@
     }
 
     /** {@hide} */
+    @NonNull
     public static String permissionFlagToString(int flag) {
         switch (flag) {
             case FLAG_PERMISSION_GRANTED_BY_DEFAULT: return "GRANTED_BY_DEFAULT";
@@ -6668,8 +6774,8 @@
      * @hide
      */
     @TestApi
-    public abstract @InstallReason int getInstallReason(String packageName,
-            @NonNull UserHandle user);
+    @InstallReason
+    public abstract int getInstallReason(@NonNull String packageName, @NonNull UserHandle user);
 
     /**
      * Checks whether the calling package is allowed to request package installs through package
@@ -6695,6 +6801,7 @@
      * @see {@link android.content.Intent#ACTION_INSTANT_APP_RESOLVER_SETTINGS}
      * @hide
      */
+    @Nullable
     @SystemApi
     public abstract ComponentName getInstantAppResolverSettingsComponent();
 
@@ -6705,6 +6812,7 @@
      * @see {@link android.content.Intent#ACTION_INSTALL_INSTANT_APP_PACKAGE}
      * @hide
      */
+    @Nullable
     @SystemApi
     public abstract ComponentName getInstantAppInstallerComponent();
 
@@ -6714,7 +6822,9 @@
      * @see {@link android.provider.Settings.Secure#ANDROID_ID}
      * @hide
      */
-    public abstract String getInstantAppAndroidId(String packageName, @NonNull UserHandle user);
+    @Nullable
+    public abstract String getInstantAppAndroidId(@NonNull String packageName,
+            @NonNull UserHandle user);
 
     /**
      * Callback use to notify the callers of module registration that the operation
@@ -6757,7 +6867,7 @@
      * @hide
      */
     @SystemApi
-    public abstract void registerDexModule(String dexModulePath,
+    public abstract void registerDexModule(@NonNull String dexModulePath,
             @Nullable DexModuleRegisterCallback callback);
 
     /**
@@ -6837,8 +6947,8 @@
      * @param type representation of the {@code certificate}
      * @return true if this package was or is signed by exactly the certificate {@code certificate}
      */
-    public boolean hasSigningCertificate(
-            String packageName, byte[] certificate, @CertificateInputType int type) {
+    public boolean hasSigningCertificate(@NonNull String packageName, @NonNull byte[] certificate,
+            @CertificateInputType int type) {
         throw new UnsupportedOperationException(
                 "hasSigningCertificate not implemented in subclass");
     }
@@ -6862,7 +6972,7 @@
      * @return true if this package was or is signed by exactly the certificate {@code certificate}
      */
     public boolean hasSigningCertificate(
-            int uid, byte[] certificate, @CertificateInputType int type) {
+            int uid, @NonNull byte[] certificate, @CertificateInputType int type) {
         throw new UnsupportedOperationException(
                 "hasSigningCertificate not implemented in subclass");
     }
@@ -6872,6 +6982,7 @@
      *
      * @hide
      */
+    @Nullable
     public String getSystemTextClassifierPackageName() {
         throw new UnsupportedOperationException(
                 "getSystemTextClassifierPackageName not implemented in subclass");
@@ -6882,6 +6993,7 @@
      *
      * @hide
      */
+    @Nullable
     @TestApi
     public String getWellbeingPackageName() {
         throw new UnsupportedOperationException(
@@ -6893,6 +7005,7 @@
      *
      * @hide
      */
+    @Nullable
     public String getAppPredictionServicePackageName() {
         throw new UnsupportedOperationException(
             "getAppPredictionServicePackageName not implemented in subclass");
@@ -6903,6 +7016,7 @@
      *
      * @hide
      */
+    @Nullable
     public String getSystemCaptionsServicePackageName() {
         throw new UnsupportedOperationException(
                 "getSystemCaptionsServicePackageName not implemented in subclass");
@@ -6928,7 +7042,7 @@
      *
      * @hide
      */
-    public boolean isPackageStateProtected(String packageName, int userId) {
+    public boolean isPackageStateProtected(@NonNull String packageName, @UserIdInt int userId) {
         throw new UnsupportedOperationException(
             "isPackageStateProtected not implemented in subclass");
     }
diff --git a/core/java/android/database/TranslatingCursor.java b/core/java/android/database/TranslatingCursor.java
index d9165b4..35cbdc7 100644
--- a/core/java/android/database/TranslatingCursor.java
+++ b/core/java/android/database/TranslatingCursor.java
@@ -22,6 +22,7 @@
 import android.database.sqlite.SQLiteQueryBuilder;
 import android.net.Uri;
 import android.os.CancellationSignal;
+import android.util.ArraySet;
 
 import com.android.internal.util.ArrayUtils;
 
@@ -59,7 +60,7 @@
     private final boolean mDropLast;
 
     private final int mAuxiliaryColumnIndex;
-    private final int[] mTranslateColumnIndices;
+    private final ArraySet<Integer> mTranslateColumnIndices;
 
     public TranslatingCursor(@NonNull Cursor cursor, @NonNull Config config,
             @NonNull Translator translator, boolean dropLast) {
@@ -70,9 +71,12 @@
         mDropLast = dropLast;
 
         mAuxiliaryColumnIndex = cursor.getColumnIndexOrThrow(config.auxiliaryColumn);
-        mTranslateColumnIndices = new int[config.translateColumns.length];
-        for (int i = 0; i < mTranslateColumnIndices.length; ++i) {
-            mTranslateColumnIndices[i] = cursor.getColumnIndex(config.translateColumns[i]);
+        mTranslateColumnIndices = new ArraySet<>();
+        for (int i = 0; i < cursor.getColumnCount(); ++i) {
+            String columnName = cursor.getColumnName(i);
+            if (ArrayUtils.contains(config.translateColumns, columnName)) {
+                mTranslateColumnIndices.add(i);
+            }
         }
     }
 
diff --git a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
index da0899b..690df1a 100644
--- a/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
+++ b/core/java/android/hardware/camera2/legacy/RequestThreadManager.java
@@ -333,6 +333,16 @@
         startPreview();
     }
 
+    private void disconnectCallbackSurfaces() {
+        for (Surface s : mCallbackOutputs) {
+            try {
+                LegacyCameraDevice.disconnectSurface(s);
+            } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
+                Log.d(TAG, "Surface abandoned, skipping...", e);
+            }
+        }
+    }
+
     private void configureOutputs(Collection<Pair<Surface, Size>> outputs) {
         if (DEBUG) {
             String outputsStr = outputs == null ? "null" : (outputs.size() + " surfaces");
@@ -370,14 +380,8 @@
             mGLThreadManager.waitUntilIdle();
         }
         resetJpegSurfaceFormats(mCallbackOutputs);
+        disconnectCallbackSurfaces();
 
-        for (Surface s : mCallbackOutputs) {
-            try {
-                LegacyCameraDevice.disconnectSurface(s);
-            } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
-                Log.w(TAG, "Surface abandoned, skipping...", e);
-            }
-        }
         mPreviewOutputs.clear();
         mCallbackOutputs.clear();
         mJpegSurfaceIds.clear();
@@ -972,11 +976,11 @@
                         mGLThreadManager.quit();
                         mGLThreadManager = null;
                     }
+                    disconnectCallbackSurfaces();
                     if (mCamera != null) {
                         mCamera.release();
                         mCamera = null;
                     }
-                    resetJpegSurfaceFormats(mCallbackOutputs);
                     break;
                 case RequestHandlerThread.MSG_POKE_IDLE_HANDLER:
                     // OK: Ignore message.
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index ae93cf0..4a64128 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -1934,6 +1934,8 @@
             @NonNull Callback callback) {
         ParcelFileDescriptor dup;
         try {
+            // Dup is needed here as the pfd inside the socket is owned by the IpSecService,
+            // which cannot be obtained by the app process.
             dup = ParcelFileDescriptor.dup(socket.getFileDescriptor());
         } catch (IOException ignored) {
             // Construct an invalid fd, so that if the user later calls start(), it will fail with
@@ -1975,6 +1977,7 @@
             @NonNull Callback callback) {
         ParcelFileDescriptor dup;
         try {
+            // TODO: Consider remove unnecessary dup.
             dup = pfd.dup();
         } catch (IOException ignored) {
             // Construct an invalid fd, so that if the user later calls start(), it will fail with
diff --git a/core/java/android/net/DnsResolver.java b/core/java/android/net/DnsResolver.java
index 5980251..687b721 100644
--- a/core/java/android/net/DnsResolver.java
+++ b/core/java/android/net/DnsResolver.java
@@ -22,6 +22,10 @@
 import static android.net.NetworkUtils.resNetworkSend;
 import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_ERROR;
 import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT;
+import static android.system.OsConstants.AF_INET;
+import static android.system.OsConstants.AF_INET6;
+import static android.system.OsConstants.IPPROTO_UDP;
+import static android.system.OsConstants.SOCK_DGRAM;
 
 import android.annotation.CallbackExecutor;
 import android.annotation.IntDef;
@@ -30,12 +34,18 @@
 import android.os.CancellationSignal;
 import android.os.Looper;
 import android.system.ErrnoException;
+import android.system.Os;
 import android.util.Log;
 
+import libcore.io.IoUtils;
+
 import java.io.FileDescriptor;
+import java.io.IOException;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.net.InetAddress;
+import java.net.InetSocketAddress;
+import java.net.SocketAddress;
 import java.net.UnknownHostException;
 import java.util.ArrayList;
 import java.util.List;
@@ -52,6 +62,7 @@
     private static final String TAG = "DnsResolver";
     private static final int FD_EVENTS = EVENT_INPUT | EVENT_ERROR;
     private static final int MAXPACKET = 8 * 1024;
+    private static final int SLEEP_TIME = 2;
 
     @IntDef(prefix = { "CLASS_" }, value = {
             CLASS_IN
@@ -188,9 +199,9 @@
      * Send a raw DNS query.
      * The answer will be provided asynchronously through the provided {@link AnswerCallback}.
      *
-     * @param network {@link Network} specifying which network for querying.
+     * @param network {@link Network} specifying which network to query on.
      *         {@code null} for query on default network.
-     * @param query blob message
+     * @param query blob message to query
      * @param flags flags as a combination of the FLAGS_* constants
      * @param executor The {@link Executor} that the callback should be executed on.
      * @param cancellationSignal used by the caller to signal if the query should be
@@ -205,26 +216,29 @@
         if (cancellationSignal != null && cancellationSignal.isCanceled()) {
             return;
         }
+        final Object lock = new Object();
         final FileDescriptor queryfd;
         try {
             queryfd = resNetworkSend((network != null
                 ? network.netId : NETID_UNSET), query, query.length, flags);
         } catch (ErrnoException e) {
-            callback.onQueryException(e);
+            executor.execute(() -> {
+                callback.onQueryException(e);
+            });
             return;
         }
 
-        maybeAddCancellationSignal(cancellationSignal, queryfd);
-        registerFDListener(executor, queryfd, callback);
+        registerFDListener(executor, queryfd, callback, cancellationSignal, lock);
+        maybeAddCancellationSignal(cancellationSignal, queryfd, lock);
     }
 
     /**
      * Send a DNS query with the specified name, class and query type.
      * The answer will be provided asynchronously through the provided {@link AnswerCallback}.
      *
-     * @param network {@link Network} specifying which network for querying.
+     * @param network {@link Network} specifying which network to query on.
      *         {@code null} for query on default network.
-     * @param domain domain name for querying
+     * @param domain domain name to query
      * @param nsClass dns class as one of the CLASS_* constants
      * @param nsType dns resource record (RR) type as one of the TYPE_* constants
      * @param flags flags as a combination of the FLAGS_* constants
@@ -242,40 +256,180 @@
         if (cancellationSignal != null && cancellationSignal.isCanceled()) {
             return;
         }
+        final Object lock = new Object();
         final FileDescriptor queryfd;
         try {
             queryfd = resNetworkQuery((network != null
                     ? network.netId : NETID_UNSET), domain, nsClass, nsType, flags);
         } catch (ErrnoException e) {
-            callback.onQueryException(e);
+            executor.execute(() -> {
+                callback.onQueryException(e);
+            });
             return;
         }
 
-        maybeAddCancellationSignal(cancellationSignal, queryfd);
-        registerFDListener(executor, queryfd, callback);
+        registerFDListener(executor, queryfd, callback, cancellationSignal, lock);
+        maybeAddCancellationSignal(cancellationSignal, queryfd, lock);
+    }
+
+    private class InetAddressAnswerAccumulator extends InetAddressAnswerCallback {
+        private final List<InetAddress> mAllAnswers;
+        private ParseException mParseException;
+        private ErrnoException mErrnoException;
+        private final InetAddressAnswerCallback mUserCallback;
+        private final int mTargetAnswerCount;
+        private int mReceivedAnswerCount = 0;
+
+        InetAddressAnswerAccumulator(int size, @NonNull InetAddressAnswerCallback callback) {
+            mTargetAnswerCount = size;
+            mAllAnswers = new ArrayList<>();
+            mUserCallback = callback;
+        }
+
+        private boolean maybeReportException() {
+            if (mErrnoException != null) {
+                mUserCallback.onQueryException(mErrnoException);
+                return true;
+            }
+            if (mParseException != null) {
+                mUserCallback.onParseException(mParseException);
+                return true;
+            }
+            return false;
+        }
+
+        private void maybeReportAnswer() {
+            if (++mReceivedAnswerCount != mTargetAnswerCount) return;
+            if (mAllAnswers.isEmpty() && maybeReportException()) return;
+            // TODO: Do RFC6724 sort.
+            mUserCallback.onAnswer(mAllAnswers);
+        }
+
+        @Override
+        public void onAnswer(@NonNull List<InetAddress> answer) {
+            mAllAnswers.addAll(answer);
+            maybeReportAnswer();
+        }
+
+        @Override
+        public void onParseException(@NonNull ParseException e) {
+            mParseException = e;
+            maybeReportAnswer();
+        }
+
+        @Override
+        public void onQueryException(@NonNull ErrnoException e) {
+            mErrnoException = e;
+            maybeReportAnswer();
+        }
+    }
+
+    /**
+     * Send a DNS query with the specified name, get back a set of InetAddresses asynchronously.
+     * The answer will be provided asynchronously through the provided
+     * {@link InetAddressAnswerCallback}.
+     *
+     * @param network {@link Network} specifying which network to query on.
+     *         {@code null} for query on default network.
+     * @param domain domain name to query
+     * @param flags flags as a combination of the FLAGS_* constants
+     * @param executor The {@link Executor} that the callback should be executed on.
+     * @param cancellationSignal used by the caller to signal if the query should be
+     *    cancelled. May be {@code null}.
+     * @param callback an {@link InetAddressAnswerCallback} which will be called to notify the
+     *    caller of the result of dns query.
+     */
+    public void query(@Nullable Network network, @NonNull String domain, @QueryFlag int flags,
+            @NonNull @CallbackExecutor Executor executor,
+            @Nullable CancellationSignal cancellationSignal,
+            @NonNull InetAddressAnswerCallback callback) {
+        if (cancellationSignal != null && cancellationSignal.isCanceled()) {
+            return;
+        }
+        final Object lock = new Object();
+        final boolean queryIpv6 = haveIpv6(network);
+        final boolean queryIpv4 = haveIpv4(network);
+
+        final FileDescriptor v4fd;
+        final FileDescriptor v6fd;
+
+        int queryCount = 0;
+
+        if (queryIpv6) {
+            try {
+                v6fd = resNetworkQuery((network != null
+                        ? network.netId : NETID_UNSET), domain, CLASS_IN, TYPE_AAAA, flags);
+            } catch (ErrnoException e) {
+                executor.execute(() -> {
+                    callback.onQueryException(e);
+                });
+                return;
+            }
+            queryCount++;
+        } else v6fd = null;
+
+        // TODO: Use device flag to controll the sleep time.
+        // Avoiding gateways drop packets if queries are sent too close together
+        try {
+            Thread.sleep(SLEEP_TIME);
+        } catch (InterruptedException ex) { }
+
+        if (queryIpv4) {
+            try {
+                v4fd = resNetworkQuery((network != null
+                        ? network.netId : NETID_UNSET), domain, CLASS_IN, TYPE_A, flags);
+            } catch (ErrnoException e) {
+                if (queryIpv6) resNetworkCancel(v6fd);  // Closes fd, marks it invalid.
+                executor.execute(() -> {
+                    callback.onQueryException(e);
+                });
+                return;
+            }
+            queryCount++;
+        } else v4fd = null;
+
+        final InetAddressAnswerAccumulator accumulator =
+                new InetAddressAnswerAccumulator(queryCount, callback);
+
+        if (queryIpv6) registerFDListener(executor, v6fd, accumulator, cancellationSignal, lock);
+        if (queryIpv4) registerFDListener(executor, v4fd, accumulator, cancellationSignal, lock);
+
+        if (cancellationSignal == null) return;
+        cancellationSignal.setOnCancelListener(() -> {
+            synchronized (lock)  {
+                if (queryIpv4) cancelQuery(v4fd);
+                if (queryIpv6) cancelQuery(v6fd);
+            }
+        });
     }
 
     private <T> void registerFDListener(@NonNull Executor executor,
-            @NonNull FileDescriptor queryfd, @NonNull AnswerCallback<T> answerCallback) {
+            @NonNull FileDescriptor queryfd, @NonNull AnswerCallback<T> answerCallback,
+            @Nullable CancellationSignal cancellationSignal, @NonNull Object lock) {
         Looper.getMainLooper().getQueue().addOnFileDescriptorEventListener(
                 queryfd,
                 FD_EVENTS,
                 (fd, events) -> {
                     executor.execute(() -> {
-                        byte[] answerbuf = null;
-                        try {
-                            answerbuf = resNetworkResult(fd);
-                        } catch (ErrnoException e) {
-                            Log.e(TAG, "resNetworkResult:" + e.toString());
-                            answerCallback.onQueryException(e);
-                            return;
-                        }
+                        synchronized (lock) {
+                            if (cancellationSignal != null && cancellationSignal.isCanceled()) {
+                                return;
+                            }
+                            byte[] answerbuf = null;
+                            try {
+                                answerbuf = resNetworkResult(fd);  // Closes fd, marks it invalid.
+                            } catch (ErrnoException e) {
+                                Log.e(TAG, "resNetworkResult:" + e.toString());
+                                answerCallback.onQueryException(e);
+                                return;
+                            }
 
-                        try {
-                            answerCallback.onAnswer(
-                                    answerCallback.parser.parse(answerbuf));
-                        } catch (ParseException e) {
-                            answerCallback.onParseException(e);
+                            try {
+                                answerCallback.onAnswer(
+                                        answerCallback.parser.parse(answerbuf));
+                            } catch (ParseException e) {
+                                answerCallback.onParseException(e);
+                            }
                         }
                     });
                     // Unregister this fd listener
@@ -283,15 +437,52 @@
                 });
     }
 
+    private void cancelQuery(@NonNull FileDescriptor queryfd) {
+        if (!queryfd.valid()) return;
+        Looper.getMainLooper().getQueue().removeOnFileDescriptorEventListener(queryfd);
+        resNetworkCancel(queryfd);  // Closes fd, marks it invalid.
+    }
+
     private void maybeAddCancellationSignal(@Nullable CancellationSignal cancellationSignal,
-            @NonNull FileDescriptor queryfd) {
+            @NonNull FileDescriptor queryfd, @NonNull Object lock) {
         if (cancellationSignal == null) return;
-        cancellationSignal.setOnCancelListener(
-                () -> {
-                    Looper.getMainLooper().getQueue()
-                            .removeOnFileDescriptorEventListener(queryfd);
-                    resNetworkCancel(queryfd);
-            });
+        cancellationSignal.setOnCancelListener(() -> {
+            synchronized (lock)  {
+                cancelQuery(queryfd);
+            }
+        });
+    }
+
+    // These two functions match the behaviour of have_ipv4 and have_ipv6 in the native resolver.
+    private boolean haveIpv4(@Nullable Network network) {
+        final SocketAddress addrIpv4 =
+                new InetSocketAddress(InetAddresses.parseNumericAddress("8.8.8.8"), 0);
+        return checkConnectivity(network, AF_INET, addrIpv4);
+    }
+
+    private boolean haveIpv6(@Nullable Network network) {
+        final SocketAddress addrIpv6 =
+                new InetSocketAddress(InetAddresses.parseNumericAddress("2000::"), 0);
+        return checkConnectivity(network, AF_INET6, addrIpv6);
+    }
+
+    private boolean checkConnectivity(@Nullable Network network,
+            int domain, @NonNull SocketAddress addr) {
+        final FileDescriptor socket;
+        try {
+            socket = Os.socket(domain, SOCK_DGRAM, IPPROTO_UDP);
+        } catch (ErrnoException e) {
+            return false;
+        }
+        try {
+            if (network != null) network.bindSocket(socket);
+            Os.connect(socket, addr);
+        } catch (IOException | ErrnoException e) {
+            return false;
+        } finally {
+            IoUtils.closeQuietly(socket);
+        }
+        return true;
     }
 
     private static class DnsAddressAnswer extends DnsPacket {
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index 8970c62..1be6c4b 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -373,7 +373,8 @@
      * A callback to be invoked when the system successfully delivers your {@link NdefMessage}
      * to another device.
      * @see #setOnNdefPushCompleteCallback
-     * @deprecated this feature is deprecated.
+     * @deprecated this feature is deprecated. File sharing can work using other technology like
+     * Bluetooth.
      */
     @java.lang.Deprecated
     public interface OnNdefPushCompleteCallback {
@@ -398,7 +399,8 @@
      * content currently visible to the user. Alternatively, you can call {@link
      * #setNdefPushMessage setNdefPushMessage()} if the {@link NdefMessage} always contains the
      * same data.
-     * @deprecated this feature is deprecated.
+     * @deprecated this feature is deprecated. File sharing can work using other technology like
+     * Bluetooth.
      */
     @java.lang.Deprecated
     public interface CreateNdefMessageCallback {
@@ -427,7 +429,8 @@
 
 
      /**
-     * @deprecated this feature is deprecated.
+     * @deprecated this feature is deprecated. File sharing can work using other technology like
+     * Bluetooth.
      */
     @java.lang.Deprecated
     public interface CreateBeamUrisCallback {
@@ -981,7 +984,8 @@
      * @param uris an array of Uri(s) to push over Android Beam
      * @param activity activity for which the Uri(s) will be pushed
      * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
-     * @deprecated this feature is deprecated.
+     * @deprecated this feature is deprecated. File sharing can work using other technology like
+     * Bluetooth.
      */
     @java.lang.Deprecated
     public void setBeamPushUris(Uri[] uris, Activity activity) {
@@ -1068,7 +1072,8 @@
      * @param callback callback, or null to disable
      * @param activity activity for which the Uri(s) will be pushed
      * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
-     * @deprecated this feature is deprecated.
+     * @deprecated this feature is deprecated. File sharing can work using other technology like
+     * Bluetooth.
      */
     @java.lang.Deprecated
     public void setBeamPushUrisCallback(CreateBeamUrisCallback callback, Activity activity) {
@@ -1157,7 +1162,8 @@
      *        to only register one at a time, and to do so in that activity's
      *        {@link Activity#onCreate}
      * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
-     * @deprecated this feature is deprecated.
+     * @deprecated this feature is deprecated. File sharing can work using other technology like
+     * Bluetooth.
      */
     @java.lang.Deprecated
     public void setNdefPushMessage(NdefMessage message, Activity activity,
@@ -1275,7 +1281,8 @@
      *        to only register one at a time, and to do so in that activity's
      *        {@link Activity#onCreate}
      * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
-     * @deprecated this feature is deprecated.
+     * @deprecated this feature is deprecated. File sharing can work using other technology like
+     * Bluetooth.
      */
     @java.lang.Deprecated
     public void setNdefPushMessageCallback(CreateNdefMessageCallback callback, Activity activity,
@@ -1361,7 +1368,8 @@
      *        to only register one at a time, and to do so in that activity's
      *        {@link Activity#onCreate}
      * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
-     * @deprecated this feature is deprecated.
+     * @deprecated this feature is deprecated. File sharing can work using other technology like
+     * Bluetooth.
      */
     @java.lang.Deprecated
     public void setOnNdefPushCompleteCallback(OnNdefPushCompleteCallback callback,
@@ -1577,7 +1585,8 @@
      * @param activity the current foreground Activity that has registered data to share
      * @return whether the Beam animation was successfully invoked
      * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
-     * @deprecated this feature is deprecated.
+     * @deprecated this feature is deprecated. File sharing can work using other technology like
+     * Bluetooth.
      */
     @java.lang.Deprecated
     public boolean invokeBeam(Activity activity) {
@@ -1822,7 +1831,8 @@
      * @see android.provider.Settings#ACTION_NFCSHARING_SETTINGS
      * @return true if NDEF Push feature is enabled
      * @throws UnsupportedOperationException if FEATURE_NFC is unavailable.
-     * @deprecated this feature is deprecated.
+     * @deprecated this feature is deprecated. File sharing can work using other technology like
+     * Bluetooth.
      */
     @java.lang.Deprecated
 
diff --git a/core/java/android/os/DropBoxManager.java b/core/java/android/os/DropBoxManager.java
index b92e713..b7cccc6 100644
--- a/core/java/android/os/DropBoxManager.java
+++ b/core/java/android/os/DropBoxManager.java
@@ -69,7 +69,8 @@
     /**
      * Broadcast Action: This is broadcast when a new entry is added in the dropbox.
      * You must hold the {@link android.Manifest.permission#READ_LOGS} permission
-     * in order to receive this broadcast.
+     * in order to receive this broadcast. This broadcast can be rate limited for low priority
+     * entries
      *
      * <p class="note">This is a protected intent that can only be sent
      * by the system.
diff --git a/core/java/android/os/INetworkManagementService.aidl b/core/java/android/os/INetworkManagementService.aidl
index 6536fc9..03e8c15 100644
--- a/core/java/android/os/INetworkManagementService.aidl
+++ b/core/java/android/os/INetworkManagementService.aidl
@@ -330,12 +330,6 @@
      */
     void removeIdleTimer(String iface);
 
-    /**
-     * Configure name servers, search paths, and resolver parameters for the given network.
-     */
-    void setDnsConfigurationForNetwork(int netId, in String[] servers, in String[] domains,
-            in int[] params, String tlsHostname, in String[] tlsServers);
-
     void setFirewallEnabled(boolean enabled);
     boolean isFirewallEnabled();
     void setFirewallInterfaceRule(String iface, boolean allow);
@@ -381,11 +375,6 @@
     void createVirtualNetwork(int netId, boolean secure);
 
     /**
-     * Remove a network.
-     */
-    void removeNetwork(int netId);
-
-    /**
      * Add an interface to a network.
      */
     void addInterfaceToNetwork(String iface, int netId);
diff --git a/core/java/android/os/IStatsManager.aidl b/core/java/android/os/IStatsManager.aidl
index 6d4c5a0..311c86d 100644
--- a/core/java/android/os/IStatsManager.aidl
+++ b/core/java/android/os/IStatsManager.aidl
@@ -217,4 +217,9 @@
      */
      oneway void sendBinaryPushStateChangedAtom(in String trainName, in long trainVersionCode,
          in int options, in int state, in long[] experimentId);
+
+    /**
+     * Returns the most recently registered experiment IDs.
+     */
+    long[] getRegisteredExperimentIds();
 }
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index f6fcdb0..56c2f4c 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -135,6 +135,7 @@
 @SystemService(Context.STORAGE_SERVICE)
 public class StorageManager {
     private static final String TAG = "StorageManager";
+    private static final boolean LOCAL_LOGV = Log.isLoggable(TAG, Log.VERBOSE);
 
     /** {@hide} */
     public static final String PROP_PRIMARY_PHYSICAL = "ro.vold.primary_physical";
@@ -1652,13 +1653,11 @@
 
     /**
      * Check that given app holds both permission and appop.
-     *
-     * @return {@code null} if the permission and appop are held, otherwise
-     *         returns a string indicating why access was denied.
+     * @hide
      */
-    private boolean checkPermissionAndAppOp(boolean enforce, int pid, int uid, String packageName,
-            String permission, int op) {
-        if (mContext.checkPermission(permission, pid, uid) != PERMISSION_GRANTED) {
+    public static boolean checkPermissionAndAppOp(Context context, boolean enforce,
+            int pid, int uid, String packageName, String permission, int op) {
+        if (context.checkPermission(permission, pid, uid) != PERMISSION_GRANTED) {
             if (enforce) {
                 throw new SecurityException(
                         "Permission " + permission + " denied for package " + packageName);
@@ -1667,7 +1666,7 @@
             }
         }
 
-        final AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class);
+        final AppOpsManager appOps = context.getSystemService(AppOpsManager.class);
         final int mode = appOps.noteOpNoThrow(op, uid, packageName);
         switch (mode) {
             case AppOpsManager.MODE_ALLOWED:
@@ -1688,6 +1687,11 @@
         }
     }
 
+    private boolean checkPermissionAndAppOp(boolean enforce,
+            int pid, int uid, String packageName, String permission, int op) {
+        return checkPermissionAndAppOp(mContext, enforce, pid, uid, packageName, permission, op);
+    }
+
     // Callers must hold both the old and new permissions, so that we can
     // handle obscure cases like when an app targets Q but was installed on
     // a device that was originally running on P before being upgraded to Q.
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index 728d77e..5631282 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -299,27 +299,6 @@
                 "device_identifier_access_restrictions_disabled";
     }
 
-    /**
-     * Telephony related properties definitions.
-     *
-     * @hide
-     */
-    public interface Telephony {
-        String NAMESPACE = "telephony";
-        /**
-         * Ringer ramping time in milliseconds.
-         */
-        String RAMPING_RINGER_DURATION = "ramping_ringer_duration";
-        /**
-         * Whether to apply ramping ringer on incoming phone calls.
-         */
-        String RAMPING_RINGER_ENABLED = "ramping_ringer_enabled";
-        /**
-         * Vibration time in milliseconds before ramping ringer starts.
-         */
-        String RAMPING_RINGER_VIBRATION_DURATION = "ramping_ringer_vibration_duration";
-    }
-
     private static final Object sLock = new Object();
     @GuardedBy("sLock")
     private static ArrayMap<OnPropertyChangedListener, Pair<String, Executor>> sSingleListeners =
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 884210d..5c2eacc 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1542,6 +1542,18 @@
             = "android.settings.CHANNEL_NOTIFICATION_SETTINGS";
 
     /**
+     * Activity Action: Show notification bubble settings for a single app.
+     * See {@link NotificationManager#areBubblesAllowed()}.
+     * <p>
+     *     Input: {@link #EXTRA_APP_PACKAGE}, the package to display.
+     * <p>
+     * Output: Nothing.
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_APP_NOTIFICATION_BUBBLE_SETTINGS
+            = "android.settings.APP_NOTIFICATION_BUBBLE_SETTINGS";
+
+    /**
      * Activity Extra: The package owner of the notification channel settings to display.
      * <p>
      * This must be passed as an extra field to the {@link #ACTION_CHANNEL_NOTIFICATION_SETTINGS}.
@@ -12395,6 +12407,19 @@
         public static final String EMERGENCY_AFFORDANCE_NEEDED = "emergency_affordance_needed";
 
         /**
+         * Whether to enable automatic system server heap dumps. This only works on userdebug or
+         * eng builds, not on user builds. This is set by the user and overrides the config value.
+         * 1 means enable, 0 means disable.
+         *
+         * @hide
+         */
+        public static final String ENABLE_AUTOMATIC_SYSTEM_SERVER_HEAP_DUMPS =
+                "enable_automatic_system_server_heap_dumps";
+
+        private static final Validator ENABLE_AUTOMATIC_SYSTEM_SERVER_HEAP_DUMPS_VALIDATOR =
+                new SettingsValidators.DiscreteValueValidator(new String[] {"0", "1"});
+
+        /**
          * See RIL_PreferredNetworkType in ril.h
          * @hide
          */
@@ -13464,24 +13489,6 @@
                 "hidden_api_blacklist_exemptions";
 
         /**
-         * Sampling rate for hidden API access event logs with libmetricslogger, as an integer in
-         * the range 0 to 0x10000 inclusive.
-         *
-         * @hide
-         */
-        public static final String HIDDEN_API_ACCESS_LOG_SAMPLING_RATE =
-                "hidden_api_access_log_sampling_rate";
-
-        /**
-         * Sampling rate for hidden API access event logging with statslog, as an integer in the
-         * range 0 to 0x10000 inclusive.
-         *
-         * @hide
-         */
-        public static final String HIDDEN_API_ACCESS_STATSLOG_SAMPLING_RATE =
-                "hidden_api_access_statslog_sampling_rate";
-
-        /**
          * Hidden API enforcement policy for apps.
          *
          * Values correspond to @{@link
@@ -13565,6 +13572,7 @@
             EMERGENCY_TONE,
             CALL_AUTO_RETRY,
             DOCK_AUDIO_MEDIA_ENABLED,
+            ENABLE_AUTOMATIC_SYSTEM_SERVER_HEAP_DUMPS,
             ENCODED_SURROUND_OUTPUT,
             ENCODED_SURROUND_OUTPUT_ENABLED_FORMATS,
             LOW_POWER_MODE_TRIGGER_LEVEL,
@@ -13607,6 +13615,8 @@
             VALIDATORS.put(EMERGENCY_TONE, EMERGENCY_TONE_VALIDATOR);
             VALIDATORS.put(CALL_AUTO_RETRY, CALL_AUTO_RETRY_VALIDATOR);
             VALIDATORS.put(DOCK_AUDIO_MEDIA_ENABLED, DOCK_AUDIO_MEDIA_ENABLED_VALIDATOR);
+            VALIDATORS.put(ENABLE_AUTOMATIC_SYSTEM_SERVER_HEAP_DUMPS,
+                    ENABLE_AUTOMATIC_SYSTEM_SERVER_HEAP_DUMPS_VALIDATOR);
             VALIDATORS.put(ENCODED_SURROUND_OUTPUT, ENCODED_SURROUND_OUTPUT_VALIDATOR);
             VALIDATORS.put(ENCODED_SURROUND_OUTPUT_ENABLED_FORMATS,
                     ENCODED_SURROUND_OUTPUT_ENABLED_FORMATS_VALIDATOR);
diff --git a/core/java/android/service/carrier/CarrierIdentifier.java b/core/java/android/service/carrier/CarrierIdentifier.java
index 6629233..af5bf74 100644
--- a/core/java/android/service/carrier/CarrierIdentifier.java
+++ b/core/java/android/service/carrier/CarrierIdentifier.java
@@ -20,6 +20,7 @@
 import android.annotation.Nullable;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.telephony.Rlog;
 import android.telephony.TelephonyManager;
 
 import com.android.internal.telephony.uicc.IccUtils;
@@ -223,7 +224,7 @@
               + "mcc=" + mMcc
               + ",mnc=" + mMnc
               + ",spn=" + mSpn
-              + ",imsi=" + mImsi
+              + ",imsi=" + Rlog.pii(false, mImsi)
               + ",gid1=" + mGid1
               + ",gid2=" + mGid2
               + ",carrierid=" + mCarrierId
diff --git a/core/java/android/service/contentcapture/ContentCaptureService.java b/core/java/android/service/contentcapture/ContentCaptureService.java
index 7a35b9e..dc57a15 100644
--- a/core/java/android/service/contentcapture/ContentCaptureService.java
+++ b/core/java/android/service/contentcapture/ContentCaptureService.java
@@ -17,6 +17,8 @@
 
 import static android.view.contentcapture.ContentCaptureHelper.sDebug;
 import static android.view.contentcapture.ContentCaptureHelper.sVerbose;
+import static android.view.contentcapture.ContentCaptureHelper.toList;
+import static android.view.contentcapture.ContentCaptureSession.NO_SESSION_ID;
 
 import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
 
@@ -36,9 +38,9 @@
 import android.os.Looper;
 import android.os.RemoteException;
 import android.service.autofill.AutofillService;
-import android.util.ArrayMap;
 import android.util.Log;
 import android.util.Slog;
+import android.util.SparseIntArray;
 import android.view.contentcapture.ContentCaptureCondition;
 import android.view.contentcapture.ContentCaptureContext;
 import android.view.contentcapture.ContentCaptureEvent;
@@ -53,7 +55,6 @@
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
-import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
 
@@ -117,7 +118,7 @@
         }
 
         @Override
-        public void onSessionStarted(ContentCaptureContext context, String sessionId, int uid,
+        public void onSessionStarted(ContentCaptureContext context, int sessionId, int uid,
                 IResultReceiver clientReceiver, int initialState) {
             mHandler.sendMessage(obtainMessage(ContentCaptureService::handleOnCreateSession,
                     ContentCaptureService.this, context, sessionId, uid, clientReceiver,
@@ -125,14 +126,14 @@
         }
 
         @Override
-        public void onActivitySnapshot(String sessionId, SnapshotData snapshotData) {
+        public void onActivitySnapshot(int sessionId, SnapshotData snapshotData) {
             mHandler.sendMessage(
                     obtainMessage(ContentCaptureService::handleOnActivitySnapshot,
                             ContentCaptureService.this, sessionId, snapshotData));
         }
 
         @Override
-        public void onSessionFinished(String sessionId) {
+        public void onSessionFinished(int sessionId) {
             mHandler.sendMessage(obtainMessage(ContentCaptureService::handleFinishSession,
                     ContentCaptureService.this, sessionId));
         }
@@ -171,7 +172,7 @@
      * <p>This map is populated when an session is started, which is called by the system server
      * and can be trusted. Then subsequent calls made by the app are verified against this map.
      */
-    private final ArrayMap<String, Integer> mSessionUids = new ArrayMap<>();
+    private final SparseIntArray mSessionUids = new SparseIntArray();
 
     @CallSuper
     @Override
@@ -240,11 +241,17 @@
      */
     public final void setContentCaptureConditions(@NonNull String packageName,
             @Nullable Set<ContentCaptureCondition> conditions) {
-        // TODO(b/129267994): implement
-    }
+        final IContentCaptureServiceCallback callback = mCallback;
+        if (callback == null) {
+            Log.w(TAG, "setContentCaptureConditions(): no server callback");
+            return;
+        }
 
-    private <T> ArrayList<T> toList(@Nullable Set<T> set) {
-        return set == null ? null : new ArrayList<T>(set);
+        try {
+            callback.setContentCaptureConditions(packageName, toList(conditions));
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
     }
 
     /**
@@ -378,7 +385,7 @@
     // so we don't need to create a temporary InteractionSessionId for each event.
 
     private void handleOnCreateSession(@NonNull ContentCaptureContext context,
-            @NonNull String sessionId, int uid, IResultReceiver clientReceiver, int initialState) {
+            int sessionId, int uid, IResultReceiver clientReceiver, int initialState) {
         mSessionUids.put(sessionId, uid);
         onCreateContentCaptureSession(context, new ContentCaptureSessionId(sessionId));
 
@@ -403,27 +410,27 @@
 
         // Most events belong to the same session, so we can keep a reference to the last one
         // to avoid creating too many ContentCaptureSessionId objects
-        String lastSessionId = null;
+        int lastSessionId = NO_SESSION_ID;
         ContentCaptureSessionId sessionId = null;
 
         final List<ContentCaptureEvent> events = parceledEvents.getList();
         for (int i = 0; i < events.size(); i++) {
             final ContentCaptureEvent event = events.get(i);
             if (!handleIsRightCallerFor(event, uid)) continue;
-            String sessionIdString = event.getSessionId();
-            if (!sessionIdString.equals(lastSessionId)) {
-                sessionId = new ContentCaptureSessionId(sessionIdString);
-                lastSessionId = sessionIdString;
+            int sessionIdInt = event.getSessionId();
+            if (sessionIdInt != lastSessionId) {
+                sessionId = new ContentCaptureSessionId(sessionIdInt);
+                lastSessionId = sessionIdInt;
             }
             switch (event.getType()) {
                 case ContentCaptureEvent.TYPE_SESSION_STARTED:
                     final ContentCaptureContext clientContext = event.getContentCaptureContext();
                     clientContext.setParentSessionId(event.getParentSessionId());
-                    mSessionUids.put(sessionIdString, uid);
+                    mSessionUids.put(sessionIdInt, uid);
                     onCreateContentCaptureSession(clientContext, sessionId);
                     break;
                 case ContentCaptureEvent.TYPE_SESSION_FINISHED:
-                    mSessionUids.remove(sessionIdString);
+                    mSessionUids.delete(sessionIdInt);
                     onDestroyContentCaptureSession(sessionId);
                     break;
                 default:
@@ -432,13 +439,12 @@
         }
     }
 
-    private void handleOnActivitySnapshot(@NonNull String sessionId,
-            @NonNull SnapshotData snapshotData) {
+    private void handleOnActivitySnapshot(int sessionId, @NonNull SnapshotData snapshotData) {
         onActivitySnapshot(new ContentCaptureSessionId(sessionId), snapshotData);
     }
 
-    private void handleFinishSession(@NonNull String sessionId) {
-        mSessionUids.remove(sessionId);
+    private void handleFinishSession(int sessionId) {
+        mSessionUids.delete(sessionId);
         onDestroyContentCaptureSession(new ContentCaptureSessionId(sessionId));
     }
 
@@ -454,7 +460,7 @@
      * Checks if the given {@code uid} owns the session associated with the event.
      */
     private boolean handleIsRightCallerFor(@NonNull ContentCaptureEvent event, int uid) {
-        final String sessionId;
+        final int sessionId;
         switch (event.getType()) {
             case ContentCaptureEvent.TYPE_SESSION_STARTED:
             case ContentCaptureEvent.TYPE_SESSION_FINISHED:
@@ -463,8 +469,7 @@
             default:
                 sessionId = event.getSessionId();
         }
-        final Integer rightUid = mSessionUids.get(sessionId);
-        if (rightUid == null) {
+        if (mSessionUids.indexOfKey(sessionId) < 0) {
             if (sVerbose) {
                 Log.v(TAG, "handleIsRightCallerFor(" + event + "): no session for " + sessionId
                         + ": " + mSessionUids);
@@ -472,6 +477,7 @@
             // Just ignore, as the session could have been finished already
             return false;
         }
+        final int rightUid = mSessionUids.get(sessionId);
         if (rightUid != uid) {
             Log.e(TAG, "invalid call from UID " + uid + ": session " + sessionId + " belongs to "
                     + rightUid);
diff --git a/core/java/android/service/contentcapture/IContentCaptureService.aidl b/core/java/android/service/contentcapture/IContentCaptureService.aidl
index 6be7a80..03e1b78 100644
--- a/core/java/android/service/contentcapture/IContentCaptureService.aidl
+++ b/core/java/android/service/contentcapture/IContentCaptureService.aidl
@@ -35,10 +35,10 @@
 oneway interface IContentCaptureService {
     void onConnected(IBinder callback, boolean verbose, boolean debug);
     void onDisconnected();
-    void onSessionStarted(in ContentCaptureContext context, String sessionId, int uid,
+    void onSessionStarted(in ContentCaptureContext context, int sessionId, int uid,
                           in IResultReceiver clientReceiver, int initialState);
-    void onSessionFinished(String sessionId);
-    void onActivitySnapshot(String sessionId, in SnapshotData snapshotData);
+    void onSessionFinished(int sessionId);
+    void onActivitySnapshot(int sessionId, in SnapshotData snapshotData);
     void onUserDataRemovalRequest(in UserDataRemovalRequest request);
     void onActivityEvent(in ActivityEvent event);
 }
diff --git a/core/java/android/service/contentcapture/IContentCaptureServiceCallback.aidl b/core/java/android/service/contentcapture/IContentCaptureServiceCallback.aidl
index 8bc8def..0550ad3 100644
--- a/core/java/android/service/contentcapture/IContentCaptureServiceCallback.aidl
+++ b/core/java/android/service/contentcapture/IContentCaptureServiceCallback.aidl
@@ -17,6 +17,7 @@
 package android.service.contentcapture;
 
 import android.content.ComponentName;
+import android.view.contentcapture.ContentCaptureCondition;
 
 import java.util.List;
 
@@ -27,5 +28,6 @@
  */
 oneway interface IContentCaptureServiceCallback {
     void setContentCaptureWhitelist(in List<String> packages, in List<ComponentName> activities);
+    void setContentCaptureConditions(String packageName, in List<ContentCaptureCondition> conditions);
     void disableSelf();
  }
diff --git a/core/java/android/service/quicksettings/TileService.java b/core/java/android/service/quicksettings/TileService.java
index c35423f..d32bdad 100644
--- a/core/java/android/service/quicksettings/TileService.java
+++ b/core/java/android/service/quicksettings/TileService.java
@@ -87,6 +87,10 @@
      * This intent may also define a {@link Intent#EXTRA_COMPONENT_NAME} value
      * to indicate the {@link ComponentName} that caused the preferences to be
      * opened.
+     * <p>
+     * To ensure that the activity can only be launched through quick settings
+     * UI provided by this service, apps can protect it with the
+     * BIND_QUICK_SETTINGS_TILE permission.
      */
     @SdkConstant(SdkConstantType.INTENT_CATEGORY)
     public static final String ACTION_QS_TILE_PREFERENCES
diff --git a/core/java/android/service/wallpaper/IWallpaperService.aidl b/core/java/android/service/wallpaper/IWallpaperService.aidl
index 99a81f5..56e2486 100644
--- a/core/java/android/service/wallpaper/IWallpaperService.aidl
+++ b/core/java/android/service/wallpaper/IWallpaperService.aidl
@@ -26,4 +26,5 @@
     void attach(IWallpaperConnection connection,
             IBinder windowToken, int windowType, boolean isPreview,
             int reqWidth, int reqHeight, in Rect padding, int displayId);
+    void detach();
 }
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index e1762df..d645e3f 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -72,6 +72,7 @@
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.function.Supplier;
 
 /**
@@ -1309,6 +1310,7 @@
         final int mDisplayId;
         final DisplayManager mDisplayManager;
         final Display mDisplay;
+        private final AtomicBoolean mDetached = new AtomicBoolean();
 
         Engine mEngine;
 
@@ -1399,8 +1401,23 @@
             mCaller.sendMessage(msg);
         }
 
+        public void detach() {
+            mDetached.set(true);
+        }
+
+        private void doDetachEngine() {
+            mActiveEngines.remove(mEngine);
+            mEngine.detach();
+        }
+
         @Override
         public void executeMessage(Message message) {
+            if (mDetached.get()) {
+                if (mActiveEngines.contains(mEngine)) {
+                    doDetachEngine();
+                }
+                return;
+            }
             switch (message.what) {
                 case DO_ATTACH: {
                     try {
@@ -1416,8 +1433,7 @@
                     return;
                 }
                 case DO_DETACH: {
-                    mActiveEngines.remove(mEngine);
-                    mEngine.detach();
+                    doDetachEngine();
                     return;
                 }
                 case DO_SET_DESIRED_SIZE: {
@@ -1497,6 +1513,7 @@
      */
     class IWallpaperServiceWrapper extends IWallpaperService.Stub {
         private final WallpaperService mTarget;
+        private IWallpaperEngineWrapper mEngineWrapper;
 
         public IWallpaperServiceWrapper(WallpaperService context) {
             mTarget = context;
@@ -1506,9 +1523,14 @@
         public void attach(IWallpaperConnection conn, IBinder windowToken,
                 int windowType, boolean isPreview, int reqWidth, int reqHeight, Rect padding,
                 int displayId) {
-            new IWallpaperEngineWrapper(mTarget, conn, windowToken,
+            mEngineWrapper = new IWallpaperEngineWrapper(mTarget, conn, windowToken,
                     windowType, isPreview, reqWidth, reqHeight, padding, displayId);
         }
+
+        @Override
+        public void detach() {
+            mEngineWrapper.detach();
+        }
     }
 
     @Override
diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl
index 87efb3f..d317df0 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -255,12 +255,11 @@
     void updatePointerIcon(IWindow window);
 
     /**
-     * Update a tap exclude region with a rectangular area identified by provided id in the window.
-     * Touches on this region will not switch focus to this window. Passing an empty rect will
-     * remove the area from the exclude region of this window.
+     * Update a tap exclude region identified by provided id in the window. Touches on this region
+     * will neither be dispatched to this window nor change the focus to this window. Passing an
+     * invalid region will remove the area from the exclude region of this window.
      */
-    void updateTapExcludeRegion(IWindow window, int regionId, int left, int top, int width,
-            int height);
+    void updateTapExcludeRegion(IWindow window, int regionId, in Region region);
 
     /**
      * Called when the client has changed the local insets state, and now the server should reflect
diff --git a/core/java/android/view/MenuInflater.java b/core/java/android/view/MenuInflater.java
index a3cd0ba..8b3b10f 100644
--- a/core/java/android/view/MenuInflater.java
+++ b/core/java/android/view/MenuInflater.java
@@ -23,7 +23,7 @@
 import android.content.res.ColorStateList;
 import android.content.res.TypedArray;
 import android.content.res.XmlResourceParser;
-import android.graphics.PorterDuff;
+import android.graphics.BlendMode;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -308,7 +308,7 @@
         private CharSequence itemTitleCondensed;
         private int itemIconResId;
         private ColorStateList itemIconTintList = null;
-        private PorterDuff.Mode itemIconTintMode = null;
+        private BlendMode mItemIconBlendMode = null;
         private char itemAlphabeticShortcut;
         private int itemAlphabeticModifiers;
         private char itemNumericShortcut;
@@ -401,12 +401,12 @@
             itemTitleCondensed = a.getText(com.android.internal.R.styleable.MenuItem_titleCondensed);
             itemIconResId = a.getResourceId(com.android.internal.R.styleable.MenuItem_icon, 0);
             if (a.hasValue(com.android.internal.R.styleable.MenuItem_iconTintMode)) {
-                itemIconTintMode = Drawable.parseTintMode(a.getInt(
+                mItemIconBlendMode = Drawable.parseBlendMode(a.getInt(
                         com.android.internal.R.styleable.MenuItem_iconTintMode, -1),
-                        itemIconTintMode);
+                        mItemIconBlendMode);
             } else {
                 // Reset to null so that it's not carried over to the next item
-                itemIconTintMode = null;
+                mItemIconBlendMode = null;
             }
             if (a.hasValue(com.android.internal.R.styleable.MenuItem_iconTint)) {
                 itemIconTintList = a.getColorStateList(
@@ -487,8 +487,8 @@
                 item.setShowAsAction(itemShowAsAction);
             }
 
-            if (itemIconTintMode != null) {
-                item.setIconTintMode(itemIconTintMode);
+            if (mItemIconBlendMode != null) {
+                item.setIconTintMode(mItemIconBlendMode);
             }
 
             if (itemIconTintList != null) {
diff --git a/core/java/android/view/MenuItem.java b/core/java/android/view/MenuItem.java
index ad160cb..3785310 100644
--- a/core/java/android/view/MenuItem.java
+++ b/core/java/android/view/MenuItem.java
@@ -18,11 +18,13 @@
 
 import android.annotation.DrawableRes;
 import android.annotation.LayoutRes;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.StringRes;
 import android.app.Activity;
 import android.content.Intent;
 import android.content.res.ColorStateList;
+import android.graphics.BlendMode;
 import android.graphics.PorterDuff;
 import android.graphics.drawable.Drawable;
 import android.view.ContextMenu.ContextMenuInfo;
@@ -268,8 +270,33 @@
      * @attr ref android.R.styleable#MenuItem_iconTintMode
      * @see #setIconTintList(ColorStateList)
      * @see Drawable#setTintMode(PorterDuff.Mode)
+     * @see Drawable#setTintMode(BlendMode)
+     *
+     * @deprecated use {@link #setIconTintMode(BlendMode)} instead
      */
-    public default MenuItem setIconTintMode(@Nullable PorterDuff.Mode tintMode) { return this; }
+    @Deprecated
+    default @NonNull MenuItem setIconTintMode(@Nullable PorterDuff.Mode tintMode) {
+        return this;
+    }
+
+    /**
+     * Specifies the blending mode used to apply the tint specified by
+     * {@link #setIconTintList(ColorStateList)} to this item's icon. The default mode is
+     * {@link BlendMode#SRC_IN}.
+     *
+     * @param blendMode the blending mode used to apply the tint, may be
+     *                 {@code null} to clear tint
+     * @attr ref android.R.styleable#MenuItem_iconTintMode
+     * @see #setIconTintList(ColorStateList)
+     */
+    default @NonNull MenuItem setIconTintMode(@Nullable BlendMode blendMode) {
+        PorterDuff.Mode mode = BlendMode.blendModeToPorterDuffMode(blendMode);
+        if (mode != null) {
+            return setIconTintMode(mode);
+        } else {
+            return this;
+        }
+    }
 
     /**
      * Returns the blending mode used to apply the tint to this item's icon, if specified.
@@ -277,9 +304,31 @@
      * @return the blending mode used to apply the tint to this item's icon
      * @attr ref android.R.styleable#MenuItem_iconTintMode
      * @see #setIconTintMode(PorterDuff.Mode)
+     * @see #setIconTintMode(BlendMode)
+     *
+     * @deprecated Use {@link #getIconTintBlendMode()} instead
      */
+    @Deprecated
     @Nullable
     public default PorterDuff.Mode getIconTintMode() { return null; }
+
+    /**
+     * Returns the blending mode used to apply the tint to this item's icon, if specified.
+     *
+     * @return the blending mode used to apply the tint to this item's icon
+     * @attr ref android.R.styleable#MenuItem_iconTintMode
+     * @see #setIconTintMode(BlendMode)
+     *
+     */
+    @Nullable
+    default BlendMode getIconTintBlendMode() {
+        PorterDuff.Mode mode = getIconTintMode();
+        if (mode != null) {
+            return BlendMode.fromValue(mode.nativeInt);
+        } else {
+            return null;
+        }
+    }
     
     /**
      * Change the Intent associated with this item.  By default there is no
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 2357db4..5df990c 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -50,6 +50,7 @@
 import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
+import android.graphics.BlendMode;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.Insets;
@@ -85,7 +86,6 @@
 import android.sysprop.DisplayProperties;
 import android.text.InputType;
 import android.text.TextUtils;
-import android.util.ArrayMap;
 import android.util.AttributeSet;
 import android.util.FloatProperty;
 import android.util.LayoutDirection;
@@ -4506,7 +4506,7 @@
 
     static class TintInfo {
         ColorStateList mTintList;
-        PorterDuff.Mode mTintMode;
+        BlendMode mBlendMode;
         boolean mHasTintMode;
         boolean mHasTintList;
     }
@@ -5687,7 +5687,7 @@
                     if (mBackgroundTint == null) {
                         mBackgroundTint = new TintInfo();
                     }
-                    mBackgroundTint.mTintMode = Drawable.parseTintMode(a.getInt(
+                    mBackgroundTint.mBlendMode = Drawable.parseBlendMode(a.getInt(
                             R.styleable.View_backgroundTintMode, -1), null);
                     mBackgroundTint.mHasTintMode = true;
                     break;
@@ -5707,7 +5707,7 @@
                     break;
                 case R.styleable.View_foregroundTintMode:
                     if (targetSdkVersion >= Build.VERSION_CODES.M || this instanceof FrameLayout) {
-                        setForegroundTintMode(Drawable.parseTintMode(a.getInt(attr, -1), null));
+                        setForegroundTintMode(Drawable.parseBlendMode(a.getInt(attr, -1), null));
                     }
                     break;
                 case R.styleable.View_foregroundTint:
@@ -8524,11 +8524,11 @@
     }
 
     /**
-     * Populates a {@link ViewStructure} for Content Capture.
+     * Populates a {@link ViewStructure} for content capture.
      *
-     * <p>This method is called after a view is that is eligible for Content Capture
+     * <p>This method is called after a view is that is eligible for content capture
      * (for example, if it {@link #isImportantForAutofill()}, an intelligence service is enabled for
-     * the user, and the activity rendering the view is enabled for Content Capture) is laid out and
+     * the user, and the activity rendering the view is enabled for content capture) is laid out and
      * is visible.
      *
      * <p>The populated structure is then passed to the service through
@@ -8547,6 +8547,16 @@
      * {@code childStructure.getAutofillId()} or
      * {@link ContentCaptureSession#newAutofillId(AutofillId, long)}.
      *
+     * <p>When the virtual view hierarchy represents a web page, you should also:
+     *
+     * <ul>
+     *   <li>Call {@link ContentCaptureManager#getContentCaptureConditions()} to infer content
+     *   capture events should be generate for that URL.
+     *   <li>Create a new {@link ContentCaptureSession} child for every HTML element that
+     *   renders a new URL (like an {@code IFRAME}) and use that session to notify events from
+     *   that subtree.
+     * </ul>
+     *
      * <p><b>Note: </b>the following methods of the {@code structure} will be ignored:
      * <ul>
      *   <li>{@link ViewStructure#setChildCount(int)}
@@ -9263,11 +9273,13 @@
     }
 
     /**
-     * Hints the Android System whether this view is considered important for Content Capture, based
+     * Hints the Android System whether this view is considered important for content capture, based
      * on the value explicitly set by {@link #setImportantForContentCapture(int)} and heuristics
      * when it's {@link #IMPORTANT_FOR_CONTENT_CAPTURE_AUTO}.
      *
-     * @return whether the view is considered important for autofill.
+     * <p>See {@link ContentCaptureManager} for more info about content capture.
+     *
+     * @return whether the view is considered important for content capture.
      *
      * @see #setImportantForContentCapture(int)
      * @see #IMPORTANT_FOR_CONTENT_CAPTURE_AUTO
@@ -9466,7 +9478,7 @@
      * Sets the (optional) {@link ContentCaptureSession} associated with this view.
      *
      * <p>This method should be called when you need to associate a {@link ContentCaptureContext} to
-     * the Content Capture events associated with this view or its view hierarchy (if it's a
+     * the content capture events associated with this view or its view hierarchy (if it's a
      * {@link ViewGroup}).
      *
      * <p>For example, if your activity is associated with a web domain, first you would need to
@@ -9497,7 +9509,7 @@
     }
 
     /**
-     * Gets the session used to notify Content Capture events.
+     * Gets the session used to notify content capture events.
      *
      * @return session explicitly set by {@link #setContentCaptureSession(ContentCaptureSession)},
      * inherited by ancestors, default session or {@code null} if content capture is disabled for
@@ -9718,7 +9730,7 @@
     }
 
     /**
-     * Dispatches the initial Content Capture events for a view structure.
+     * Dispatches the initial content capture events for a view structure.
      *
      * @hide
      */
@@ -13899,6 +13911,16 @@
     }
 
     /**
+     * Returns whether this view can receive pointer events.
+     *
+     * @return {@code true} if this view can receive pointer events.
+     * @hide
+     */
+    protected boolean canReceivePointerEvents() {
+        return (mViewFlags & VISIBILITY_MASK) == VISIBLE || getAnimation() != null;
+    }
+
+    /**
      * Filter the touch event to apply security policies.
      *
      * @param event The motion event to be filtered.
@@ -23266,7 +23288,7 @@
 
     /**
      * Applies a tint to the background drawable. Does not modify the current tint
-     * mode, which is {@link PorterDuff.Mode#SRC_IN} by default.
+     * mode, which is {@link BlendMode#SRC_IN} by default.
      * <p>
      * Subsequent calls to {@link #setBackground(Drawable)} will automatically
      * mutate the drawable and apply the specified tint and tint mode using
@@ -23311,12 +23333,36 @@
      * @attr ref android.R.styleable#View_backgroundTintMode
      * @see #getBackgroundTintMode()
      * @see Drawable#setTintMode(PorterDuff.Mode)
+     *
+     * @deprecated use @setBackgroundTintMode(BlendMode) instead
      */
+    @Deprecated
     public void setBackgroundTintMode(@Nullable PorterDuff.Mode tintMode) {
+        BlendMode mode = null;
+        if (tintMode != null) {
+            mode = BlendMode.fromValue(tintMode.nativeInt);
+        }
+
+        setBackgroundTintMode(mode);
+    }
+
+    /**
+     * Specifies the blending mode used to apply the tint specified by
+     * {@link #setBackgroundTintList(ColorStateList)}} to the background
+     * drawable. The default mode is {@link BlendMode#SRC_IN}.
+     *
+     * @param blendMode the blending mode used to apply the tint, may be
+     *                 {@code null} to clear tint
+     * @attr ref android.R.styleable#View_backgroundTintMode
+     * @see #getBackgroundTintMode()
+     * @see Drawable#setTintMode(BlendMode)
+     */
+    public void setBackgroundTintMode(@Nullable BlendMode blendMode) {
         if (mBackgroundTint == null) {
             mBackgroundTint = new TintInfo();
         }
-        mBackgroundTint.mTintMode = tintMode;
+
+        mBackgroundTint.mBlendMode = blendMode;
         mBackgroundTint.mHasTintMode = true;
 
         applyBackgroundTint();
@@ -23329,12 +23375,34 @@
      * @return the blending mode used to apply the tint to the background
      *         drawable
      * @attr ref android.R.styleable#View_backgroundTintMode
-     * @see #setBackgroundTintMode(PorterDuff.Mode)
+     * @see #setBackgroundTintMode(BlendMode)
+     *
+     * @deprecated use #getBackgroundBlendMode() instead
      */
     @Nullable
     @InspectableProperty
+    @Deprecated
     public PorterDuff.Mode getBackgroundTintMode() {
-        return mBackgroundTint != null ? mBackgroundTint.mTintMode : null;
+        PorterDuff.Mode porterDuffMode;
+        if (mBackgroundTint != null && mBackgroundTint.mBlendMode != null) {
+            porterDuffMode = BlendMode.blendModeToPorterDuffMode(mBackgroundTint.mBlendMode);
+        } else {
+            porterDuffMode = null;
+        }
+        return porterDuffMode;
+    }
+
+    /**
+     * Return the blending mode used to apply the tint to the background
+     * drawable, if specified.
+     *
+     * @return the blending mode used to apply the tint to the background
+     *         drawable, null if no blend has previously been configured
+     * @attr ref android.R.styleable#View_backgroundTintMode
+     * @see #setBackgroundTintMode(BlendMode)
+     */
+    public @Nullable BlendMode getBackgroundBlendMode() {
+        return mBackgroundTint != null ? mBackgroundTint.mBlendMode : null;
     }
 
     private void applyBackgroundTint() {
@@ -23348,7 +23416,7 @@
                 }
 
                 if (tintInfo.mHasTintMode) {
-                    mBackground.setTintMode(tintInfo.mTintMode);
+                    mBackground.setTintMode(tintInfo.mBlendMode);
                 }
 
                 // The drawable (or one of its children) may not have been
@@ -23532,15 +23600,37 @@
      * @attr ref android.R.styleable#View_foregroundTintMode
      * @see #getForegroundTintMode()
      * @see Drawable#setTintMode(PorterDuff.Mode)
+     *
+     * @deprecated use #setForegroundTintMode(BlendMode)
      */
+    @Deprecated
     public void setForegroundTintMode(@Nullable PorterDuff.Mode tintMode) {
+        BlendMode mode = null;
+        if (tintMode != null) {
+            mode = BlendMode.fromValue(tintMode.nativeInt);
+        }
+        setForegroundTintMode(mode);
+    }
+
+    /**
+     * Specifies the blending mode used to apply the tint specified by
+     * {@link #setForegroundTintList(ColorStateList)}} to the background
+     * drawable. The default mode is {@link BlendMode#SRC_IN}.
+     *
+     * @param blendMode the blending mode used to apply the tint, may be
+     *                 {@code null} to clear tint
+     * @attr ref android.R.styleable#View_foregroundTintMode
+     * @see #getForegroundTintMode()
+     * @see Drawable#setTintMode(BlendMode)
+     */
+    public void setForegroundTintMode(@Nullable BlendMode blendMode) {
         if (mForegroundInfo == null) {
             mForegroundInfo = new ForegroundInfo();
         }
         if (mForegroundInfo.mTintInfo == null) {
             mForegroundInfo.mTintInfo = new TintInfo();
         }
-        mForegroundInfo.mTintInfo.mTintMode = tintMode;
+        mForegroundInfo.mTintInfo.mBlendMode = blendMode;
         mForegroundInfo.mTintInfo.mHasTintMode = true;
 
         applyForegroundTint();
@@ -23554,12 +23644,35 @@
      *         drawable
      * @attr ref android.R.styleable#View_foregroundTintMode
      * @see #setForegroundTintMode(PorterDuff.Mode)
+     *
+     * @deprecated use #getForegroundBlendMode() instead
      */
     @InspectableProperty
     @Nullable
+    @Deprecated
     public PorterDuff.Mode getForegroundTintMode() {
+        BlendMode blendMode = mForegroundInfo != null && mForegroundInfo.mTintInfo != null
+                ? mForegroundInfo.mTintInfo.mBlendMode : null;
+        if (blendMode != null) {
+            return BlendMode.blendModeToPorterDuffMode(blendMode);
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Return the blending mode used to apply the tint to the foreground
+     * drawable, if specified.
+     *
+     * @return the blending mode used to apply the tint to the foreground
+     *         drawable
+     * @attr ref android.R.styleable#View_foregroundTintMode
+     * @see #setForegroundTintMode(BlendMode)
+     *
+     */
+    public @Nullable BlendMode getForegroundBlendMode() {
         return mForegroundInfo != null && mForegroundInfo.mTintInfo != null
-                ? mForegroundInfo.mTintInfo.mTintMode : null;
+                ? mForegroundInfo.mTintInfo.mBlendMode : null;
     }
 
     private void applyForegroundTint() {
@@ -23574,7 +23687,7 @@
                 }
 
                 if (tintInfo.mHasTintMode) {
-                    mForegroundInfo.mDrawable.setTintMode(tintInfo.mTintMode);
+                    mForegroundInfo.mDrawable.setTintMode(tintInfo.mBlendMode);
                 }
 
                 // The drawable (or one of its children) may not have been
@@ -28486,8 +28599,7 @@
          * hierarchy is traversed: value is either the view itself for appearead events, or its
          * autofill id for disappeared.
          */
-        // TODO(b/121197119): use SparseArray once session id becomes integer
-        ArrayMap<String, ArrayList<Object>> mContentCaptureEvents;
+        SparseArray<ArrayList<Object>> mContentCaptureEvents;
 
         /**
          * Cached reference to the {@link ContentCaptureManager}.
@@ -28517,9 +28629,9 @@
                 @NonNull View view, boolean appeared) {
             if (mContentCaptureEvents == null) {
                 // Most of the time there will be just one session, so intial capacity is 1
-                mContentCaptureEvents = new ArrayMap<>(1);
+                mContentCaptureEvents = new SparseArray<>(1);
             }
-            String sessionId = session.getId();
+            int sessionId = session.getId();
             // TODO: life would be much easier if we provided a MultiMap implementation somwhere...
             ArrayList<Object> events = mContentCaptureEvents.get(sessionId);
             if (events == null) {
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 4851476..937bd1b 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -2011,7 +2011,7 @@
             for (int i = childrenCount - 1; i >= 0; i--) {
                 final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
                 final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);
-                if (!canViewReceivePointerEvents(child)
+                if (!child.canReceivePointerEvents()
                         || !isTransformedTouchPointInView(x, y, child, null)) {
                     continue;
                 }
@@ -2094,7 +2094,7 @@
                             childrenCount, i, customOrder);
                     final View child = getAndVerifyPreorderedView(
                             preorderedList, children, childIndex);
-                    if (!canViewReceivePointerEvents(child)
+                    if (!child.canReceivePointerEvents()
                             || !isTransformedTouchPointInView(x, y, child, null)) {
                         continue;
                     }
@@ -2314,7 +2314,7 @@
                                 getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
                         final View child =
                                 getAndVerifyPreorderedView(preorderedList, children, childIndex);
-                        if (!canViewReceivePointerEvents(child)
+                        if (!child.canReceivePointerEvents()
                                 || !isTransformedTouchPointInView(x, y, child, null)) {
                             continue;
                         }
@@ -2500,7 +2500,7 @@
             for (int i = childrenCount - 1; i >= 0; i--) {
                 final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
                 final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);
-                if (!canViewReceivePointerEvents(child)
+                if (!child.canReceivePointerEvents()
                         || !isTransformedTouchPointInView(x, y, child, null)) {
                     continue;
                 }
@@ -2680,7 +2680,7 @@
                                 i = childrenCount - 1;
                             }
 
-                            if (!canViewReceivePointerEvents(child)
+                            if (!child.canReceivePointerEvents()
                                     || !isTransformedTouchPointInView(x, y, child, null)) {
                                 ev.setTargetAccessibilityFocus(false);
                                 continue;
@@ -2970,15 +2970,6 @@
         }
     }
 
-    /**
-     * Returns true if a child view can receive pointer events.
-     * @hide
-     */
-    private static boolean canViewReceivePointerEvents(@NonNull View child) {
-        return (child.mViewFlags & VISIBILITY_MASK) == VISIBLE
-                || child.getAnimation() != null;
-    }
-
     private float[] getTempPoint() {
         if (mTempPoint == null) {
             mTempPoint = new float[2];
@@ -7199,6 +7190,46 @@
         }
     }
 
+    /**
+     * @hide
+     */
+    @Override
+    public void subtractObscuredTouchableRegion(Region touchableRegion, View view) {
+        final int childrenCount = mChildrenCount;
+        final ArrayList<View> preorderedList = buildTouchDispatchChildList();
+        final boolean customOrder = preorderedList == null && isChildrenDrawingOrderEnabled();
+        final View[] children = mChildren;
+        for (int i = childrenCount - 1; i >= 0; i--) {
+            final int childIndex = getAndVerifyPreorderedIndex(childrenCount, i, customOrder);
+            final View child = getAndVerifyPreorderedView(preorderedList, children, childIndex);
+            if (child == view) {
+                // We've reached the target view.
+                break;
+            }
+            if (!child.canReceivePointerEvents()) {
+                // This child cannot be touched. Skip it.
+                continue;
+            }
+            applyOpToRegionByBounds(touchableRegion, child, Region.Op.DIFFERENCE);
+        }
+
+        // The touchable region should not exceed the bounds of its container.
+        applyOpToRegionByBounds(touchableRegion, this, Region.Op.INTERSECT);
+
+        final ViewParent parent = getParent();
+        if (parent != null) {
+            parent.subtractObscuredTouchableRegion(touchableRegion, this);
+        }
+    }
+
+    private static void applyOpToRegionByBounds(Region region, View view, Region.Op op) {
+        final int[] locationInWindow = new int[2];
+        view.getLocationInWindow(locationInWindow);
+        final int x = locationInWindow[0];
+        final int y = locationInWindow[1];
+        region.op(x, y, x + view.getWidth(), y + view.getHeight(), op);
+    }
+
     @Override
     public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) {
         insets = super.dispatchApplyWindowInsets(insets);
diff --git a/core/java/android/view/ViewParent.java b/core/java/android/view/ViewParent.java
index 572e69b..feba7bb 100644
--- a/core/java/android/view/ViewParent.java
+++ b/core/java/android/view/ViewParent.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.graphics.Rect;
+import android.graphics.Region;
 import android.os.Bundle;
 import android.view.accessibility.AccessibilityEvent;
 
@@ -660,4 +661,17 @@
      * @return true if the action was consumed by this ViewParent
      */
     public boolean onNestedPrePerformAccessibilityAction(View target, int action, Bundle arguments);
+
+    /**
+     * Given a touchable region of a child, this method reduces region by the bounds of all views on
+     * top of the child for which {@link View#canReceivePointerEvents} returns {@code true}. This
+     * applies recursively for all views in the view hierarchy on top of this one.
+     *
+     * @param touchableRegion The touchable region we want to modify.
+     * @param view A child view of this ViewGroup which indicates the z-order of the touchable
+     *             region.
+     * @hide
+     */
+    default void subtractObscuredTouchableRegion(Region touchableRegion, View view) {
+    }
 }
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 2880e7f..5f60333 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -2811,8 +2811,7 @@
             MainContentCaptureSession mainSession = mAttachInfo.mContentCaptureManager
                     .getMainContentCaptureSession();
             for (int i = 0; i < mAttachInfo.mContentCaptureEvents.size(); i++) {
-                String sessionId = mAttachInfo.mContentCaptureEvents
-                        .keyAt(i);
+                int sessionId = mAttachInfo.mContentCaptureEvents.keyAt(i);
                 mainSession.notifyViewTreeEvent(sessionId, /* started= */ true);
                 ArrayList<Object> events = mAttachInfo.mContentCaptureEvents
                         .valueAt(i);
@@ -2827,8 +2826,8 @@
                             Log.w(mTag, "no content capture session on view: " + view);
                             continue for_each_event;
                         }
-                        String actualId = session.getId().toString();
-                        if (!actualId.equals(sessionId)) {
+                        int actualId = session.getId();
+                        if (actualId != sessionId) {
                             Log.w(mTag, "content capture session mismatch for view (" + view
                                     + "): was " + sessionId + " before, it's " + actualId + " now");
                             continue for_each_event;
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 385d491..774a359 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -1682,17 +1682,29 @@
     }
 
     /**
-     * Gets the node bounds in parent coordinates.
+     * Gets the node bounds in the viewParent's coordinates.
+     * {@link #getParent()} does not represent the source's viewParent.
+     * Instead it represents the result of {@link View#getParentForAccessibility()},
+     * which returns the closest ancestor where {@link View#isImportantForAccessibility()} is true.
+     * So this method is not reliable.
      *
      * @param outBounds The output node bounds.
+     * @deprecated Use {@link #getBoundsInScreen(Rect)} instead.
+     *
      */
+    @Deprecated
     public void getBoundsInParent(Rect outBounds) {
         outBounds.set(mBoundsInParent.left, mBoundsInParent.top,
                 mBoundsInParent.right, mBoundsInParent.bottom);
     }
 
     /**
-     * Sets the node bounds in parent coordinates.
+     * Sets the node bounds in the viewParent's coordinates.
+     * {@link #getParent()} does not represent the source's viewParent.
+     * Instead it represents the result of {@link View#getParentForAccessibility()},
+     * which returns the closest ancestor where {@link View#isImportantForAccessibility()} is true.
+     * So this method is not reliable.
+     *
      * <p>
      *   <strong>Note:</strong> Cannot be called from an
      *   {@link android.accessibilityservice.AccessibilityService}.
@@ -1702,7 +1714,9 @@
      * @param bounds The node bounds.
      *
      * @throws IllegalStateException If called from an AccessibilityService.
+     * @deprecated Accessibility services should not care about these bounds.
      */
+    @Deprecated
     public void setBoundsInParent(Rect bounds) {
         enforceNotSealed();
         mBoundsInParent.set(bounds.left, bounds.top, bounds.right, bounds.bottom);
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 77a0c4c..6503a80 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -2178,6 +2178,18 @@
             boolean saveOnAllViewsInvisible, boolean saveOnFinish,
             @Nullable AutofillId[] fillableIds, @Nullable AutofillId saveTriggerId) {
         synchronized (mLock) {
+            if (sVerbose) {
+                Log.v(TAG, "setTrackedViews(): sessionId=" + sessionId
+                        + ", trackedIds=" + Arrays.toString(trackedIds)
+                        + ", saveOnAllViewsInvisible=" + saveOnAllViewsInvisible
+                        + ", saveOnFinish=" + saveOnFinish
+                        + ", fillableIds=" + Arrays.toString(fillableIds)
+                        + ", saveTrigerId=" + saveTriggerId
+                        + ", mFillableIds=" + mFillableIds
+                        + ", mEnabled=" + mEnabled
+                        + ", mSessionId=" + mSessionId);
+
+            }
             if (mEnabled && mSessionId == sessionId) {
                 if (saveOnAllViewsInvisible) {
                     mTrackedViews = new TrackedViews(trackedIds);
@@ -2192,10 +2204,6 @@
                     for (AutofillId id : fillableIds) {
                         mFillableIds.add(id);
                     }
-                    if (sVerbose) {
-                        Log.v(TAG, "setTrackedViews(): fillableIds=" + Arrays.toString(fillableIds)
-                                + ", mFillableIds" + mFillableIds);
-                    }
                 }
 
                 if (mSaveTriggerId != null && !mSaveTriggerId.equals(saveTriggerId)) {
diff --git a/core/java/android/view/autofill/AutofillManagerInternal.java b/core/java/android/view/autofill/AutofillManagerInternal.java
index d5862bd..3de1a03 100644
--- a/core/java/android/view/autofill/AutofillManagerInternal.java
+++ b/core/java/android/view/autofill/AutofillManagerInternal.java
@@ -33,7 +33,10 @@
     public abstract void onBackKeyPressed();
 
     /**
-     * Gets autofill options for a package
+     * Gets autofill options for a package.
+     *
+     * <p><b>NOTE: </b>this method is called by the {@code ActivityManager} service and hence cannot
+     * hold the main service lock.
      *
      * @param packageName The package for which to query.
      * @param versionCode The package version code.
diff --git a/cmds/statsd/src/logd/LogListener.cpp b/core/java/android/view/contentcapture/ContentCaptureCondition.aidl
similarity index 60%
rename from cmds/statsd/src/logd/LogListener.cpp
rename to core/java/android/view/contentcapture/ContentCaptureCondition.aidl
index ddb26f9..99f8894 100644
--- a/cmds/statsd/src/logd/LogListener.cpp
+++ b/core/java/android/view/contentcapture/ContentCaptureCondition.aidl
@@ -1,11 +1,11 @@
-/*
- * Copyright (C) 2017 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.
  * You may obtain a copy of the License at
  *
- *      http://www.apache.org/licenses/LICENSE-2.0
+ *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
@@ -14,18 +14,6 @@
  * limitations under the License.
  */
 
-#include "logd/LogListener.h"
+package android.view.contentcapture;
 
-namespace android {
-namespace os {
-namespace statsd {
-
-LogListener::LogListener() {
-}
-
-LogListener::~LogListener() {
-}
-
-}  // namespace statsd
-}  // namespace os
-}  // namespace android
+parcelable ContentCaptureCondition;
diff --git a/core/java/android/view/contentcapture/ContentCaptureCondition.java b/core/java/android/view/contentcapture/ContentCaptureCondition.java
index ed87257..cf171d7 100644
--- a/core/java/android/view/contentcapture/ContentCaptureCondition.java
+++ b/core/java/android/view/contentcapture/ContentCaptureCondition.java
@@ -20,6 +20,7 @@
 import android.content.LocusId;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.util.DebugUtils;
 
 import com.android.internal.util.Preconditions;
 
@@ -58,7 +59,6 @@
     public ContentCaptureCondition(@NonNull LocusId locusId, @Flags int flags) {
         this.mLocusId = Preconditions.checkNotNull(locusId);
         this.mFlags = flags;
-        // TODO(b/129267994): check flags, add test case for null and invalid flags
     }
 
     /**
@@ -79,6 +79,42 @@
     }
 
     @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + mFlags;
+        result = prime * result + ((mLocusId == null) ? 0 : mLocusId.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) return true;
+        if (obj == null) return false;
+        if (getClass() != obj.getClass()) return false;
+        final ContentCaptureCondition other = (ContentCaptureCondition) obj;
+        if (mFlags != other.mFlags) return false;
+        if (mLocusId == null) {
+            if (other.mLocusId != null) return false;
+        } else {
+            if (!mLocusId.equals(other.mLocusId)) return false;
+        }
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder string = new StringBuilder(mLocusId.toString()); // LocusID is PII safe
+        if (mFlags != 0) {
+            string
+                .append(" (")
+                .append(DebugUtils.flagsToString(ContentCaptureCondition.class, "FLAG_", mFlags))
+                .append(')');
+        }
+        return string.toString();
+    }
+
+    @Override
     public int describeContents() {
         return 0;
     }
diff --git a/core/java/android/view/contentcapture/ContentCaptureContext.java b/core/java/android/view/contentcapture/ContentCaptureContext.java
index 5a27e94..94e548f 100644
--- a/core/java/android/view/contentcapture/ContentCaptureContext.java
+++ b/core/java/android/view/contentcapture/ContentCaptureContext.java
@@ -15,6 +15,8 @@
  */
 package android.view.contentcapture;
 
+import static android.view.contentcapture.ContentCaptureSession.NO_SESSION_ID;
+
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -35,9 +37,9 @@
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
-
 /**
- * Context associated with a {@link ContentCaptureSession}.
+ * Context associated with a {@link ContentCaptureSession} - see {@link ContentCaptureManager} for
+ * more info.
  */
 public final class ContentCaptureContext implements Parcelable {
 
@@ -50,8 +52,7 @@
 
     /**
      * Flag used to indicate that the app explicitly disabled content capture for the activity
-     * (using
-     * {@link android.view.contentcapture.ContentCaptureManager#setContentCaptureEnabled(boolean)}),
+     * (using {@link ContentCaptureManager#setContentCaptureEnabled(boolean)}),
      * in which case the service will just receive activity-level events.
      *
      * @hide
@@ -107,7 +108,7 @@
     private final int mDisplayId;
 
     // Fields below are set by the service upon "delivery" and are not marshalled in the parcel
-    private @Nullable String mParentSessionId;
+    private int mParentSessionId = NO_SESSION_ID;
 
     /** @hide */
     public ContentCaptureContext(@Nullable ContentCaptureContext clientContext,
@@ -198,11 +199,12 @@
     @SystemApi
     @TestApi
     public @Nullable ContentCaptureSessionId getParentSessionId() {
-        return mParentSessionId == null ?  null : new ContentCaptureSessionId(mParentSessionId);
+        return mParentSessionId == NO_SESSION_ID ? null
+                : new ContentCaptureSessionId(mParentSessionId);
     }
 
     /** @hide */
-    public void setParentSessionId(@NonNull String parentSessionId) {
+    public void setParentSessionId(int parentSessionId) {
         mParentSessionId = parentSessionId;
     }
 
@@ -260,9 +262,10 @@
          *   <li>A unique identifier of the application state (for example, a conversation between
          *   2 users in a chat app).
          *
+         * <p>See {@link ContentCaptureManager} for more info about the content capture context.
+         *
          * @param id id associated with this context.
          */
-        // TODO(b/123577059): make sure this is well documented and understandable
         public Builder(@NonNull LocusId id) {
             mId = Preconditions.checkNotNull(id);
         }
@@ -316,7 +319,7 @@
         }
         pw.print(", taskId="); pw.print(mTaskId);
         pw.print(", displayId="); pw.print(mDisplayId);
-        if (mParentSessionId != null) {
+        if (mParentSessionId != NO_SESSION_ID) {
             pw.print(", parentId="); pw.print(mParentSessionId);
         }
         if (mFlags > 0) {
@@ -348,7 +351,7 @@
                 builder.append(", hasExtras");
             }
         }
-        if (mParentSessionId != null) {
+        if (mParentSessionId != NO_SESSION_ID) {
             builder.append(", parentId=").append(mParentSessionId);
         }
         return builder.append(']').toString();
diff --git a/core/java/android/view/contentcapture/ContentCaptureEvent.java b/core/java/android/view/contentcapture/ContentCaptureEvent.java
index 8188e05..bd38629 100644
--- a/core/java/android/view/contentcapture/ContentCaptureEvent.java
+++ b/core/java/android/view/contentcapture/ContentCaptureEvent.java
@@ -16,6 +16,7 @@
 package android.view.contentcapture;
 
 import static android.view.contentcapture.ContentCaptureHelper.getSanitizedString;
+import static android.view.contentcapture.ContentCaptureSession.NO_SESSION_ID;
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
@@ -126,25 +127,25 @@
     @Retention(RetentionPolicy.SOURCE)
     public @interface EventType{}
 
-    private final @NonNull String mSessionId;
+    private final int mSessionId;
     private final int mType;
     private final long mEventTime;
     private @Nullable AutofillId mId;
     private @Nullable ArrayList<AutofillId> mIds;
     private @Nullable ViewNode mNode;
     private @Nullable CharSequence mText;
-    private @Nullable String mParentSessionId;
+    private int mParentSessionId = NO_SESSION_ID;
     private @Nullable ContentCaptureContext mClientContext;
 
     /** @hide */
-    public ContentCaptureEvent(@NonNull String sessionId, int type, long eventTime) {
+    public ContentCaptureEvent(int sessionId, int type, long eventTime) {
         mSessionId = sessionId;
         mType = type;
         mEventTime = eventTime;
     }
 
     /** @hide */
-    public ContentCaptureEvent(@NonNull String sessionId, int type) {
+    public ContentCaptureEvent(int sessionId, int type) {
         this(sessionId, type, System.currentTimeMillis());
     }
 
@@ -185,7 +186,7 @@
      *
      * @hide
      */
-    public ContentCaptureEvent setParentSessionId(@NonNull String parentSessionId) {
+    public ContentCaptureEvent setParentSessionId(int parentSessionId) {
         mParentSessionId = parentSessionId;
         return this;
     }
@@ -202,7 +203,7 @@
 
     /** @hide */
     @NonNull
-    public String getSessionId() {
+    public int getSessionId() {
         return mSessionId;
     }
 
@@ -212,7 +213,7 @@
      * @hide
      */
     @Nullable
-    public String getParentSessionId() {
+    public int getParentSessionId() {
         return mParentSessionId;
     }
 
@@ -357,10 +358,10 @@
         if (mNode != null) {
             pw.print(", mNode.id="); pw.print(mNode.getAutofillId());
         }
-        if (mSessionId != null) {
+        if (mSessionId != NO_SESSION_ID) {
             pw.print(", sessionId="); pw.print(mSessionId);
         }
-        if (mParentSessionId != null) {
+        if (mParentSessionId != NO_SESSION_ID) {
             pw.print(", parentSessionId="); pw.print(mParentSessionId);
         }
         if (mText != null) {
@@ -377,7 +378,7 @@
         final StringBuilder string = new StringBuilder("ContentCaptureEvent[type=")
                 .append(getTypeAsString(mType));
         string.append(", session=").append(mSessionId);
-        if (mType == TYPE_SESSION_STARTED && mParentSessionId != null) {
+        if (mType == TYPE_SESSION_STARTED && mParentSessionId != NO_SESSION_ID) {
             string.append(", parent=").append(mParentSessionId);
         }
         if (mId != null) {
@@ -409,7 +410,7 @@
 
     @Override
     public void writeToParcel(Parcel parcel, int flags) {
-        parcel.writeString(mSessionId);
+        parcel.writeInt(mSessionId);
         parcel.writeInt(mType);
         parcel.writeLong(mEventTime);
         parcel.writeParcelable(mId, flags);
@@ -417,7 +418,7 @@
         ViewNode.writeToParcel(parcel, mNode, flags);
         parcel.writeCharSequence(mText);
         if (mType == TYPE_SESSION_STARTED || mType == TYPE_SESSION_FINISHED) {
-            parcel.writeString(mParentSessionId);
+            parcel.writeInt(mParentSessionId);
         }
         if (mType == TYPE_SESSION_STARTED || mType == TYPE_CONTEXT_UPDATED) {
             parcel.writeParcelable(mClientContext, flags);
@@ -430,7 +431,7 @@
         @Override
         @NonNull
         public ContentCaptureEvent createFromParcel(Parcel parcel) {
-            final String sessionId = parcel.readString();
+            final int sessionId = parcel.readInt();
             final int type = parcel.readInt();
             final long eventTime  = parcel.readLong();
             final ContentCaptureEvent event = new ContentCaptureEvent(sessionId, type, eventTime);
@@ -448,7 +449,7 @@
             }
             event.setText(parcel.readCharSequence());
             if (type == TYPE_SESSION_STARTED || type == TYPE_SESSION_FINISHED) {
-                event.setParentSessionId(parcel.readString());
+                event.setParentSessionId(parcel.readInt());
             }
             if (type == TYPE_SESSION_STARTED || type == TYPE_CONTEXT_UPDATED) {
                 event.setClientContext(parcel.readParcelable(null));
diff --git a/core/java/android/view/contentcapture/ContentCaptureHelper.java b/core/java/android/view/contentcapture/ContentCaptureHelper.java
index 6bc3829..c7ca220 100644
--- a/core/java/android/view/contentcapture/ContentCaptureHelper.java
+++ b/core/java/android/view/contentcapture/ContentCaptureHelper.java
@@ -23,9 +23,14 @@
 import android.annotation.Nullable;
 import android.os.Build;
 import android.provider.DeviceConfig;
+import android.util.ArraySet;
 import android.util.Log;
 import android.view.contentcapture.ContentCaptureManager.LoggingLevel;
 
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+
 /**
  * Helper class for this package and server's.
  *
@@ -101,6 +106,22 @@
         }
     }
 
+    /**
+     * Converts a set to a list.
+     */
+    @Nullable
+    public static <T> ArrayList<T> toList(@Nullable Set<T> set) {
+        return set == null ? null : new ArrayList<T>(set);
+    }
+
+    /**
+     * Converts a list to a set.
+     */
+    @Nullable
+    public static <T> ArraySet<T> toSet(@Nullable List<T> list) {
+        return list == null ? null : new ArraySet<T>(list);
+    }
+
     private ContentCaptureHelper() {
         throw new UnsupportedOperationException("contains only static methods");
     }
diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
index 817b130..2539356 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -17,6 +17,7 @@
 
 import static android.view.contentcapture.ContentCaptureHelper.sDebug;
 import static android.view.contentcapture.ContentCaptureHelper.sVerbose;
+import static android.view.contentcapture.ContentCaptureHelper.toSet;
 
 import android.annotation.IntDef;
 import android.annotation.NonNull;
@@ -28,12 +29,15 @@
 import android.content.ComponentName;
 import android.content.ContentCaptureOptions;
 import android.content.Context;
+import android.graphics.Canvas;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.util.Log;
+import android.view.View;
+import android.view.ViewStructure;
 import android.view.contentcapture.ContentCaptureSession.FlushReason;
 
 import com.android.internal.annotations.GuardedBy;
@@ -43,10 +47,152 @@
 import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
 import java.util.Set;
 
 /**
- * TODO(b/123577059): add javadocs / mention it can be null
+ * <p>The {@link ContentCaptureManager} provides additional ways for for apps to
+ * integrate with the content capture subsystem.
+ *
+ * <p>Content capture provides real-time, continuous capture of application activity, display and
+ * events to an intelligence service that is provided by the Android system. The intelligence
+ * service then uses that info to mediate and speed user journey through different apps. For
+ * example, when the user receives a restaurant address in a chat app and switchs to a map app
+ * to search for that restaurant, the intelligence service could offer an autofill dialog to
+ * let the user automatically select its address.
+ *
+ * <p>Content capture was designed with two major concerns in mind: privacy and performance.
+ *
+ * <ul>
+ *   <li><b>Privacy:</b> the intelligence service is a trusted component provided that is provided
+ *   by the device manufacturer and that cannot be changed by the user (although the user can
+ *   globaly disable content capture using the Android Settings app). This service can only use the
+ *   data for in-device machine learning, which is enforced both by process isolation and
+ *   <a href="https://source.android.com/compatibility/cdd">CDD requirements</a>.
+ *   <li><b>Performance:</b> content capture is highly optimized to minimize its impact in the app
+ *   jankiness and overall device system health. For example, its only enabled on apps (or even
+ *   specific activities from an app) that were explicitly whitelisted by the intelligence service,
+ *   and it buffers the events so they are sent in a batch to the service (see
+ *   {@link #isContentCaptureEnabled()} for other cases when its disabled).
+ * </ul>
+ *
+ * <p>In fact, before using this manager, the app developer should check if it's available. Example:
+ *  <code>
+ *  ContentCaptureManager mgr = context.getSystemService(ContentCaptureManager.class);
+ *  if (mgr != null && mgr.isContentCaptureEnabled()) {
+ *    // ...
+ *  }
+ *  </code>
+ *
+ * <p>App developers usually don't need to explicitly interact with content capture, except when the
+ * app:
+ *
+ * <ul>
+ *   <li>Can define a contextual {@link android.content.LocusId} to identify unique state (such as a
+ *   conversation between 2 chat users).
+ *   <li>Can have multiple view hierarchies with different contextual meaning (for example, a
+ *   browser app with multiple tabs, each representing a different URL).
+ *   <li>Contains custom views (that extend View directly and are not provided by the standard
+ *   Android SDK.
+ *   <li>Contains views that provide their own virtual hierarchy (like a web browser that render the
+ *   HTML elements using a Canvas).
+ * </ul>
+ *
+ * <p>The main integration point with content capture is the {@link ContentCaptureSession}. A "main"
+ * session is automatically created by the Android System when content capture is enabled for the
+ * activity and its used by the standard Android views to notify the content capture service of
+ * events such as views being added, views been removed, and text changed by user input. The session
+ * could have a {@link ContentCaptureContext} to provide more contextual info about it, such as
+ * the locus associated with the view hierarchy (see {@link android.content.LocusId} for more info
+ * about locus). By default, the main session doesn't have a {@code ContentCaptureContext}, but you
+ * can change it after its created. Example:
+ *
+ * <pre><code>
+ * protected void onCreate(Bundle savedInstanceState) {
+ *   // Initialize view structure
+ *   ContentCaptureSession session = rootView.getContentCaptureSession();
+ *   if (session != null) {
+ *     session.setContentCaptureContext(ContentCaptureContext.forLocusId("chat_UserA_UserB"));
+ *   }
+ * }
+ * </code></pre>
+ *
+ * <p>If your activity contains view hierarchies with a different contextual meaning, you should
+ * created child sessions for each view hierarchy root. For example, if your activity is a browser,
+ * you could use the main session for the main URL being rendered, then child sessions for each
+ * {@code IFRAME}:
+ *
+ * <pre><code>
+ * ContentCaptureSession mMainSession;
+ *
+ * protected void onCreate(Bundle savedInstanceState) {
+ *    // Initialize view structure...
+ *    mMainSession = rootView.getContentCaptureSession();
+ *    if (mMainSession != null) {
+ *      mMainSession.setContentCaptureContext(
+ *          ContentCaptureContext.forLocusId("https://example.com"));
+ *    }
+ * }
+ *
+ * private void loadIFrame(View iframeRootView, String url) {
+ *   if (mMainSession != null) {
+ *      ContentCaptureSession iFrameSession = mMainSession.newChild(
+ *          ContentCaptureContext.forLocusId(url));
+ *      }
+ *      iframeRootView.setContentCaptureSession(iFrameSession);
+ *   }
+ *   // Load iframe...
+ * }
+ * </code></pre>
+ *
+ * <p>If your activity has custom views (i.e., views that extend {@link View} directly and provide
+ * just one logical view, not a virtual tree hiearchy) and it provides content that's relevant for
+ * content capture (as of {@link android.os.Build.VERSION_CODES#Q Android Q}, the only relevant
+ * content is text), then your view implementation should:
+ *
+ * <ul>
+ *   <li>Set it as important for content capture.
+ *   <li>Fill {@link ViewStructure} used for content capture.
+ *   <li>Notify the {@link ContentCaptureSession} when the text is changed by user input.
+ * </ul>
+ *
+ * <p>Here's an example of the relevant methods for an {@code EditText}-like view:
+ *
+ * <pre><code>
+ * public class MyEditText extends View {
+ *
+ * public MyEditText(...) {
+ *   if (getImportantForContentCapture() == IMPORTANT_FOR_CONTENT_CAPTURE_AUTO) {
+ *     setImportantForContentCapture(IMPORTANT_FOR_CONTENT_CAPTURE_YES);
+ *   }
+ * }
+ *
+ * public void onProvideContentCaptureStructure(@NonNull ViewStructure structure, int flags) {
+ *   super.onProvideContentCaptureStructure(structure, flags);
+ *
+ *   structure.setText(getText(), getSelectionStart(), getSelectionEnd());
+ *   structure.setHint(getHint());
+ *   structure.setInputType(getInputType());
+ *   // set other properties like setTextIdEntry(), setTextLines(), setTextStyle(),
+ *   // setMinTextEms(), setMaxTextEms(), setMaxTextLength()
+ * }
+ *
+ * private void onTextChanged() {
+ *   if (isLaidOut() && isImportantForContentCapture() && isTextEditable()) {
+ *     ContentCaptureManager mgr = mContext.getSystemService(ContentCaptureManager.class);
+ *     if (cm != null && cm.isContentCaptureEnabled()) {
+ *        ContentCaptureSession session = getContentCaptureSession();
+ *        if (session != null) {
+ *          session.notifyViewTextChanged(getAutofillId(), getText());
+ *        }
+ *   }
+ * }
+ * </code></pre>
+ *
+ * <p>If your view provides its own virtual hierarchy (for example, if it's a browser that draws
+ * the HTML using {@link Canvas} or native libraries in a different render process), then the view
+ * is also responsible to notify the session when the virtual elements appear and disappear - see
+ * {@link View#onProvideContentCaptureStructure(ViewStructure, int)} for more info.
  */
 @SystemService(Context.CONTENT_CAPTURE_MANAGER_SERVICE)
 public final class ContentCaptureManager {
@@ -69,7 +215,7 @@
 
     /**
      * DeviceConfig property used by {@code com.android.server.SystemServer} on start to decide
-     * whether the Content Capture service should be created or not
+     * whether the content capture service should be created or not
      *
      * <p>By default it should *NOT* be set (or set to {@code "default"}, so the decision is based
      * on whether the OEM provides an implementation for the service), but it can be overridden to:
@@ -340,12 +486,12 @@
      * <p>There are many reasons it could be disabled, such as:
      * <ul>
      *   <li>App itself disabled content capture through {@link #setContentCaptureEnabled(boolean)}.
-     *   <li>Service disabled content capture for this specific activity.
-     *   <li>Service disabled content capture for all activities of this package.
-     *   <li>Service disabled content capture globally.
-     *   <li>User disabled content capture globally (through Settings).
-     *   <li>OEM disabled content capture globally.
-     *   <li>Transient errors.
+     *   <li>Intelligence service did not whitelist content capture for this activity's package.
+     *   <li>Intelligence service did not whitelist content capture for this specific activity.
+     *   <li>Intelligence service disabled content capture globally.
+     *   <li>User disabled content capture globally through the Android Settings app.
+     *   <li>Device manufacturer (OEM) disabled content capture globally.
+     *   <li>Transient errors, such as intelligence service package being updated.
      * </ul>
      */
     public boolean isContentCaptureEnabled() {
@@ -369,11 +515,22 @@
      * capture events for websites the content capture service is not interested on.
      *
      * @return list of conditions, or {@code null} if the service didn't set any restriction
-     * (in which case content capture events should always be generated).
+     * (in which case content capture events should always be generated). If the list is empty,
+     * then it should not generate any event at all.
      */
     @Nullable
     public Set<ContentCaptureCondition> getContentCaptureConditions() {
-        return null; // TODO(b/129267994): implement
+        // NOTE: we could cache the conditions on ContentCaptureOptions, but then it would be stick
+        // to the lifetime of the app. OTOH, by dynamically calling the server every time, we allow
+        // the service to fine tune how long-lived apps (like browsers) are whitelisted.
+        if (!isContentCaptureEnabled() && !mOptions.lite) return null;
+
+        final SyncResultReceiver resultReceiver = syncRun(
+                (r) -> mService.getContentCaptureConditions(mContext.getPackageName(), r));
+
+        final ArrayList<ContentCaptureCondition> result = resultReceiver
+                .getParcelableListResult();
+        return toSet(result);
     }
 
     /**
@@ -393,12 +550,12 @@
     }
 
     /**
-     * Gets whether Content Capture is enabled for the given user.
+     * Gets whether content capture is enabled for the given user.
      *
-     * <p>This method is typically used by the Content Capture Service settings page, so it can
+     * <p>This method is typically used by the content capture service settings page, so it can
      * provide a toggle to enable / disable it.
      *
-     * @throws SecurityException if caller is not the app that owns the Content Capture service
+     * @throws SecurityException if caller is not the app that owns the content capture service
      * associated with the user.
      *
      * @hide
@@ -406,21 +563,14 @@
     @SystemApi
     @TestApi
     public boolean isContentCaptureFeatureEnabled() {
-        final SyncResultReceiver resultReceiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
-        final int resultCode;
-        try {
-            mService.isContentCaptureFeatureEnabled(resultReceiver);
-            resultCode = resultReceiver.getIntResult();
-        } catch (RemoteException e) {
-            throw e.rethrowFromSystemServer();
-        }
+        final SyncResultReceiver resultReceiver = syncRun(
+                (r) -> mService.isContentCaptureFeatureEnabled(r));
+        final int resultCode = resultReceiver.getIntResult();
         switch (resultCode) {
             case RESULT_CODE_TRUE:
                 return true;
             case RESULT_CODE_FALSE:
                 return false;
-            case RESULT_CODE_SECURITY_EXCEPTION:
-                throw new SecurityException("caller is not user's ContentCapture service");
             default:
                 Log.wtf(TAG, "received invalid result: " + resultCode);
                 return false;
@@ -428,7 +578,7 @@
     }
 
     /**
-     * Called by the app to request the Content Capture service to remove user-data associated with
+     * Called by the app to request the content capture service to remove user-data associated with
      * some context.
      *
      * @param request object specifying what user data should be removed.
@@ -443,6 +593,26 @@
         }
     }
 
+    /**
+     * Runs a sync method in the service, properly handling exceptions.
+     *
+     * @throws SecurityException if caller is not allowed to execute the method.
+     */
+    @NonNull
+    private SyncResultReceiver syncRun(@NonNull MyRunnable r) {
+        final SyncResultReceiver resultReceiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS);
+        try {
+            r.run(resultReceiver);
+            final int resultCode = resultReceiver.getIntResult();
+            if (resultCode == RESULT_CODE_SECURITY_EXCEPTION) {
+                throw new SecurityException(resultReceiver.getStringResult());
+            }
+            return resultReceiver;
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
     /** @hide */
     public void dump(String prefix, PrintWriter pw) {
         pw.print(prefix); pw.println("ContentCaptureManager");
@@ -466,4 +636,8 @@
             }
         }
     }
+
+    private interface MyRunnable {
+        void run(@NonNull SyncResultReceiver receiver) throws RemoteException;
+    }
 }
diff --git a/core/java/android/view/contentcapture/ContentCaptureSession.java b/core/java/android/view/contentcapture/ContentCaptureSession.java
index ed1ca2a..7761038 100644
--- a/core/java/android/view/contentcapture/ContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/ContentCaptureSession.java
@@ -38,7 +38,7 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
-import java.util.UUID;
+import java.util.Random;
 
 /**
  * Session used to notify a system-provided Content Capture service about events associated with
@@ -48,6 +48,11 @@
 
     private static final String TAG = ContentCaptureSession.class.getSimpleName();
 
+    private static final Random sIdGenerator = new Random();
+
+    /** @hide */
+    public static final int NO_SESSION_ID = 0;
+
     /**
      * Initial state, when there is no session.
      *
@@ -186,7 +191,7 @@
 
     /** @hide */
     @Nullable
-    protected final String mId;
+    protected final int mId;
 
     private int mState = UNKNOWN_STATE;
 
@@ -210,13 +215,14 @@
 
     /** @hide */
     protected ContentCaptureSession() {
-        this(UUID.randomUUID().toString());
+        this(getRandomSessionId());
     }
 
     /** @hide */
     @VisibleForTesting
-    public ContentCaptureSession(@NonNull String id) {
-        mId = Preconditions.checkNotNull(id);
+    public ContentCaptureSession(int id) {
+        Preconditions.checkArgument(id != NO_SESSION_ID);
+        mId = id;
     }
 
     // Used by ChildCOntentCaptureSession
@@ -241,15 +247,8 @@
     }
 
     /** @hide */
-    @VisibleForTesting
-    public int getIdAsInt() {
-        // TODO(b/121197119): use sessionId instead of hashcode once it's changed to int
-        return mId.hashCode();
-    }
-
-    /** @hide */
     @NonNull
-    public String getId() {
+    public int getId() {
         return mId;
     }
 
@@ -415,7 +414,7 @@
         // TODO(b/123036895): use a internalNotifyViewsDisappeared that optimizes how the event is
         // parcelized
         for (long id : virtualIds) {
-            internalNotifyViewDisappeared(new AutofillId(hostId, id, getIdAsInt()));
+            internalNotifyViewDisappeared(new AutofillId(hostId, id, mId));
         }
     }
 
@@ -464,7 +463,7 @@
     public @NonNull AutofillId newAutofillId(@NonNull AutofillId hostId, long virtualChildId) {
         Preconditions.checkNotNull(hostId);
         Preconditions.checkArgument(hostId.isNonVirtual(), "hostId cannot be virtual: %s", hostId);
-        return new AutofillId(hostId, virtualChildId, getIdAsInt());
+        return new AutofillId(hostId, virtualChildId, mId);
     }
 
     /**
@@ -480,7 +479,7 @@
     @NonNull
     public final ViewStructure newVirtualViewStructure(@NonNull AutofillId parentId,
             long virtualId) {
-        return new ViewNode.ViewStructureImpl(parentId, virtualId, getIdAsInt());
+        return new ViewNode.ViewStructureImpl(parentId, virtualId, mId);
     }
 
     boolean isContentCaptureEnabled() {
@@ -511,7 +510,7 @@
 
     @Override
     public String toString() {
-        return mId;
+        return Integer.toString(mId);
     }
 
     /** @hide */
@@ -541,4 +540,12 @@
                 return "UNKOWN-" + reason;
         }
     }
+
+    private static int getRandomSessionId() {
+        int id;
+        do {
+            id = sIdGenerator.nextInt();
+        } while (id == NO_SESSION_ID);
+        return id;
+    }
 }
diff --git a/core/java/android/view/contentcapture/ContentCaptureSessionId.java b/core/java/android/view/contentcapture/ContentCaptureSessionId.java
index e7c350a..2d350b2 100644
--- a/core/java/android/view/contentcapture/ContentCaptureSessionId.java
+++ b/core/java/android/view/contentcapture/ContentCaptureSessionId.java
@@ -27,7 +27,7 @@
  */
 public final class ContentCaptureSessionId implements Parcelable {
 
-    private final @NonNull String mValue;
+    private final @NonNull int mValue;
 
     /**
      * Creates a new instance.
@@ -36,14 +36,14 @@
      *
      * @hide
      */
-    public ContentCaptureSessionId(@NonNull String value) {
+    public ContentCaptureSessionId(@NonNull int value) {
         mValue = value;
     }
 
     /**
      * @hide
      */
-    public String getValue() {
+    public int getValue() {
         return mValue;
     }
 
@@ -51,7 +51,7 @@
     public int hashCode() {
         final int prime = 31;
         int result = 1;
-        result = prime * result + ((mValue == null) ? 0 : mValue.hashCode());
+        result = prime * result + mValue;
         return result;
     }
 
@@ -61,11 +61,7 @@
         if (obj == null) return false;
         if (getClass() != obj.getClass()) return false;
         final ContentCaptureSessionId other = (ContentCaptureSessionId) obj;
-        if (mValue == null) {
-            if (other.mValue != null) return false;
-        } else if (!mValue.equals(other.mValue)) {
-            return false;
-        }
+        if (mValue != other.mValue) return false;
         return true;
     }
 
@@ -77,9 +73,10 @@
      */
     @Override
     public String toString() {
-        return mValue;
+        return Integer.toString(mValue);
     }
 
+
     /** @hide */
     // TODO(b/111276913): dump to proto as well
     public void dump(PrintWriter pw) {
@@ -93,16 +90,16 @@
 
     @Override
     public void writeToParcel(Parcel parcel, int flags) {
-        parcel.writeString(mValue);
+        parcel.writeInt(mValue);
     }
 
-    public static final @android.annotation.NonNull Parcelable.Creator<ContentCaptureSessionId> CREATOR =
+    public static final @NonNull Parcelable.Creator<ContentCaptureSessionId> CREATOR =
             new Parcelable.Creator<ContentCaptureSessionId>() {
 
         @Override
         @NonNull
         public ContentCaptureSessionId createFromParcel(Parcel parcel) {
-            return new ContentCaptureSessionId(parcel.readString());
+            return new ContentCaptureSessionId(parcel.readInt());
         }
 
         @Override
diff --git a/core/java/android/view/contentcapture/IContentCaptureManager.aidl b/core/java/android/view/contentcapture/IContentCaptureManager.aidl
index 15fbaa2..7335073 100644
--- a/core/java/android/view/contentcapture/IContentCaptureManager.aidl
+++ b/core/java/android/view/contentcapture/IContentCaptureManager.aidl
@@ -42,13 +42,13 @@
      *     {@link IContentCaptureContext#flags}).
      */
     void startSession(IBinder activityToken, in ComponentName componentName,
-                      String sessionId, int flags, in IResultReceiver result);
+                      int sessionId, int flags, in IResultReceiver result);
 
     /**
      * Marks the end of a session for the calling user identified by
      * the corresponding {@code startSession}'s {@code sessionId}.
      */
-    void finishSession(String sessionId);
+    void finishSession(int sessionId);
 
     /**
      * Returns the content capture service's component name (if enabled and
@@ -72,4 +72,9 @@
      * Returns a ComponentName with the name of custom service activity, if defined.
      */
     void getServiceSettingsActivity(in IResultReceiver result);
+
+    /**
+     * Returns a list with the ContentCaptureConditions for the package (or null if not defined).
+     */
+    void getContentCaptureConditions(String packageName, in IResultReceiver result);
 }
diff --git a/core/java/android/view/contentcapture/MainContentCaptureSession.java b/core/java/android/view/contentcapture/MainContentCaptureSession.java
index 790b8f9..784cf9c 100644
--- a/core/java/android/view/contentcapture/MainContentCaptureSession.java
+++ b/core/java/android/view/contentcapture/MainContentCaptureSession.java
@@ -318,7 +318,7 @@
         if (!mEvents.isEmpty() && eventType == TYPE_VIEW_DISAPPEARED) {
             final ContentCaptureEvent lastEvent = mEvents.get(mEvents.size() - 1);
             if (lastEvent.getType() == TYPE_VIEW_DISAPPEARED
-                    && event.getSessionId().equals(lastEvent.getSessionId())) {
+                    && event.getSessionId() == lastEvent.getSessionId()) {
                 if (sVerbose) {
                     Log.v(TAG, "Buffering TYPE_VIEW_DISAPPEARED events for session "
                             + lastEvent.getSessionId());
@@ -581,37 +581,35 @@
     // TODO(b/122454205): refactor "notifyXXXX" methods below to a common "Buffer" object that is
     // shared between ActivityContentCaptureSession and ChildContentCaptureSession objects. Such
     // change should also get get rid of the "internalNotifyXXXX" methods above
-    void notifyChildSessionStarted(@NonNull String parentSessionId,
-            @NonNull String childSessionId, @NonNull ContentCaptureContext clientContext) {
+    void notifyChildSessionStarted(int parentSessionId, int childSessionId,
+            @NonNull ContentCaptureContext clientContext) {
         sendEvent(new ContentCaptureEvent(childSessionId, TYPE_SESSION_STARTED)
                 .setParentSessionId(parentSessionId).setClientContext(clientContext),
                 FORCE_FLUSH);
     }
 
-    void notifyChildSessionFinished(@NonNull String parentSessionId,
-            @NonNull String childSessionId) {
+    void notifyChildSessionFinished(int parentSessionId, int childSessionId) {
         sendEvent(new ContentCaptureEvent(childSessionId, TYPE_SESSION_FINISHED)
                 .setParentSessionId(parentSessionId), FORCE_FLUSH);
     }
 
-    void notifyViewAppeared(@NonNull String sessionId, @NonNull ViewStructureImpl node) {
+    void notifyViewAppeared(int sessionId, @NonNull ViewStructureImpl node) {
         sendEvent(new ContentCaptureEvent(sessionId, TYPE_VIEW_APPEARED)
                 .setViewNode(node.mNode));
     }
 
     /** Public because is also used by ViewRootImpl */
-    public void notifyViewDisappeared(@NonNull String sessionId, @NonNull AutofillId id) {
+    public void notifyViewDisappeared(int sessionId, @NonNull AutofillId id) {
         sendEvent(new ContentCaptureEvent(sessionId, TYPE_VIEW_DISAPPEARED).setAutofillId(id));
     }
 
-    void notifyViewTextChanged(@NonNull String sessionId, @NonNull AutofillId id,
-            @Nullable CharSequence text) {
+    void notifyViewTextChanged(int sessionId, @NonNull AutofillId id, @Nullable CharSequence text) {
         sendEvent(new ContentCaptureEvent(sessionId, TYPE_VIEW_TEXT_CHANGED).setAutofillId(id)
                 .setText(text));
     }
 
     /** Public because is also used by ViewRootImpl */
-    public void notifyViewTreeEvent(@NonNull String sessionId, boolean started) {
+    public void notifyViewTreeEvent(int sessionId, boolean started) {
         final int type = started ? TYPE_VIEW_TREE_APPEARING : TYPE_VIEW_TREE_APPEARED;
         sendEvent(new ContentCaptureEvent(sessionId, type), FORCE_FLUSH);
     }
@@ -622,8 +620,7 @@
         sendEvent(new ContentCaptureEvent(mId, type), FORCE_FLUSH);
     }
 
-    void notifyContextUpdated(@NonNull String sessionId,
-            @Nullable ContentCaptureContext context) {
+    void notifyContextUpdated(int sessionId, @Nullable ContentCaptureContext context) {
         sendEvent(new ContentCaptureEvent(sessionId, TYPE_CONTEXT_UPDATED)
                 .setClientContext(context));
     }
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index a5a1a80c..a961783 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -10081,7 +10081,7 @@
     }
 
     /**
-     * Return true iff there is a selection inside this text view.
+     * Return true iff there is a selection of nonzero length inside this text view.
      */
     public boolean hasSelection() {
         final int selectionStart = getSelectionStart();
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 4f5678a..f29174b 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -163,6 +163,8 @@
      */
     private static final int NO_DIRECT_SHARE_ANIM_IN_MILLIS = 200;
 
+    private static final float DIRECT_SHARE_EXPANSION_RATE = 0.7f;
+
     // TODO(b/121287224): Re-evaluate this limit
     private static final int SHARE_TARGET_QUERY_PACKAGE_LIMIT = 20;
 
@@ -435,9 +437,13 @@
         mChooserRowServiceSpacing = getResources()
                                         .getDimensionPixelSize(R.dimen.chooser_service_spacing);
 
-        // expand/shrink direct share 4 -> 8 viewgroup
-        if (mResolverDrawerLayout != null && isSendAction(target)) {
-            mResolverDrawerLayout.setOnScrollChangeListener(this::handleScroll);
+        if (mResolverDrawerLayout != null) {
+            mResolverDrawerLayout.addOnLayoutChangeListener(this::handleLayoutChange);
+
+            // expand/shrink direct share 4 -> 8 viewgroup
+            if (isSendAction(target)) {
+                mResolverDrawerLayout.setOnScrollChangeListener(this::handleScroll);
+            }
         }
 
         if (DEBUG) {
@@ -878,18 +884,9 @@
             mChooserListAdapter.addServiceResults(null, Lists.newArrayList(mCallerChooserTargets));
         }
         mChooserRowAdapter = new ChooserRowAdapter(mChooserListAdapter);
-        mChooserRowAdapter.registerDataSetObserver(new OffsetDataSetObserver(adapterView));
         if (listView != null) {
             listView.setItemsCanFocus(true);
-            listView.addOnLayoutChangeListener(
-                    (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
-                        if (mChooserRowAdapter.calculateMaxTargetsPerRow(right - left)) {
-                            adapterView.setAdapter(mChooserRowAdapter);
-                        }
-                    });
         }
-
-        adapterView.setAdapter(mChooserRowAdapter);
     }
 
     @Override
@@ -1728,6 +1725,66 @@
         }
     }
 
+    /*
+     * Need to dynamically adjust how many icons can fit per row before we add them,
+     * which also means setting the correct offset to initially show the content
+     * preview area + 2 rows of targets
+     */
+    private void handleLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
+            int oldTop, int oldRight, int oldBottom) {
+        if (mChooserRowAdapter == null || mAdapterView == null) {
+            return;
+        }
+
+        if (mChooserRowAdapter.calculateMaxTargetsPerRow(right - left)
+                || mAdapterView.getAdapter() == null) {
+            mAdapterView.setAdapter(mChooserRowAdapter);
+
+            getMainThreadHandler().post(() -> {
+                if (mResolverDrawerLayout == null || mChooserRowAdapter == null) {
+                    return;
+                }
+
+                int offset = 0;
+                int rowsToShow = mChooserRowAdapter.getContentPreviewRowCount()
+                        + mChooserRowAdapter.getServiceTargetRowCount()
+                        + mChooserRowAdapter.getCallerTargetRowCount();
+
+                // then this is most likely not a SEND_* action, so check
+                // the app target count
+                if (rowsToShow == 0) {
+                    rowsToShow = mChooserRowAdapter.getCount();
+                }
+
+                // still zero? then use a default height and leave, which
+                // can happen when there are no targets to show
+                if (rowsToShow == 0) {
+                    offset = getResources().getDimensionPixelSize(
+                            R.dimen.chooser_max_collapsed_height);
+                    mResolverDrawerLayout.setCollapsibleHeightReserved(offset);
+                    return;
+                }
+
+                int lastHeight = 0;
+                rowsToShow = Math.max(3, rowsToShow);
+                for (int i = 0; i < Math.min(rowsToShow, mAdapterView.getChildCount()); i++) {
+                    lastHeight = mAdapterView.getChildAt(i).getHeight();
+                    offset += lastHeight;
+                }
+
+                if (lastHeight != 0 && isSendAction(getTargetIntent())) {
+                    // make sure to leave room for direct share 4->8 expansion
+                    int expansionArea =
+                            (int) (mResolverDrawerLayout.getUncollapsibleHeight()
+                                    / DIRECT_SHARE_EXPANSION_RATE);
+                    offset = Math.min(offset, bottom - top - lastHeight - expansionArea);
+                }
+
+                mResolverDrawerLayout.setCollapsibleHeightReserved(offset);
+            });
+        }
+    }
+
     public class ChooserListAdapter extends ResolveListAdapter {
         public static final int TARGET_BAD = -1;
         public static final int TARGET_CALLER = 0;
@@ -2541,7 +2598,6 @@
             getRow(0).measure(spec, spec);
             getRow(1).measure(spec, spec);
 
-            // uses ChooserActiivty state variables to track height
             mDirectShareMinHeight = getRow(0).getMeasuredHeight();
             mDirectShareCurrHeight = mDirectShareCurrHeight > 0
                                          ? mDirectShareCurrHeight : mDirectShareMinHeight;
@@ -2574,18 +2630,18 @@
         }
 
         public void handleScroll(AbsListView view, int y, int oldy, int maxTargetsPerRow) {
-            // only expand if we have more than 4 targets, and delay that decision until
-            // they start to scroll
             if (mHideDirectShareExpansion) {
                 return;
             }
 
+            // only expand if we have more than maxTargetsPerRow, and delay that decision
+            // until they start to scroll
             if (mChooserListAdapter.getSelectableServiceTargetCount() <= maxTargetsPerRow) {
                 mHideDirectShareExpansion = true;
                 return;
             }
 
-            int yDiff = (int) ((oldy - y) * 0.7f);
+            int yDiff = (int) ((oldy - y) * DIRECT_SHARE_EXPANSION_RATE);
 
             int prevHeight = mDirectShareCurrHeight;
             mDirectShareCurrHeight = Math.min(mDirectShareCurrHeight + yDiff,
@@ -2593,27 +2649,31 @@
             mDirectShareCurrHeight = Math.max(mDirectShareCurrHeight, mDirectShareMinHeight);
             yDiff = mDirectShareCurrHeight - prevHeight;
 
-            if (view == null || view.getChildCount() == 0) {
+            if (view == null || view.getChildCount() == 0 || yDiff == 0) {
                 return;
             }
 
-            int index = mChooserRowAdapter.getContentPreviewRowCount();
+            // locate the item to expand, and offset the rows below that one
+            boolean foundExpansion = false;
+            for (int i = 0; i < view.getChildCount(); i++) {
+                View child = view.getChildAt(i);
 
-            ViewGroup expansionGroup = (ViewGroup) view.getChildAt(index);
-            int widthSpec = MeasureSpec.makeMeasureSpec(expansionGroup.getWidth(),
-                    MeasureSpec.EXACTLY);
-            int heightSpec = MeasureSpec.makeMeasureSpec(mDirectShareCurrHeight,
-                    MeasureSpec.EXACTLY);
-            expansionGroup.measure(widthSpec, heightSpec);
-            expansionGroup.getLayoutParams().height = expansionGroup.getMeasuredHeight();
-            expansionGroup.layout(expansionGroup.getLeft(), expansionGroup.getTop(),
-                    expansionGroup.getRight(),
-                    expansionGroup.getTop() + expansionGroup.getMeasuredHeight());
+                if (foundExpansion) {
+                    child.offsetTopAndBottom(yDiff);
+                } else {
+                    if (child.getTag() != null && child.getTag() instanceof DirectShareViewHolder) {
+                        int widthSpec = MeasureSpec.makeMeasureSpec(child.getWidth(),
+                                MeasureSpec.EXACTLY);
+                        int heightSpec = MeasureSpec.makeMeasureSpec(mDirectShareCurrHeight,
+                                MeasureSpec.EXACTLY);
+                        child.measure(widthSpec, heightSpec);
+                        child.getLayoutParams().height = child.getMeasuredHeight();
+                        child.layout(child.getLeft(), child.getTop(), child.getRight(),
+                                child.getTop() + child.getMeasuredHeight());
 
-            // reposition list items
-            int items = view.getChildCount();
-            for (int i = index + 1; i < items; i++) {
-                view.getChildAt(i).offsetTopAndBottom(yDiff);
+                        foundExpansion = true;
+                    }
+                }
             }
         }
     }
@@ -2771,47 +2831,6 @@
         }
     }
 
-    class OffsetDataSetObserver extends DataSetObserver {
-        private final AbsListView mListView;
-        private int mCachedViewType = -1;
-        private View mCachedView;
-
-        public OffsetDataSetObserver(AbsListView listView) {
-            mListView = listView;
-        }
-
-        @Override
-        public void onChanged() {
-            if (mResolverDrawerLayout == null) {
-                return;
-            }
-
-            final int chooserTargetRows = mChooserRowAdapter.getServiceTargetRowCount();
-            int offset = 0;
-            for (int i = 0; i < chooserTargetRows; i++) {
-                final int pos = mChooserRowAdapter.getContentPreviewRowCount() + i;
-                final int vt = mChooserRowAdapter.getItemViewType(pos);
-                if (vt != mCachedViewType) {
-                    mCachedView = null;
-                }
-                final View v = mChooserRowAdapter.getView(pos, mCachedView, mListView);
-                int height = ((RowViewHolder) (v.getTag())).getMeasuredRowHeight();
-
-                offset += (int) (height);
-
-                if (vt >= 0) {
-                    mCachedViewType = vt;
-                    mCachedView = v;
-                } else {
-                    mCachedViewType = -1;
-                }
-            }
-
-            mResolverDrawerLayout.setCollapsibleHeightReserved(offset);
-        }
-    }
-
-
     /**
      * Used internally to round image corners while obeying view padding.
      */
diff --git a/core/java/com/android/internal/app/DumpHeapActivity.java b/core/java/com/android/internal/app/DumpHeapActivity.java
index 0ce501e..e04e870 100644
--- a/core/java/com/android/internal/app/DumpHeapActivity.java
+++ b/core/java/com/android/internal/app/DumpHeapActivity.java
@@ -37,6 +37,10 @@
     public static final String KEY_PROCESS = "process";
     /** The size limit the process reached */
     public static final String KEY_SIZE = "size";
+    /** Whether the user initiated the dump or not. */
+    public static final String KEY_IS_USER_INITIATED = "is_user_initiated";
+    /** Whether the process is a system process (eg: Android System) or not. */
+    public static final String KEY_IS_SYSTEM_PROCESS = "is_system_process";
     /** Optional name of package to directly launch */
     public static final String KEY_DIRECT_LAUNCH = "direct_launch";
 
@@ -59,6 +63,8 @@
 
         mProcess = getIntent().getStringExtra(KEY_PROCESS);
         mSize = getIntent().getLongExtra(KEY_SIZE, 0);
+        final boolean isUserInitiated = getIntent().getBooleanExtra(KEY_IS_USER_INITIATED, false);
+        final boolean isSystemProcess = getIntent().getBooleanExtra(KEY_IS_SYSTEM_PROCESS, false);
 
         String directLaunch = getIntent().getStringExtra(KEY_DIRECT_LAUNCH);
         if (directLaunch != null) {
@@ -81,11 +87,19 @@
             }
         }
 
+        final int messageId;
+        if (isUserInitiated) {
+            messageId = com.android.internal.R.string.dump_heap_ready_text;
+        } else if (isSystemProcess) {
+            messageId = com.android.internal.R.string.dump_heap_system_text;
+        } else {
+            messageId = com.android.internal.R.string.dump_heap_text;
+        }
         AlertDialog.Builder b = new AlertDialog.Builder(this,
                 android.R.style.Theme_Material_Light_Dialog_Alert);
         b.setTitle(com.android.internal.R.string.dump_heap_title);
-        b.setMessage(getString(com.android.internal.R.string.dump_heap_text,
-                mProcess, DebugUtils.sizeValueToString(mSize, null)));
+        b.setMessage(getString(
+                messageId, mProcess, DebugUtils.sizeValueToString(mSize, null)));
         b.setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() {
             @Override
             public void onClick(DialogInterface dialog, int which) {
diff --git a/core/java/com/android/internal/infra/GlobalWhitelistState.java b/core/java/com/android/internal/infra/GlobalWhitelistState.java
new file mode 100644
index 0000000..dfa59b7
--- /dev/null
+++ b/core/java/com/android/internal/infra/GlobalWhitelistState.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.infra;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.content.ComponentName;
+import android.util.ArraySet;
+import android.util.SparseArray;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.io.PrintWriter;
+import java.util.List;
+
+/**
+ * Helper class used to manage a {@link WhitelistHelper} per user instance when the main service
+ * cannot hold a lock when external entities (typically {@code ActivityManagerService}) needs to
+ * get whitelist info.
+ *
+ * <p>This class is thread safe.
+ */
+public class GlobalWhitelistState {
+
+    // Uses full-name to avoid collision with service-provided mLock
+    protected final Object mGlobalWhitelistStateLock = new Object();
+
+    @Nullable
+    @GuardedBy("mGlobalWhitelistStateLock")
+    protected SparseArray<WhitelistHelper> mWhitelisterHelpers;
+
+    /**
+     * Sets the whitelist for the given user.
+     */
+    public void setWhitelist(@UserIdInt int userId, @Nullable List<String> packageNames,
+            @Nullable List<ComponentName> components) {
+        synchronized (mGlobalWhitelistStateLock) {
+            if (mWhitelisterHelpers == null) {
+                mWhitelisterHelpers = new SparseArray<>(1);
+            }
+            WhitelistHelper helper = mWhitelisterHelpers.get(userId);
+            if (helper == null) {
+                helper = new WhitelistHelper();
+                mWhitelisterHelpers.put(userId, helper);
+            }
+            helper.setWhitelist(packageNames, components);
+        }
+    }
+
+    /**
+     * Checks if the given package is whitelisted for the given user.
+     */
+    public boolean isWhitelisted(@UserIdInt int userId, @NonNull String packageName) {
+        synchronized (mGlobalWhitelistStateLock) {
+            if (mWhitelisterHelpers == null) return false;
+            final WhitelistHelper helper = mWhitelisterHelpers.get(userId);
+            return helper == null ? false : helper.isWhitelisted(packageName);
+        }
+    }
+
+    /**
+     * Checks if the given component is whitelisted for the given user.
+     */
+    public boolean isWhitelisted(@UserIdInt int userId, @NonNull ComponentName componentName) {
+        synchronized (mGlobalWhitelistStateLock) {
+            if (mWhitelisterHelpers == null) return false;
+            final WhitelistHelper helper = mWhitelisterHelpers.get(userId);
+            return helper == null ? false : helper.isWhitelisted(componentName);
+        }
+    }
+
+    /**
+     * Gets the whitelisted components for the given package and user.
+     */
+    public ArraySet<ComponentName> getWhitelistedComponents(@UserIdInt int userId,
+            @NonNull String packageName) {
+        synchronized (mGlobalWhitelistStateLock) {
+            if (mWhitelisterHelpers == null) return null;
+            final WhitelistHelper helper = mWhitelisterHelpers.get(userId);
+            return helper == null ? null : helper.getWhitelistedComponents(packageName);
+        }
+    }
+
+    /**
+     * Resets the whitelist for the given user.
+     */
+    public void resetWhitelist(@NonNull int userId) {
+        synchronized (mGlobalWhitelistStateLock) {
+            if (mWhitelisterHelpers == null) return;
+            mWhitelisterHelpers.remove(userId);
+            if (mWhitelisterHelpers.size() == 0) {
+                mWhitelisterHelpers = null;
+            }
+        }
+    }
+
+    /**
+     * Dumps it!
+     */
+    public void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
+        pw.print(prefix); pw.print("State: ");
+        synchronized (mGlobalWhitelistStateLock) {
+            if (mWhitelisterHelpers == null) {
+                pw.println("empty");
+                return;
+            }
+            pw.print(mWhitelisterHelpers.size()); pw.println(" services");
+            final String prefix2 = prefix + "  ";
+            for (int i = 0; i < mWhitelisterHelpers.size(); i++) {
+                final int userId  = mWhitelisterHelpers.keyAt(i);
+                final WhitelistHelper helper = mWhitelisterHelpers.valueAt(i);
+                helper.dump(prefix2, "Whitelist for userId " + userId, pw);
+            }
+        }
+    }
+}
diff --git a/core/java/com/android/internal/infra/WhitelistHelper.java b/core/java/com/android/internal/infra/WhitelistHelper.java
index 183b465..d7753db 100644
--- a/core/java/com/android/internal/infra/WhitelistHelper.java
+++ b/core/java/com/android/internal/infra/WhitelistHelper.java
@@ -31,6 +31,7 @@
 /**
  * Helper class for keeping track of whitelisted packages/activities.
  *
+ * <p><b>NOTE: </b>this class is not thread safe.
  * @hide
  */
 public final class WhitelistHelper {
diff --git a/core/java/com/android/internal/os/RoSystemProperties.java b/core/java/com/android/internal/os/RoSystemProperties.java
index 524a5cc..b0855f4 100644
--- a/core/java/com/android/internal/os/RoSystemProperties.java
+++ b/core/java/com/android/internal/os/RoSystemProperties.java
@@ -59,6 +59,8 @@
     // ------ ro.fw.* ------------ //
     public static final boolean FW_SYSTEM_USER_SPLIT =
             SystemProperties.getBoolean("ro.fw.system_user_split", false);
+    public static final boolean MULTIUSER_HEADLESS_SYSTEM_USER =
+            SystemProperties.getBoolean("ro.fw.multiuser.headless_system_user", false);
 
     // ------ ro.crypto.* -------- //
     public static final CryptoProperties.state_values CRYPTO_STATE =
diff --git a/core/java/com/android/internal/util/SyncResultReceiver.java b/core/java/com/android/internal/util/SyncResultReceiver.java
index 60af511..00e9101 100644
--- a/core/java/com/android/internal/util/SyncResultReceiver.java
+++ b/core/java/com/android/internal/util/SyncResultReceiver.java
@@ -19,10 +19,10 @@
 import android.annotation.Nullable;
 import android.os.Bundle;
 import android.os.Parcelable;
-import android.os.RemoteException;
 
 import com.android.internal.os.IResultReceiver;
 
+import java.util.ArrayList;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
@@ -97,6 +97,15 @@
     }
 
     /**
+     * Gets the result from an operation that returns a {@code Parcelable} list.
+     */
+    @Nullable
+    public <P extends Parcelable> ArrayList<P> getParcelableListResult() throws TimeoutException {
+        waitResult();
+        return mBundle == null ? null : mBundle.getParcelableArrayList(EXTRA);
+    }
+
+    /**
      * Gets the optional result from an operation that returns an extra {@code int} (besides the
      * result code).
      *
@@ -150,6 +159,17 @@
     }
 
     /**
+     * Creates a bundle for a {@code Parcelable} list so it can be retrieved by
+     * {@link #getParcelableResult()}.
+     */
+    @NonNull
+    public static Bundle bundleFor(@Nullable ArrayList<? extends Parcelable> value) {
+        final Bundle bundle = new Bundle();
+        bundle.putParcelableArrayList(EXTRA, value);
+        return bundle;
+    }
+
+    /**
      * Creates a bundle for an {@code int} value so it can be retrieved by
      * {@link #getParcelableResult()} - typically used to return an extra {@code int} (as the 1st
      * is returned as the result code).
@@ -162,7 +182,7 @@
     }
 
     /** @hide */
-    public static final class TimeoutException extends RemoteException {
+    public static final class TimeoutException extends RuntimeException {
         private TimeoutException(String msg) {
             super(msg);
         }
diff --git a/core/java/com/android/internal/widget/ResolverDrawerLayout.java b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
index 9722fcb..a160b57 100644
--- a/core/java/com/android/internal/widget/ResolverDrawerLayout.java
+++ b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
@@ -868,6 +868,13 @@
         setMeasuredDimension(sourceWidth, heightSize);
     }
 
+    /**
+      * @return The space reserved by views with 'alwaysShow=true'
+      */
+    public int getUncollapsibleHeight() {
+        return mUncollapsibleHeight;
+    }
+
     @Override
     protected void onLayout(boolean changed, int l, int t, int r, int b) {
         final int width = getWidth();
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 664f7f4..000c044 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -303,6 +303,7 @@
         "libnativewindow",
         "libhwui",
         "libdl",
+        "libdl_android",
         "libstatslog",
         "server_configurable_flags",
     ],
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index e0b7629..a4e3709 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -39,7 +39,6 @@
 static jfieldID gBitmap_nativePtr;
 static jmethodID gBitmap_constructorMethodID;
 static jmethodID gBitmap_reinitMethodID;
-static jmethodID gBitmap_getAllocationByteCountMethodID;
 
 namespace android {
 
@@ -193,11 +192,6 @@
             info.width(), info.height(), isPremultiplied);
 }
 
-int getBitmapAllocationByteCount(JNIEnv* env, jobject javaBitmap)
-{
-    return env->CallIntMethod(javaBitmap, gBitmap_getAllocationByteCountMethodID);
-}
-
 jobject createBitmap(JNIEnv* env, Bitmap* bitmap,
         int bitmapCreateFlags, jbyteArray ninePatchChunk, jobject ninePatchInsets,
         int density) {
@@ -236,8 +230,7 @@
     return localBitmap->bitmap();
 }
 
-Bitmap& toBitmap(JNIEnv* env, jlong bitmapHandle) {
-    SkASSERT(env);
+Bitmap& toBitmap(jlong bitmapHandle) {
     LocalScopedBitmap localBitmap(bitmapHandle);
     return localBitmap->bitmap();
 }
@@ -1227,7 +1220,6 @@
     gBitmap_nativePtr = GetFieldIDOrDie(env, gBitmap_class, "mNativePtr", "J");
     gBitmap_constructorMethodID = GetMethodIDOrDie(env, gBitmap_class, "<init>", "(JIIIZ[BLandroid/graphics/NinePatch$InsetStruct;Z)V");
     gBitmap_reinitMethodID = GetMethodIDOrDie(env, gBitmap_class, "reinit", "(IIZ)V");
-    gBitmap_getAllocationByteCountMethodID = GetMethodIDOrDie(env, gBitmap_class, "getAllocationByteCount", "()I");
     return android::RegisterMethodsOrDie(env, "android/graphics/Bitmap", gBitmapMethods,
                                          NELEM(gBitmapMethods));
 }
diff --git a/core/jni/android/graphics/Bitmap.h b/core/jni/android/graphics/Bitmap.h
index 06877915..6934d26 100644
--- a/core/jni/android/graphics/Bitmap.h
+++ b/core/jni/android/graphics/Bitmap.h
@@ -41,7 +41,7 @@
 void toSkBitmap(jlong bitmapHandle, SkBitmap* outBitmap);
 
 Bitmap& toBitmap(JNIEnv* env, jobject bitmap);
-Bitmap& toBitmap(JNIEnv* env, jlong bitmapHandle);
+Bitmap& toBitmap(jlong bitmapHandle);
 
 // NDK access
 void imageInfo(JNIEnv* env, jobject bitmap, AndroidBitmapInfo* info);
@@ -56,8 +56,6 @@
 void reinitBitmap(JNIEnv* env, jobject javaBitmap, const SkImageInfo& info,
         bool isPremultiplied);
 
-int getBitmapAllocationByteCount(JNIEnv* env, jobject javaBitmap);
-
 } // namespace bitmap
 
 } // namespace android
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 47b1548..3f05c3b 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -180,7 +180,8 @@
 }
 
 static jobject doDecode(JNIEnv* env, std::unique_ptr<SkStreamRewindable> stream,
-                        jobject padding, jobject options, jlong colorSpaceHandle) {
+                        jobject padding, jobject options, jlong inBitmapHandle,
+                        jlong colorSpaceHandle) {
     // Set default values for the options parameters.
     int sampleSize = 1;
     bool onlyDecodeSize = false;
@@ -323,14 +324,14 @@
 
     android::Bitmap* reuseBitmap = nullptr;
     unsigned int existingBufferSize = 0;
-    if (javaBitmap != NULL) {
-        reuseBitmap = &bitmap::toBitmap(env, javaBitmap);
+    if (javaBitmap != nullptr) {
+        reuseBitmap = &bitmap::toBitmap(inBitmapHandle);
         if (reuseBitmap->isImmutable()) {
             ALOGW("Unable to reuse an immutable bitmap as an image decoder target.");
-            javaBitmap = NULL;
+            javaBitmap = nullptr;
             reuseBitmap = nullptr;
         } else {
-            existingBufferSize = bitmap::getBitmapAllocationByteCount(env, javaBitmap);
+            existingBufferSize = reuseBitmap->getAllocationByteCount();
         }
     }
 
@@ -513,7 +514,7 @@
 }
 
 static jobject nativeDecodeStream(JNIEnv* env, jobject clazz, jobject is, jbyteArray storage,
-        jobject padding, jobject options, jlong colorSpaceHandle) {
+        jobject padding, jobject options, jlong inBitmapHandle, jlong colorSpaceHandle) {
 
     jobject bitmap = NULL;
     std::unique_ptr<SkStream> stream(CreateJavaInputStreamAdaptor(env, is, storage));
@@ -522,13 +523,14 @@
         std::unique_ptr<SkStreamRewindable> bufferedStream(
                 SkFrontBufferedStream::Make(std::move(stream), SkCodec::MinBufferedBytesNeeded()));
         SkASSERT(bufferedStream.get() != NULL);
-        bitmap = doDecode(env, std::move(bufferedStream), padding, options, colorSpaceHandle);
+        bitmap = doDecode(env, std::move(bufferedStream), padding, options, inBitmapHandle,
+                          colorSpaceHandle);
     }
     return bitmap;
 }
 
 static jobject nativeDecodeFileDescriptor(JNIEnv* env, jobject clazz, jobject fileDescriptor,
-        jobject padding, jobject bitmapFactoryOptions, jlong colorSpaceHandle) {
+        jobject padding, jobject bitmapFactoryOptions, jlong inBitmapHandle, jlong colorSpaceHandle) {
 
     NPE_CHECK_RETURN_ZERO(env, fileDescriptor);
 
@@ -565,7 +567,7 @@
     if (::lseek(descriptor, 0, SEEK_CUR) == 0) {
         assert(isSeekable(dupDescriptor));
         return doDecode(env, std::move(fileStream), padding, bitmapFactoryOptions,
-                colorSpaceHandle);
+                        inBitmapHandle, colorSpaceHandle);
     }
 
     // Use a buffered stream. Although an SkFILEStream can be rewound, this
@@ -574,25 +576,26 @@
     std::unique_ptr<SkStreamRewindable> stream(SkFrontBufferedStream::Make(std::move(fileStream),
             SkCodec::MinBufferedBytesNeeded()));
 
-    return doDecode(env, std::move(stream), padding, bitmapFactoryOptions, colorSpaceHandle);
+    return doDecode(env, std::move(stream), padding, bitmapFactoryOptions, inBitmapHandle,
+                    colorSpaceHandle);
 }
 
 static jobject nativeDecodeAsset(JNIEnv* env, jobject clazz, jlong native_asset,
-        jobject padding, jobject options, jlong colorSpaceHandle) {
+        jobject padding, jobject options, jlong inBitmapHandle, jlong colorSpaceHandle) {
 
     Asset* asset = reinterpret_cast<Asset*>(native_asset);
     // since we know we'll be done with the asset when we return, we can
     // just use a simple wrapper
     return doDecode(env, skstd::make_unique<AssetStreamAdaptor>(asset), padding, options,
-            colorSpaceHandle);
+                    inBitmapHandle, colorSpaceHandle);
 }
 
 static jobject nativeDecodeByteArray(JNIEnv* env, jobject, jbyteArray byteArray,
-        jint offset, jint length, jobject options, jlong colorSpaceHandle) {
+        jint offset, jint length, jobject options, jlong inBitmapHandle, jlong colorSpaceHandle) {
 
     AutoJavaByteArray ar(env, byteArray);
     return doDecode(env, skstd::make_unique<SkMemoryStream>(ar.ptr() + offset, length, false),
-                    nullptr, options, colorSpaceHandle);
+                    nullptr, options, inBitmapHandle, colorSpaceHandle);
 }
 
 static jboolean nativeIsSeekable(JNIEnv* env, jobject, jobject fileDescriptor) {
@@ -604,22 +607,22 @@
 
 static const JNINativeMethod gMethods[] = {
     {   "nativeDecodeStream",
-        "(Ljava/io/InputStream;[BLandroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;J)Landroid/graphics/Bitmap;",
+        "(Ljava/io/InputStream;[BLandroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;JJ)Landroid/graphics/Bitmap;",
         (void*)nativeDecodeStream
     },
 
     {   "nativeDecodeFileDescriptor",
-        "(Ljava/io/FileDescriptor;Landroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;J)Landroid/graphics/Bitmap;",
+        "(Ljava/io/FileDescriptor;Landroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;JJ)Landroid/graphics/Bitmap;",
         (void*)nativeDecodeFileDescriptor
     },
 
     {   "nativeDecodeAsset",
-        "(JLandroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;J)Landroid/graphics/Bitmap;",
+        "(JLandroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;JJ)Landroid/graphics/Bitmap;",
         (void*)nativeDecodeAsset
     },
 
     {   "nativeDecodeByteArray",
-        "([BIILandroid/graphics/BitmapFactory$Options;J)Landroid/graphics/Bitmap;",
+        "([BIILandroid/graphics/BitmapFactory$Options;JJ)Landroid/graphics/Bitmap;",
         (void*)nativeDecodeByteArray
     },
 
diff --git a/core/jni/android/graphics/BitmapRegionDecoder.cpp b/core/jni/android/graphics/BitmapRegionDecoder.cpp
index 9c07e2d..6ffa72a 100644
--- a/core/jni/android/graphics/BitmapRegionDecoder.cpp
+++ b/core/jni/android/graphics/BitmapRegionDecoder.cpp
@@ -125,13 +125,14 @@
  * reportSizeToVM not supported
  */
 static jobject nativeDecodeRegion(JNIEnv* env, jobject, jlong brdHandle, jint inputX,
-        jint inputY, jint inputWidth, jint inputHeight, jobject options, jlong colorSpaceHandle) {
+        jint inputY, jint inputWidth, jint inputHeight, jobject options, jlong inBitmapHandle,
+        jlong colorSpaceHandle) {
 
     // Set default options.
     int sampleSize = 1;
     SkColorType colorType = kN32_SkColorType;
     bool requireUnpremul = false;
-    jobject javaBitmap = NULL;
+    jobject javaBitmap = nullptr;
     bool isHardware = false;
     sk_sp<SkColorSpace> colorSpace = GraphicsJNI::getNativeColorSpace(colorSpaceHandle);
     // Update the default options with any options supplied by the client.
@@ -158,11 +159,11 @@
     android::Bitmap* recycledBitmap = nullptr;
     size_t recycledBytes = 0;
     if (javaBitmap) {
-        recycledBitmap = &bitmap::toBitmap(env, javaBitmap);
+        recycledBitmap = &bitmap::toBitmap(inBitmapHandle);
         if (recycledBitmap->isImmutable()) {
             ALOGW("Warning: Reusing an immutable bitmap as an image decoder target.");
         }
-        recycledBytes = bitmap::getBitmapAllocationByteCount(env, javaBitmap);
+        recycledBytes = recycledBitmap->getAllocationByteCount();
     }
 
     SkBitmapRegionDecoder* brd = reinterpret_cast<SkBitmapRegionDecoder*>(brdHandle);
@@ -258,7 +259,7 @@
 
 static const JNINativeMethod gBitmapRegionDecoderMethods[] = {
     {   "nativeDecodeRegion",
-        "(JIIIILandroid/graphics/BitmapFactory$Options;J)Landroid/graphics/Bitmap;",
+        "(JIIIILandroid/graphics/BitmapFactory$Options;JJ)Landroid/graphics/Bitmap;",
         (void*)nativeDecodeRegion},
 
     {   "nativeGetHeight", "(J)I", (void*)nativeGetHeight},
diff --git a/core/jni/android/graphics/NinePatch.cpp b/core/jni/android/graphics/NinePatch.cpp
index bb291e7..15f9516 100644
--- a/core/jni/android/graphics/NinePatch.cpp
+++ b/core/jni/android/graphics/NinePatch.cpp
@@ -84,13 +84,13 @@
         delete[] patch;
     }
 
-    static jlong getTransparentRegion(JNIEnv* env, jobject, jobject jbitmap,
+    static jlong getTransparentRegion(JNIEnv* env, jobject, jlong bitmapPtr,
             jlong chunkHandle, jobject dstRect) {
         Res_png_9patch* chunk = reinterpret_cast<Res_png_9patch*>(chunkHandle);
         SkASSERT(chunk);
 
         SkBitmap bitmap;
-        GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
+        bitmap::toBitmap(bitmapPtr).getSkBitmap(&bitmap);
         SkRect dst;
         GraphicsJNI::jrect_to_rect(env, dstRect, &dst);
 
@@ -156,7 +156,7 @@
     { "validateNinePatchChunk", "([B)J",
             (void*) SkNinePatchGlue::validateNinePatchChunk },
     { "nativeFinalize", "(J)V", (void*) SkNinePatchGlue::finalize },
-    { "nativeGetTransparentRegion", "(Landroid/graphics/Bitmap;JLandroid/graphics/Rect;)J",
+    { "nativeGetTransparentRegion", "(JJLandroid/graphics/Rect;)J",
             (void*) SkNinePatchGlue::getTransparentRegion }
 };
 
diff --git a/core/jni/android/graphics/Shader.cpp b/core/jni/android/graphics/Shader.cpp
index 298f7f8..44d2cac 100644
--- a/core/jni/android/graphics/Shader.cpp
+++ b/core/jni/android/graphics/Shader.cpp
@@ -62,14 +62,14 @@
 
 ///////////////////////////////////////////////////////////////////////////////////////////////
 
-static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jlong matrixPtr, jobject jbitmap,
+static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jlong matrixPtr, jlong bitmapHandle,
         jint tileModeX, jint tileModeY) {
     const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
     sk_sp<SkImage> image;
-    if (jbitmap) {
+    if (bitmapHandle) {
         // Only pass a valid SkBitmap object to the constructor if the Bitmap exists. Otherwise,
         // we'll pass an empty SkBitmap to avoid crashing/excepting for compatibility.
-        image = android::bitmap::toBitmap(env, jbitmap).makeImage();
+        image = android::bitmap::toBitmap(bitmapHandle).makeImage();
     }
 
     if (!image.get()) {
@@ -222,7 +222,7 @@
 };
 
 static const JNINativeMethod gBitmapShaderMethods[] = {
-    { "nativeCreate",      "(JLandroid/graphics/Bitmap;II)J",  (void*)BitmapShader_constructor },
+    { "nativeCreate",      "(JJII)J",  (void*)BitmapShader_constructor },
 };
 
 static const JNINativeMethod gLinearGradientMethods[] = {
diff --git a/core/jni/android/graphics/pdf/PdfRenderer.cpp b/core/jni/android/graphics/pdf/PdfRenderer.cpp
index 32ac30f..761830b 100644
--- a/core/jni/android/graphics/pdf/PdfRenderer.cpp
+++ b/core/jni/android/graphics/pdf/PdfRenderer.cpp
@@ -73,12 +73,12 @@
 }
 
 static void nativeRenderPage(JNIEnv* env, jclass thiz, jlong documentPtr, jlong pagePtr,
-        jobject jbitmap, jint clipLeft, jint clipTop, jint clipRight, jint clipBottom,
+        jlong bitmapPtr, jint clipLeft, jint clipTop, jint clipRight, jint clipBottom,
         jlong transformPtr, jint renderMode) {
     FPDF_PAGE page = reinterpret_cast<FPDF_PAGE>(pagePtr);
 
     SkBitmap skBitmap;
-    GraphicsJNI::getSkBitmap(env, jbitmap, &skBitmap);
+    bitmap::toBitmap(bitmapPtr).getSkBitmap(&skBitmap);
 
     const int stride = skBitmap.width() * 4;
 
@@ -117,7 +117,7 @@
     {"nativeClose", "(J)V", (void*) nativeClose},
     {"nativeGetPageCount", "(J)I", (void*) nativeGetPageCount},
     {"nativeScaleForPrinting", "(J)Z", (void*) nativeScaleForPrinting},
-    {"nativeRenderPage", "(JJLandroid/graphics/Bitmap;IIIIJI)V", (void*) nativeRenderPage},
+    {"nativeRenderPage", "(JJJIIIIJI)V", (void*) nativeRenderPage},
     {"nativeOpenPageAndGetSize", "(JILandroid/graphics/Point;)J", (void*) nativeOpenPageAndGetSize},
     {"nativeClosePage", "(J)V", (void*) nativeClosePage}
 };
diff --git a/core/jni/android/opengl/util.cpp b/core/jni/android/opengl/util.cpp
index d50e60c..09f0e8e 100644
--- a/core/jni/android/opengl/util.cpp
+++ b/core/jni/android/opengl/util.cpp
@@ -703,27 +703,27 @@
 }
 
 static jint util_getInternalFormat(JNIEnv *env, jclass clazz,
-        jobject jbitmap)
+        jlong bitmapPtr)
 {
     SkBitmap nativeBitmap;
-    GraphicsJNI::getSkBitmap(env, jbitmap, &nativeBitmap);
+    bitmap::toBitmap(bitmapPtr).getSkBitmap(&nativeBitmap);
     return getInternalFormat(nativeBitmap.colorType());
 }
 
 static jint util_getType(JNIEnv *env, jclass clazz,
-        jobject jbitmap)
+        jlong bitmapPtr)
 {
     SkBitmap nativeBitmap;
-    GraphicsJNI::getSkBitmap(env, jbitmap, &nativeBitmap);
+    bitmap::toBitmap(bitmapPtr).getSkBitmap(&nativeBitmap);
     return getType(nativeBitmap.colorType());
 }
 
 static jint util_texImage2D(JNIEnv *env, jclass clazz,
         jint target, jint level, jint internalformat,
-        jobject jbitmap, jint type, jint border)
+        jlong bitmapPtr, jint type, jint border)
 {
     SkBitmap bitmap;
-    GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
+    bitmap::toBitmap(bitmapPtr).getSkBitmap(&bitmap);
     SkColorType colorType = bitmap.colorType();
     if (internalformat < 0) {
         internalformat = getInternalFormat(colorType);
@@ -748,10 +748,10 @@
 
 static jint util_texSubImage2D(JNIEnv *env, jclass clazz,
         jint target, jint level, jint xoffset, jint yoffset,
-        jobject jbitmap, jint format, jint type)
+        jlong bitmapPtr, jint format, jint type)
 {
     SkBitmap bitmap;
-    GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
+    bitmap::toBitmap(bitmapPtr).getSkBitmap(&bitmap);
     SkColorType colorType = bitmap.colorType();
     int internalFormat = getInternalFormat(colorType);
     if (format < 0) {
@@ -1068,10 +1068,10 @@
 };
 
 static const JNINativeMethod gUtilsMethods[] = {
-    { "native_getInternalFormat", "(Landroid/graphics/Bitmap;)I", (void*) util_getInternalFormat },
-    { "native_getType", "(Landroid/graphics/Bitmap;)I", (void*) util_getType },
-    { "native_texImage2D", "(IIILandroid/graphics/Bitmap;II)I", (void*)util_texImage2D },
-    { "native_texSubImage2D", "(IIIILandroid/graphics/Bitmap;II)I", (void*)util_texSubImage2D },
+    { "native_getInternalFormat", "(J)I", (void*) util_getInternalFormat },
+    { "native_getType", "(J)I", (void*) util_getType },
+    { "native_texImage2D", "(IIIJII)I", (void*)util_texImage2D },
+    { "native_texSubImage2D", "(IIIIJII)I", (void*)util_texSubImage2D },
 };
 
 static const JNINativeMethod gEtc1Methods[] = {
diff --git a/core/jni/android_graphics_Canvas.cpp b/core/jni/android_graphics_Canvas.cpp
index 9c48c33..7a8c5c8 100644
--- a/core/jni/android_graphics_Canvas.cpp
+++ b/core/jni/android_graphics_Canvas.cpp
@@ -54,20 +54,20 @@
 }
 
 // Native wrapper constructor used by Canvas(Bitmap)
-static jlong initRaster(JNIEnv* env, jobject, jobject jbitmap) {
+static jlong initRaster(JNIEnv* env, jobject, jlong bitmapHandle) {
     SkBitmap bitmap;
-    if (jbitmap != NULL) {
-        GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
+    if (bitmapHandle != 0) {
+        bitmap::toBitmap(bitmapHandle).getSkBitmap(&bitmap);
     }
     return reinterpret_cast<jlong>(Canvas::create_canvas(bitmap));
 }
 
 // Set the given bitmap as the new draw target (wrapped in a new SkCanvas),
 // optionally copying canvas matrix & clip state.
-static void setBitmap(JNIEnv* env, jobject, jlong canvasHandle, jobject jbitmap) {
+static void setBitmap(JNIEnv* env, jobject, jlong canvasHandle, jlong bitmapHandle) {
     SkBitmap bitmap;
-    if (jbitmap != NULL) {
-        GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
+    if (bitmapHandle != 0) {
+        bitmap::toBitmap(bitmapHandle).getSkBitmap(&bitmap);
     }
     get_canvas(canvasHandle)->setBitmap(bitmap);
 }
@@ -397,7 +397,7 @@
         jlong paintHandle, jint dstDensity, jint srcDensity) {
 
     Canvas* canvas = get_canvas(canvasHandle);
-    Bitmap& bitmap = android::bitmap::toBitmap(env, bitmapHandle);
+    Bitmap& bitmap = android::bitmap::toBitmap(bitmapHandle);
     const android::Res_png_9patch* chunk = reinterpret_cast<android::Res_png_9patch*>(chunkHandle);
     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
 
@@ -423,11 +423,11 @@
     }
 }
 
-static void drawBitmap(JNIEnv* env, jobject, jlong canvasHandle, jobject jbitmap,
+static void drawBitmap(JNIEnv* env, jobject, jlong canvasHandle, jlong bitmapHandle,
                        jfloat left, jfloat top, jlong paintHandle, jint canvasDensity,
                        jint screenDensity, jint bitmapDensity) {
     Canvas* canvas = get_canvas(canvasHandle);
-    Bitmap& bitmap = android::bitmap::toBitmap(env, jbitmap);
+    Bitmap& bitmap = android::bitmap::toBitmap(bitmapHandle);
     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
 
     if (canvasDensity == bitmapDensity || canvasDensity == 0 || bitmapDensity == 0) {
@@ -458,22 +458,22 @@
     }
 }
 
-static void drawBitmapMatrix(JNIEnv* env, jobject, jlong canvasHandle, jobject jbitmap,
+static void drawBitmapMatrix(JNIEnv* env, jobject, jlong canvasHandle, jlong bitmapHandle,
                              jlong matrixHandle, jlong paintHandle) {
     const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
-    Bitmap& bitmap = android::bitmap::toBitmap(env, jbitmap);
+    Bitmap& bitmap = android::bitmap::toBitmap(bitmapHandle);
     get_canvas(canvasHandle)->drawBitmap(bitmap, *matrix, paint);
 }
 
-static void drawBitmapRect(JNIEnv* env, jobject, jlong canvasHandle, jobject jbitmap,
+static void drawBitmapRect(JNIEnv* env, jobject, jlong canvasHandle, jlong bitmapHandle,
                            float srcLeft, float srcTop, float srcRight, float srcBottom,
                            float dstLeft, float dstTop, float dstRight, float dstBottom,
                            jlong paintHandle, jint screenDensity, jint bitmapDensity) {
     Canvas* canvas = get_canvas(canvasHandle);
     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
 
-    Bitmap& bitmap = android::bitmap::toBitmap(env, jbitmap);
+    Bitmap& bitmap = android::bitmap::toBitmap(bitmapHandle);
     if (screenDensity != 0 && screenDensity != bitmapDensity) {
         Paint filteredPaint;
         if (paint) {
@@ -512,7 +512,7 @@
     get_canvas(canvasHandle)->drawBitmap(*androidBitmap, x, y, paint);
 }
 
-static void drawBitmapMesh(JNIEnv* env, jobject, jlong canvasHandle, jobject jbitmap,
+static void drawBitmapMesh(JNIEnv* env, jobject, jlong canvasHandle, jlong bitmapHandle,
                            jint meshWidth, jint meshHeight, jfloatArray jverts,
                            jint vertIndex, jintArray jcolors, jint colorIndex, jlong paintHandle) {
     if (Canvas::GetApiLevel() < __ANDROID_API_P__) {
@@ -527,7 +527,7 @@
     AutoJavaIntArray colorA(env, jcolors, colorIndex + ptCount);
 
     const Paint* paint = reinterpret_cast<Paint*>(paintHandle);
-    Bitmap& bitmap = android::bitmap::toBitmap(env, jbitmap);
+    Bitmap& bitmap = android::bitmap::toBitmap(bitmapHandle);
     get_canvas(canvasHandle)->drawBitmapMesh(bitmap, meshWidth, meshHeight,
                                              vertA.ptr() + vertIndex*2,
                                              colorA.ptr() + colorIndex, paint);
@@ -651,13 +651,13 @@
 
 static const JNINativeMethod gMethods[] = {
     {"nGetNativeFinalizer", "()J", (void*) CanvasJNI::getNativeFinalizer},
-    {"nInitRaster", "(Landroid/graphics/Bitmap;)J", (void*) CanvasJNI::initRaster},
     {"nFreeCaches", "()V", (void*) CanvasJNI::freeCaches},
     {"nFreeTextLayoutCaches", "()V", (void*) CanvasJNI::freeTextLayoutCaches},
     {"nSetCompatibilityVersion", "(I)V", (void*) CanvasJNI::setCompatibilityVersion},
 
     // ------------ @FastNative ----------------
-    {"nSetBitmap", "(JLandroid/graphics/Bitmap;)V", (void*) CanvasJNI::setBitmap},
+    {"nInitRaster", "(J)J", (void*) CanvasJNI::initRaster},
+    {"nSetBitmap", "(JJ)V", (void*) CanvasJNI::setBitmap},
     {"nGetClipBounds","(JLandroid/graphics/Rect;)Z", (void*) CanvasJNI::getClipBounds},
 
     // ------------ @CriticalNative ----------------
@@ -706,10 +706,10 @@
     {"nDrawPath","(JJJ)V", (void*) CanvasJNI::drawPath},
     {"nDrawVertices", "(JII[FI[FI[II[SIIJ)V", (void*)CanvasJNI::drawVertices},
     {"nDrawNinePatch", "(JJJFFFFJII)V", (void*)CanvasJNI::drawNinePatch},
-    {"nDrawBitmapMatrix", "(JLandroid/graphics/Bitmap;JJ)V", (void*)CanvasJNI::drawBitmapMatrix},
-    {"nDrawBitmapMesh", "(JLandroid/graphics/Bitmap;II[FI[IIJ)V", (void*)CanvasJNI::drawBitmapMesh},
-    {"nDrawBitmap","(JLandroid/graphics/Bitmap;FFJIII)V", (void*) CanvasJNI::drawBitmap},
-    {"nDrawBitmap","(JLandroid/graphics/Bitmap;FFFFFFFFJII)V", (void*) CanvasJNI::drawBitmapRect},
+    {"nDrawBitmapMatrix", "(JJJJ)V", (void*)CanvasJNI::drawBitmapMatrix},
+    {"nDrawBitmapMesh", "(JJII[FI[IIJ)V", (void*)CanvasJNI::drawBitmapMesh},
+    {"nDrawBitmap","(JJFFJIII)V", (void*) CanvasJNI::drawBitmap},
+    {"nDrawBitmap","(JJFFFFFFFFJII)V", (void*) CanvasJNI::drawBitmapRect},
     {"nDrawBitmap", "(J[IIIFFIIZJ)V", (void*)CanvasJNI::drawBitmapArray},
     {"nDrawText","(J[CIIFFIJ)V", (void*) CanvasJNI::drawTextChars},
     {"nDrawText","(JLjava/lang/String;IIFFIJ)V", (void*) CanvasJNI::drawTextString},
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index c8f81e2..a296d64 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -144,6 +144,7 @@
 static jclass gAudioMixingRuleClass;
 static struct {
     jfieldID    mCriteria;
+    jfieldID    mAllowPrivilegedPlaybackCapture;
     // other fields unused by JNI
 } gAudioMixingRuleFields;
 
@@ -1868,6 +1869,8 @@
 
     jobject jRule = env->GetObjectField(jAudioMix, gAudioMixFields.mRule);
     jobject jRuleCriteria = env->GetObjectField(jRule, gAudioMixingRuleFields.mCriteria);
+    nAudioMix->mAllowPrivilegedPlaybackCapture =
+            env->GetBooleanField(jRule, gAudioMixingRuleFields.mAllowPrivilegedPlaybackCapture);
     env->DeleteLocalRef(jRule);
     jobjectArray jCriteria = (jobjectArray)env->CallObjectMethod(jRuleCriteria,
                                                                  gArrayListMethods.toArray);
@@ -2226,6 +2229,11 @@
     return AudioSystem::isHapticPlaybackSupported();
 }
 
+static jint
+android_media_AudioSystem_setAllowedCapturePolicy(JNIEnv *env, jobject thiz, jint uid, jint flags) {
+    return AudioSystem::setAllowedCapturePolicy(uid, flags);
+}
+
 // ----------------------------------------------------------------------------
 
 static const JNINativeMethod gMethods[] = {
@@ -2301,6 +2309,7 @@
     {"isHapticPlaybackSupported", "()Z", (void *)android_media_AudioSystem_isHapticPlaybackSupported},
     {"getHwOffloadEncodingFormatsSupportedForA2DP", "(Ljava/util/ArrayList;)I",
                     (void*)android_media_AudioSystem_getHwOffloadEncodingFormatsSupportedForA2DP},
+    {"setAllowedCapturePolicy", "(II)I", (void *)android_media_AudioSystem_setAllowedCapturePolicy},
 };
 
 static const JNINativeMethod gEventHandlerMethods[] = {
@@ -2456,6 +2465,8 @@
     gAudioMixingRuleClass = MakeGlobalRefOrDie(env, audioMixingRuleClass);
     gAudioMixingRuleFields.mCriteria = GetFieldIDOrDie(env, audioMixingRuleClass, "mCriteria",
                                                        "Ljava/util/ArrayList;");
+    gAudioMixingRuleFields.mAllowPrivilegedPlaybackCapture =
+            GetFieldIDOrDie(env, audioMixingRuleClass, "mAllowPrivilegedPlaybackCapture", "Z");
 
     jclass audioMixMatchCriterionClass =
                 FindClassOrDie(env, "android/media/audiopolicy/AudioMixingRule$AudioMixMatchCriterion");
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index d7a981e..82acf6f 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -470,6 +470,7 @@
     std::vector<uint8_t> buf(MAXPACKETSIZE, 0);
 
     int res = resNetworkResult(fd, &rcode, buf.data(), MAXPACKETSIZE);
+    jniSetFileDescriptorOfFD(env, javaFd, -1);
     if (res < 0) {
         throwErrnoException(env, "resNetworkResult", -res);
         return nullptr;
@@ -490,6 +491,7 @@
 static void android_net_utils_resNetworkCancel(JNIEnv *env, jobject thiz, jobject javaFd) {
     int fd = jniGetFDFromFileDescriptor(env, javaFd);
     resNetworkCancel(fd);
+    jniSetFileDescriptorOfFD(env, javaFd, -1);
 }
 
 static jobject android_net_utils_getTcpRepairWindow(JNIEnv *env, jobject thiz, jobject javaFd) {
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index ecc2dd0..e7cbf93 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -736,11 +736,11 @@
 }
 
 static jboolean android_view_ThreadedRenderer_copyLayerInto(JNIEnv* env, jobject clazz,
-        jlong proxyPtr, jlong layerPtr, jobject jbitmap) {
+        jlong proxyPtr, jlong layerPtr, jlong bitmapPtr) {
     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
     DeferredLayerUpdater* layer = reinterpret_cast<DeferredLayerUpdater*>(layerPtr);
     SkBitmap bitmap;
-    GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
+    bitmap::toBitmap(bitmapPtr).getSkBitmap(&bitmap);
     return proxy->copyLayerInto(layer, bitmap);
 }
 
@@ -911,9 +911,9 @@
 
 static jint android_view_ThreadedRenderer_copySurfaceInto(JNIEnv* env,
         jobject clazz, jobject jsurface, jint left, jint top,
-        jint right, jint bottom, jobject jbitmap) {
+        jint right, jint bottom, jlong bitmapPtr) {
     SkBitmap bitmap;
-    GraphicsJNI::getSkBitmap(env, jbitmap, &bitmap);
+    bitmap::toBitmap(bitmapPtr).getSkBitmap(&bitmap);
     sp<Surface> surface = android_view_Surface_getSurface(env, jsurface);
     return RenderProxy::copySurfaceInto(surface, left, top, right, bottom, &bitmap);
 }
@@ -1106,7 +1106,7 @@
     { "nInvokeFunctor", "(JZ)V", (void*) android_view_ThreadedRenderer_invokeFunctor },
     { "nCreateTextureLayer", "(J)J", (void*) android_view_ThreadedRenderer_createTextureLayer },
     { "nBuildLayer", "(JJ)V", (void*) android_view_ThreadedRenderer_buildLayer },
-    { "nCopyLayerInto", "(JJLandroid/graphics/Bitmap;)Z", (void*) android_view_ThreadedRenderer_copyLayerInto },
+    { "nCopyLayerInto", "(JJJ)Z", (void*) android_view_ThreadedRenderer_copyLayerInto },
     { "nPushLayerUpdate", "(JJ)V", (void*) android_view_ThreadedRenderer_pushLayerUpdate },
     { "nCancelLayerUpdate", "(JJ)V", (void*) android_view_ThreadedRenderer_cancelLayerUpdate },
     { "nDetachSurfaceTexture", "(JJ)V", (void*) android_view_ThreadedRenderer_detachSurfaceTexture },
@@ -1135,7 +1135,7 @@
     { "nRemoveFrameMetricsObserver",
             "(JJ)V",
             (void*)android_view_ThreadedRenderer_removeFrameMetricsObserver },
-    { "nCopySurfaceInto", "(Landroid/view/Surface;IIIILandroid/graphics/Bitmap;)I",
+    { "nCopySurfaceInto", "(Landroid/view/Surface;IIIIJ)I",
                 (void*)android_view_ThreadedRenderer_copySurfaceInto },
     { "nCreateHardwareBitmap", "(JII)Landroid/graphics/Bitmap;",
             (void*)android_view_ThreadedRenderer_createHardwareBitmapFromRenderNode },
diff --git a/core/proto/android/server/activitymanagerservice.proto b/core/proto/android/server/activitymanagerservice.proto
index 4af9fc0..a7d4734 100644
--- a/core/proto/android/server/activitymanagerservice.proto
+++ b/core/proto/android/server/activitymanagerservice.proto
@@ -756,6 +756,7 @@
             optional string file = 2 [ (.android.privacy).dest = DEST_EXPLICIT ];
             optional int32 pid = 3;
             optional int32 uid = 4;
+            optional bool is_user_initiated = 5;
         }
         optional Dump dump = 2;
     }
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 2d7cfa4..ba7a93f 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -629,6 +629,9 @@
 
     <protected-broadcast android:name="android.intent.action.DEVICE_CUSTOMIZATION_READY" />
 
+    <!-- For tether entitlement recheck-->
+    <protected-broadcast
+        android:name="com.android.server.connectivity.tethering.PROVISIONING_RECHECK_ALARM" />
     <!-- ====================================================================== -->
     <!--                          RUNTIME PERMISSIONS                           -->
     <!-- ====================================================================== -->
@@ -3562,10 +3565,30 @@
         android:protectionLevel="signature" />
 
     <!-- Allows an application to capture audio output.
+         Use the {@code CAPTURE_MEDIA_OUTPUT} permission if only the {@code USAGE_UNKNOWN}),
+         {@code USAGE_MEDIA}) or {@code USAGE_GAME}) usages are intended to be captured.
          <p>Not for use by third-party applications.</p> -->
     <permission android:name="android.permission.CAPTURE_AUDIO_OUTPUT"
         android:protectionLevel="signature|privileged" />
 
+    <!-- @SystemApi Allows an application to capture the audio played by other apps
+         that have set an allow capture policy of
+         {@link android.media.AudioAttributes#ALLOW_CAPTURE_BY_SYSTEM}.
+
+         Without this permission, only audio with an allow capture policy of
+         {@link android.media.AudioAttributes#ALLOW_CAPTURE_BY_ALL} can be used.
+
+         There are strong restriction listed at
+         {@link android.media.AudioAttributes#ALLOW_CAPTURE_BY_SYSTEM}
+         on what an app can do with the captured audio.
+
+         See {@code CAPTURE_AUDIO_OUTPUT} for capturing audio use cases other than media playback.
+
+         <p>Not for use by third-party applications.</p>
+         @hide -->
+    <permission android:name="android.permission.CAPTURE_MEDIA_OUTPUT"
+        android:protectionLevel="signature|privileged" />
+
     <!-- @SystemApi Allows an application to capture audio for hotword detection.
          <p>Not for use by third-party applications.</p>
          @hide -->
diff --git a/core/res/res/drawable/ic_drag_handle.xml b/core/res/res/drawable/ic_drag_handle.xml
index 67ab84d..9b0e204 100644
--- a/core/res/res/drawable/ic_drag_handle.xml
+++ b/core/res/res/drawable/ic_drag_handle.xml
@@ -13,11 +13,9 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24.0dp"
-        android:height="24.0dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
-    <path
-        android:pathData="M20.0,9.0L4.0,9.0l0.0,2.0l16.0,0.0L20.0,9.0zM4.0,15.0l16.0,0.0l0.0,-2.0L4.0,13.0l0.0,2.0z"/>
-</vector>
\ No newline at end of file
+<shape
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle" >
+    <solid android:color="#FFFFFFFF" />
+    <corners android:radius="2dp" />
+</shape>
diff --git a/packages/SystemUI/res/drawable/ic_signal_airplane.xml b/core/res/res/drawable/ic_qs_airplane.xml
similarity index 75%
rename from packages/SystemUI/res/drawable/ic_signal_airplane.xml
rename to core/res/res/drawable/ic_qs_airplane.xml
index f708ed9..166d415 100644
--- a/packages/SystemUI/res/drawable/ic_signal_airplane.xml
+++ b/core/res/res/drawable/ic_qs_airplane.xml
@@ -15,12 +15,11 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24dp"
-        android:height="24dp"
+        android:width="18dp"
+        android:height="18dp"
         android:viewportWidth="24"
         android:viewportHeight="24">
-
-<path
-    android:fillColor="#FFFFFF"
-    android:pathData="M21,16v-2l-8-5V3.5C13,2.67,12.33,2,11.5,2S10,2.67,10,3.5V9l-8,5v2l8-2.5V19l-2,1.5V22l3.5-1l3.5,1v-1.5L13,19v-5.5L21,16z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M21,16v-2l-8-5V3.5C13,2.67,12.33,2,11.5,2S10,2.67,10,3.5V9l-8,5v2l8-2.5V19l-2,1.5V22l3.5-1l3.5,1v-1.5L13,19v-5.5L21,16z" />
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_auto_rotate.xml b/core/res/res/drawable/ic_qs_auto_rotate.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/ic_qs_auto_rotate.xml
rename to core/res/res/drawable/ic_qs_auto_rotate.xml
diff --git a/core/res/res/drawable/ic_qs_bluetooth.xml b/core/res/res/drawable/ic_qs_bluetooth.xml
new file mode 100644
index 0000000..91fcff0
--- /dev/null
+++ b/core/res/res/drawable/ic_qs_bluetooth.xml
@@ -0,0 +1,25 @@
+<!--
+    Copyright (C) 2016 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0"
+        android:tint="?android:attr/colorControlNormal">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M17.71,7.71L12,2h-1v7.59L6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 11,14.41L11,22h1l5.71,-5.71 -4.3,-4.29 4.3,-4.29zM13,5.83l1.88,1.88L13,9.59L13,5.83zM14.88,16.29L13,18.17v-3.76l1.88,1.88z"/>
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_signal_airplane.xml b/core/res/res/drawable/ic_qs_dnd.xml
similarity index 60%
copy from packages/SystemUI/res/drawable/ic_signal_airplane.xml
copy to core/res/res/drawable/ic_qs_dnd.xml
index f708ed9..b361169 100644
--- a/packages/SystemUI/res/drawable/ic_signal_airplane.xml
+++ b/core/res/res/drawable/ic_qs_dnd.xml
@@ -1,6 +1,5 @@
-<?xml version="1.0" encoding="utf-8"?>
 <!--
-     Copyright (C) 2019 The Android Open Source Project
+     Copyright (C) 2017 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -15,12 +14,12 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24dp"
-        android:height="24dp"
-        android:viewportWidth="24"
-        android:viewportHeight="24">
+    android:height="17dp"
+    android:width="17dp"
+    android:viewportHeight="24.0"
+    android:viewportWidth="24.0" >
 
-<path
-    android:fillColor="#FFFFFF"
-    android:pathData="M21,16v-2l-8-5V3.5C13,2.67,12.33,2,11.5,2S10,2.67,10,3.5V9l-8,5v2l8-2.5V19l-2,1.5V22l3.5-1l3.5,1v-1.5L13,19v-5.5L21,16z" />
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM7,11h10v2L7,13z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_signal_flashlight.xml b/core/res/res/drawable/ic_qs_flashlight.xml
similarity index 100%
rename from packages/SystemUI/res/drawable/ic_signal_flashlight.xml
rename to core/res/res/drawable/ic_qs_flashlight.xml
diff --git a/core/res/res/drawable/ic_settings_bluetooth.xml b/core/res/res/drawable/ic_settings_bluetooth.xml
index 6e32e1a..91fcff0 100644
--- a/core/res/res/drawable/ic_settings_bluetooth.xml
+++ b/core/res/res/drawable/ic_settings_bluetooth.xml
@@ -14,12 +14,12 @@
     limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24.0dp"
-        android:height="24.0dp"
+        android:width="24dp"
+        android:height="24dp"
         android:viewportWidth="24.0"
         android:viewportHeight="24.0"
         android:tint="?android:attr/colorControlNormal">
     <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M13.5,12l3.8,-3.7c0.4,-0.4 0.4,-1.1 0,-1.5l-4.5,-4.5c-0.4,-0.4 -1.1,-0.4 -1.5,0.1C11.1,2.5 11,2.8 11,3v6.4L6.9,5.4C6.5,5 5.9,5 5.5,5.4s-0.4,1.1 0,1.5l5.1,5.1l-5.1,5.1c-0.4,0.4 -0.4,1.1 0,1.5s1.1,0.4 1.5,0l4.1,-4V21c0,0.6 0.5,1 1,1c0.3,0 0.5,-0.1 0.7,-0.3l0.1,0l4.5,-4.5c0.4,-0.4 0.4,-1.1 0,-1.5L13.5,12zM13,9.7V5.4l2.1,2.2L13,9.7zM13,18.6v-4.3l2.1,2.2L13,18.6z"/>
-</vector>
+        android:fillColor="@android:color/white"
+        android:pathData="M17.71,7.71L12,2h-1v7.59L6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 11,14.41L11,22h1l5.71,-5.71 -4.3,-4.29 4.3,-4.29zM13,5.83l1.88,1.88L13,9.59L13,5.83zM14.88,16.29L13,18.17v-3.76l1.88,1.88z"/>
+</vector>
\ No newline at end of file
diff --git a/core/res/res/layout/chooser_grid.xml b/core/res/res/layout/chooser_grid.xml
index 2860ee4..1f80417 100644
--- a/core/res/res/layout/chooser_grid.xml
+++ b/core/res/res/layout/chooser_grid.xml
@@ -20,7 +20,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:maxCollapsedHeight="288dp"
+    android:maxCollapsedHeight="0dp"
     android:maxCollapsedHeightSmall="56dp"
     android:id="@id/contentPanel">
 
@@ -32,12 +32,12 @@
 
         <ImageView
             android:id="@+id/drag"
-            android:layout_width="48dp"
-            android:layout_height="wrap_content"
+            android:layout_width="32dp"
+            android:layout_height="4dp"
             android:src="@drawable/ic_drag_handle"
             android:clickable="true"
-            android:paddingTop="@dimen/chooser_edge_margin_normal"
-            android:tint="?android:attr/textColorSecondary"
+            android:layout_marginTop="@dimen/chooser_view_spacing"
+            android:tint="@color/lighter_gray"
             android:layout_centerHorizontal="true"
             android:layout_alignParentTop="true" />
 
@@ -62,8 +62,8 @@
                   android:textAppearance="?attr/textAppearanceMedium"
                   android:textSize="20sp"
                   android:gravity="center"
-                  android:paddingTop="18dp"
-                  android:paddingBottom="18dp"
+                  android:paddingTop="@dimen/chooser_view_spacing"
+                  android:paddingBottom="@dimen/chooser_view_spacing"
                   android:paddingLeft="24dp"
                   android:paddingRight="24dp"
                   android:layout_below="@id/profile_button"
diff --git a/core/res/res/values-sw600dp/config.xml b/core/res/res/values-sw600dp/config.xml
index 6edb88e..e2c8d8a 100644
--- a/core/res/res/values-sw600dp/config.xml
+++ b/core/res/res/values-sw600dp/config.xml
@@ -51,5 +51,9 @@
              4 - Snap to the long edges in each orientation and magnet to corners
     -->
     <integer name="config_pictureInPictureSnapMode">3</integer>
+
+    <!-- Controls whether the nav bar can move from the bottom to the side in landscape.
+         Only applies if the device display is not square. -->
+    <bool name="config_navBarCanMove">false</bool>
 </resources>
 
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index fe2c665..362d01c 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1673,8 +1673,19 @@
              This flag is turned on by default. <em>This attribute is usable only by system apps.
              </em> -->
         <attr name="allowClearUserDataOnFailedRestore"/>
-        <!-- If {@code true} the app's non sensitive audio can be capture by other apps.
-             The default value is true. -->
+        <!-- If {@code true} the app's non sensitive audio can be capture by other apps with
+             {@code AudioPlaybackCaptureConfiguration} and a {@code MediaProjection}.
+
+             <p>
+             Non sensitive audio is defined as audio whose {@code AttributeUsage} is
+             {@code USAGE_UNKNOWN}), {@code USAGE_MEDIA}) or {@code USAGE_GAME}).
+             All other usages (eg. {@code USAGE_VOICE_COMMUNICATION}) will not be captured.
+
+             <p>
+             The default value is:
+                 - {@code true} for apps with targetSdkVersion >= 29 (Q).
+                 - {@code false} for apps with targetSdkVersion < 29.
+             -->
         <attr name="allowAudioPlaybackCapture" format="boolean" />
     </declare-styleable>
     <!-- The <code>permission</code> tag declares a security permission that can be
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index dc0ec03..77ce8c3 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3237,6 +3237,10 @@
          2: gestures only for back, home and overview -->
     <integer name="config_navBarInteractionMode">0</integer>
 
+    <!-- Controls whether the nav bar can move from the bottom to the side in landscape.
+         Only applies if the device display is not square. -->
+    <bool name="config_navBarCanMove">true</bool>
+
     <!-- Default insets [LEFT/RIGHTxTOP/BOTTOM] from the screen edge for picture-in-picture windows.
          These values are in DPs and will be converted to pixel sizes internally. -->
     <string translatable="false" name="config_defaultPictureInPictureScreenEdgeInsets">16x16</string>
@@ -3975,4 +3979,28 @@
     <!-- The type of the light sensor to be used by the display framework for things like
          auto-brightness. If unset, then it just gets the default sensor of type TYPE_LIGHT. -->
     <string name="config_displayLightSensorType" translatable="false" />
+
+    <!-- Whether or not to enable automatic heap dumps for the system server on debuggable builds. -->
+    <bool name="config_debugEnableAutomaticSystemServerHeapDumps">false</bool>
+
+    <!-- See DropBoxManagerService.
+         The minimum period in milliseconds between broadcasts for entries with low priority
+         dropbox tags. -->
+    <integer name="config_dropboxLowPriorityBroadcastRateLimitPeriod">2000</integer>
+
+    <!-- See DropBoxManagerService.
+         An array of dropbox entry tags to marked as low priority. Low priority broadcasts will be
+         rated limited to a period defined by config_dropboxLowPriorityBroadcastRateLimitPeriod
+         (high frequency broadcasts for the tag will be dropped) -->
+    <string-array name="config_dropboxLowPriorityTags" translatable="false">
+        <item>data_app_strictmode</item>
+        <item>data_app_wtf</item>
+        <item>keymaster</item>
+        <item>netstats</item>
+        <item>system_app_strictmode</item>
+        <item>system_app_wtf</item>
+        <item>system_server_strictmode</item>
+        <item>system_server_wtf</item>
+    </string-array>
+
 </resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 023fbad..feecd02 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -725,4 +725,5 @@
     <dimen name="resolver_icon_size">42dp</dimen>
     <dimen name="resolver_badge_size">18dp</dimen>
     <dimen name="chooser_target_width">76dp</dimen>
+    <dimen name="chooser_max_collapsed_height">288dp</dimen>
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index bb47370..45494a0 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4835,7 +4835,7 @@
     <string name="package_deleted_device_owner">Deleted by your admin</string>
 
     <!-- [CHAR LIMIT=25] String for confirmation button to enable a feature gated by the battery saver warning-->
-    <string name="confirm_battery_saver">Confirm</string>
+    <string name="confirm_battery_saver">OK</string>
 
     <!-- [CHAR_LIMIT=NONE] Battery saver: Feature description, with a "learn more" link. -->
     <string name="battery_saver_description_with_learn_more">Battery Saver turns off or restricts background activity, some visual effects \u0026 other high-power features to extend battery life. <annotation id="url">Learn More</annotation></string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index ae54a6a..35fd88e 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1443,6 +1443,11 @@
   <java-symbol type="drawable" name="ic_instant_icon_badge_bolt" />
   <java-symbol type="drawable" name="emulator_circular_window_overlay" />
   <java-symbol type="drawable" name="ic_qs_battery_saver" />
+  <java-symbol type="drawable" name="ic_qs_bluetooth" />
+  <java-symbol type="drawable" name="ic_qs_airplane" />
+  <java-symbol type="drawable" name="ic_qs_flashlight" />
+  <java-symbol type="drawable" name="ic_qs_auto_rotate" />
+  <java-symbol type="drawable" name="ic_qs_dnd" />
 
   <java-symbol type="drawable" name="sim_light_blue" />
   <java-symbol type="drawable" name="sim_light_green" />
@@ -2771,6 +2776,7 @@
   <java-symbol type="dimen" name="chooser_edge_margin_normal" />
   <java-symbol type="dimen" name="chooser_preview_image_font_size"/>
   <java-symbol type="dimen" name="chooser_preview_width" />
+  <java-symbol type="dimen" name="chooser_max_collapsed_height" />
   <java-symbol type="layout" name="chooser_grid" />
   <java-symbol type="layout" name="chooser_grid_preview_text" />
   <java-symbol type="layout" name="chooser_grid_preview_image" />
@@ -2837,6 +2843,7 @@
   <java-symbol type="bool" name="config_forceWindowDrawsStatusBarBackground" />
   <java-symbol type="integer" name="config_navBarOpacityMode" />
   <java-symbol type="integer" name="config_navBarInteractionMode" />
+  <java-symbol type="bool" name="config_navBarCanMove" />
   <java-symbol type="color" name="system_bar_background_semi_transparent" />
 
   <!-- EditText suggestion popup. -->
@@ -3222,6 +3229,8 @@
   <java-symbol type="string" name="config_batterymeterPowersavePath" />
   <java-symbol type="bool" name="config_batterymeterDualTone" />
 
+  <java-symbol type="bool" name="config_debugEnableAutomaticSystemServerHeapDumps" />
+
   <!-- Accessibility Shortcut -->
   <java-symbol type="string" name="accessibility_shortcut_warning_dialog_title" />
   <java-symbol type="string" name="accessibility_shortcut_toogle_warning" />
@@ -3601,6 +3610,7 @@
   <java-symbol type="style" name="Theme.DeviceDefault.Light.Dialog.Alert.UserSwitchingDialog" />
 
   <java-symbol type="string" name="battery_saver_description_with_learn_more" />
+  <java-symbol type="string" name="confirm_battery_saver" />
 
   <java-symbol type="attr" name="opticalInsetLeft" />
   <java-symbol type="attr" name="opticalInsetTop" />
@@ -3727,4 +3737,7 @@
   <java-symbol type="dimen" name="resolver_icon_size"/>
   <java-symbol type="dimen" name="resolver_badge_size"/>
 
+  <!-- For DropBox -->
+  <java-symbol type="integer" name="config_dropboxLowPriorityBroadcastRateLimitPeriod" />
+  <java-symbol type="array" name="config_dropboxLowPriorityTags" />
 </resources>
diff --git a/core/tests/coretests/src/android/database/TranslatingCursorTest.java b/core/tests/coretests/src/android/database/TranslatingCursorTest.java
new file mode 100644
index 0000000..baca7ef
--- /dev/null
+++ b/core/tests/coretests/src/android/database/TranslatingCursorTest.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2007 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES 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.database;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.database.TranslatingCursor.Translator;
+import android.net.Uri;
+
+import junit.framework.TestCase;
+
+public class TranslatingCursorTest extends TestCase {
+
+    public void testDuplicateColumnName() {
+        MatrixCursor base = new MatrixCursor(new String[] {"_id", "colA", "colB", "colA"});
+        base.addRow(new Object[] { 0, "r1_a", "r1_b", "r1_a"});
+        base.addRow(new Object[] { 1, "r2_a", "r2_b", "r2_a"});
+        Translator translator = (data, idIndex, matchingColumn, cursor) -> data.toUpperCase();
+        TranslatingCursor.Config config = new TranslatingCursor.Config(Uri.EMPTY, "_id", "colA");
+        TranslatingCursor translating = new TranslatingCursor(base, config, translator, false);
+
+        translating.moveToNext();
+        String[] expected = new String[] { "ignored", "R1_A", "r1_b", "R1_A" };
+        for (int i = 1; i < translating.getColumnCount(); i++) {
+            assertThat(translating.getString(i)).isEqualTo(expected[i]);
+        }
+        translating.moveToNext();
+        expected = new String[] { "ignored", "R2_A", "r2_b", "R2_A" };
+        for (int i = 1; i < translating.getColumnCount(); i++) {
+            assertThat(translating.getString(i)).isEqualTo(expected[i]);
+        }
+    }
+
+}
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 8fc6a96..80250db 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -287,8 +287,6 @@
                     Settings.Global.HDMI_CONTROL_ENABLED,
                     Settings.Global.HDMI_SYSTEM_AUDIO_CONTROL_ENABLED,
                     Settings.Global.HEADS_UP_NOTIFICATIONS_ENABLED,
-                    Settings.Global.HIDDEN_API_ACCESS_LOG_SAMPLING_RATE,
-                    Settings.Global.HIDDEN_API_ACCESS_STATSLOG_SAMPLING_RATE,
                     Settings.Global.HIDDEN_API_POLICY,
                     Settings.Global.HIDE_ERROR_DIALOGS,
                     Settings.Global.HTTP_PROXY,
diff --git a/core/tests/coretests/src/android/view/ViewGroupTest.java b/core/tests/coretests/src/android/view/ViewGroupTest.java
new file mode 100644
index 0000000..979a839
--- /dev/null
+++ b/core/tests/coretests/src/android/view/ViewGroupTest.java
@@ -0,0 +1,133 @@
+/*
+ * 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;
+
+import static androidx.test.InstrumentationRegistry.getContext;
+
+import static org.junit.Assert.assertEquals;
+
+import android.content.Context;
+import android.graphics.Region;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+
+
+/**
+ * Test basic functions of ViewGroup.
+ *
+ * Build/Install/Run:
+ *     atest FrameworksCoreTests:ViewGroupTest
+ */
+@Presubmit
+@SmallTest
+public class ViewGroupTest {
+
+    /**
+     * Test if {@link ViewGroup#subtractObscuredTouchableRegion} works as expected.
+     *
+     * The view hierarchy:
+     *   A---B---C
+     *    \   \
+     *     \   --D
+     *      \
+     *       E---F
+     *
+     * The layer and bounds of each view:
+     *   F -- (invisible)
+     *   E --
+     *   D ----
+     *   C ----------
+     *   B ------
+     *   A --------
+     */
+    @Test
+    public void testSubtractObscuredTouchableRegion() {
+        final Context context = getContext();
+        final TestView viewA = new TestView(context, 8 /* right */);
+        final TestView viewB = new TestView(context, 6 /* right */);
+        final TestView viewC = new TestView(context, 10 /* right */);
+        final TestView viewD = new TestView(context, 4 /* right */);
+        final TestView viewE = new TestView(context, 2 /* right */);
+        final TestView viewF = new TestView(context, 2 /* right */);
+
+        viewA.addView(viewB);
+        viewA.addView(viewE);
+        viewB.addView(viewC);
+        viewB.addView(viewD);
+        viewE.addView(viewF);
+
+        viewF.setVisibility(View.INVISIBLE);
+
+        final Region r = new Region();
+
+        getUnobscuredTouchableRegion(r, viewA);
+        assertRegionContainPoint(1 /* x */, r, true /* contain */);
+        assertRegionContainPoint(3 /* x */, r, true /* contain */);
+        assertRegionContainPoint(5 /* x */, r, true /* contain */);
+        assertRegionContainPoint(7 /* x */, r, true /* contain */);
+        assertRegionContainPoint(9 /* x */, r, false /* contain */); // Outside of bounds
+
+        getUnobscuredTouchableRegion(r, viewB);
+        assertRegionContainPoint(1 /* x */, r, false /* contain */); // Obscured by E
+        assertRegionContainPoint(3 /* x */, r, true /* contain */);
+        assertRegionContainPoint(5 /* x */, r, true /* contain */);
+        assertRegionContainPoint(7 /* x */, r, false /* contain */); // Outside of bounds
+
+        getUnobscuredTouchableRegion(r, viewC);
+        assertRegionContainPoint(1 /* x */, r, false /* contain */); // Obscured by D and E
+        assertRegionContainPoint(3 /* x */, r, false /* contain */); // Obscured by D
+        assertRegionContainPoint(5 /* x */, r, true /* contain */);
+        assertRegionContainPoint(7 /* x */, r, false /* contain */); // Outside of parent bounds
+
+        getUnobscuredTouchableRegion(r, viewD);
+        assertRegionContainPoint(1 /* x */, r, false /* contain */); // Obscured by E
+        assertRegionContainPoint(3 /* x */, r, true /* contain */);
+        assertRegionContainPoint(5 /* x */, r, false /* contain */); // Outside of bounds
+
+        getUnobscuredTouchableRegion(r, viewE);
+        assertRegionContainPoint(1 /* x */, r, true /* contain */);
+        assertRegionContainPoint(3 /* x */, r, false /* contain */); // Outside of bounds
+    }
+
+    private static void getUnobscuredTouchableRegion(Region outRegion, View view) {
+        outRegion.set(view.getLeft(), view.getTop(), view.getRight(), view.getBottom());
+        final ViewParent parent = view.getParent();
+        if (parent != null) {
+            parent.subtractObscuredTouchableRegion(outRegion, view);
+        }
+    }
+
+    private static void assertRegionContainPoint(int x, Region region, boolean contain) {
+        assertEquals(String.format("Touchable region must%s contain (%s, 0).",
+                (contain ? "" : " not"), x), contain, region.contains(x, 0 /* y */));
+    }
+
+    private static class TestView extends ViewGroup {
+        TestView(Context context, int right) {
+            super(context);
+            setFrame(0 /* left */, 0 /* top */, right, 1 /* bottom */);
+        }
+
+        @Override
+        protected void onLayout(boolean changed, int l, int t, int r, int b) {
+            // We don't layout this view.
+        }
+    }
+}
diff --git a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureEventTest.java b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureEventTest.java
index 2416de1..2008537 100644
--- a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureEventTest.java
+++ b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureEventTest.java
@@ -49,13 +49,15 @@
 
     private static final LocusId ID = new LocusId("WHATEVER");
 
+    private static final int NO_SESSION_ID = 0;
+
     // Not using @Mock because it's final - no need to be fancy here....
     private final ContentCaptureContext mClientContext =
             new ContentCaptureContext.Builder(ID).build();
 
     @Test
     public void testSetAutofillId_null() {
-        final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_VIEW_DISAPPEARED);
+        final ContentCaptureEvent event = new ContentCaptureEvent(42, TYPE_VIEW_DISAPPEARED);
 
         assertThrows(NullPointerException.class, () -> event.setAutofillId(null));
         assertThat(event.getId()).isNull();
@@ -64,7 +66,7 @@
 
     @Test
     public void testSetAutofillIds_null() {
-        final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_VIEW_DISAPPEARED);
+        final ContentCaptureEvent event = new ContentCaptureEvent(42, TYPE_VIEW_DISAPPEARED);
 
         assertThrows(NullPointerException.class, () -> event.setAutofillIds(null));
         assertThat(event.getId()).isNull();
@@ -73,7 +75,7 @@
 
     @Test
     public void testAddAutofillId_null() {
-        final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_VIEW_DISAPPEARED);
+        final ContentCaptureEvent event = new ContentCaptureEvent(42, TYPE_VIEW_DISAPPEARED);
 
         assertThrows(NullPointerException.class, () -> event.addAutofillId(null));
         assertThat(event.getId()).isNull();
@@ -82,7 +84,7 @@
 
     @Test
     public void testSetAutofillId() {
-        final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_VIEW_DISAPPEARED);
+        final ContentCaptureEvent event = new ContentCaptureEvent(42, TYPE_VIEW_DISAPPEARED);
 
         final AutofillId id = new AutofillId(108);
         event.setAutofillId(id);
@@ -92,7 +94,7 @@
 
     @Test
     public void testSetAutofillIds() {
-        final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_VIEW_DISAPPEARED);
+        final ContentCaptureEvent event = new ContentCaptureEvent(42, TYPE_VIEW_DISAPPEARED);
 
         final AutofillId id = new AutofillId(108);
         final ArrayList<AutofillId> ids = new ArrayList<>(1);
@@ -104,7 +106,7 @@
 
     @Test
     public void testAddAutofillId() {
-        final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_VIEW_DISAPPEARED);
+        final ContentCaptureEvent event = new ContentCaptureEvent(42, TYPE_VIEW_DISAPPEARED);
 
         final AutofillId id1 = new AutofillId(108);
         event.addAutofillId(id1);
@@ -119,7 +121,7 @@
 
     @Test
     public void testAddAutofillId_afterSetId() {
-        final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_VIEW_DISAPPEARED);
+        final ContentCaptureEvent event = new ContentCaptureEvent(42, TYPE_VIEW_DISAPPEARED);
 
         final AutofillId id1 = new AutofillId(108);
         event.setAutofillId(id1);
@@ -134,7 +136,7 @@
 
     @Test
     public void testAddAutofillId_afterSetIds() {
-        final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_VIEW_DISAPPEARED);
+        final ContentCaptureEvent event = new ContentCaptureEvent(42, TYPE_VIEW_DISAPPEARED);
 
         final AutofillId id1 = new AutofillId(108);
         final ArrayList<AutofillId> ids = new ArrayList<>(1);
@@ -163,9 +165,9 @@
     }
 
     private ContentCaptureEvent newEventForSessionStarted() {
-        final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_SESSION_STARTED)
+        final ContentCaptureEvent event = new ContentCaptureEvent(42, TYPE_SESSION_STARTED)
                 .setClientContext(mClientContext)
-                .setParentSessionId("108");
+                .setParentSessionId(108);
         assertThat(event).isNotNull();
         return event;
     }
@@ -173,8 +175,8 @@
     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.getSessionId()).isEqualTo(42);
+        assertThat(event.getParentSessionId()).isEqualTo(108);
         assertThat(event.getId()).isNull();
         assertThat(event.getIds()).isNull();
         assertThat(event.getText()).isNull();
@@ -186,17 +188,17 @@
 
     @Test
     public void testSessionFinished_directly() {
-        final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_SESSION_FINISHED)
-                .setParentSessionId("108");
+        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)
+        final ContentCaptureEvent event = new ContentCaptureEvent(42, TYPE_SESSION_FINISHED)
                 .setClientContext(mClientContext) // should not be writting to parcel
-                .setParentSessionId("108");
+                .setParentSessionId(108);
         assertThat(event).isNotNull();
         final ContentCaptureEvent clone = cloneThroughParcel(event);
         assertSessionFinishedEvent(clone);
@@ -205,8 +207,8 @@
     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.getSessionId()).isEqualTo(42);
+        assertThat(event.getParentSessionId()).isEqualTo(108);
         assertThat(event.getId()).isNull();
         assertThat(event.getIds()).isNull();
         assertThat(event.getText()).isNull();
@@ -216,7 +218,7 @@
 
     @Test
     public void testContextUpdated_directly() {
-        final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_CONTEXT_UPDATED)
+        final ContentCaptureEvent event = new ContentCaptureEvent(42, TYPE_CONTEXT_UPDATED)
                 .setClientContext(mClientContext);
         assertThat(event).isNotNull();
         assertContextUpdatedEvent(event);
@@ -224,7 +226,7 @@
 
     @Test
     public void testContextUpdated_throughParcel() {
-        final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_CONTEXT_UPDATED)
+        final ContentCaptureEvent event = new ContentCaptureEvent(42, TYPE_CONTEXT_UPDATED)
                 .setClientContext(mClientContext);
         assertThat(event).isNotNull();
         final ContentCaptureEvent clone = cloneThroughParcel(event);
@@ -233,9 +235,9 @@
 
     @Test
     public void testMergeEvent_typeViewTextChanged() {
-        final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_VIEW_TEXT_CHANGED)
+        final ContentCaptureEvent event = new ContentCaptureEvent(42, TYPE_VIEW_TEXT_CHANGED)
                 .setText("test");
-        final ContentCaptureEvent event2 = new ContentCaptureEvent("43", TYPE_VIEW_TEXT_CHANGED)
+        final ContentCaptureEvent event2 = new ContentCaptureEvent(43, TYPE_VIEW_TEXT_CHANGED)
                 .setText("empty");
 
         event.mergeEvent(event2);
@@ -244,14 +246,14 @@
 
     @Test
     public void testMergeEvent_typeViewDisappeared() {
-        final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_VIEW_DISAPPEARED)
+        final ContentCaptureEvent event = new ContentCaptureEvent(42, TYPE_VIEW_DISAPPEARED)
                 .setAutofillId(new AutofillId(1));
-        final ContentCaptureEvent event2 = new ContentCaptureEvent("43", TYPE_VIEW_DISAPPEARED)
+        final ContentCaptureEvent event2 = new ContentCaptureEvent(43, TYPE_VIEW_DISAPPEARED)
                 .setAutofillId(new AutofillId(2));
         final ArrayList<AutofillId> autofillIds = new ArrayList<>();
         autofillIds.add(new AutofillId(3));
         autofillIds.add(new AutofillId(4));
-        final ContentCaptureEvent event3 = new ContentCaptureEvent("17", TYPE_VIEW_DISAPPEARED)
+        final ContentCaptureEvent event3 = new ContentCaptureEvent(17, TYPE_VIEW_DISAPPEARED)
                 .setAutofillIds(autofillIds);
 
         event.mergeEvent(event2);
@@ -264,24 +266,24 @@
 
     @Test
     public void testMergeEvent_typeViewDisappeared_noIds() {
-        final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_VIEW_DISAPPEARED)
+        final ContentCaptureEvent event = new ContentCaptureEvent(42, TYPE_VIEW_DISAPPEARED)
                 .setAutofillId(new AutofillId(1));
-        final ContentCaptureEvent event2 = new ContentCaptureEvent("43", TYPE_VIEW_DISAPPEARED);
+        final ContentCaptureEvent event2 = new ContentCaptureEvent(43, TYPE_VIEW_DISAPPEARED);
 
         assertThrows(IllegalArgumentException.class, () -> event.mergeEvent(event2));
     }
 
     @Test
     public void testMergeEvent_nullArgument() {
-        final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_VIEW_DISAPPEARED);
+        final ContentCaptureEvent event = new ContentCaptureEvent(42, TYPE_VIEW_DISAPPEARED);
         assertThrows(NullPointerException.class, () -> event.mergeEvent(null));
     }
 
     @Test
     public void testMergeEvent_differentEventTypes() {
-        final ContentCaptureEvent event = new ContentCaptureEvent("42", TYPE_VIEW_DISAPPEARED)
+        final ContentCaptureEvent event = new ContentCaptureEvent(42, TYPE_VIEW_DISAPPEARED)
                 .setText("test").setAutofillId(new AutofillId(1));
-        final ContentCaptureEvent event2 = new ContentCaptureEvent("17", TYPE_VIEW_TEXT_CHANGED)
+        final ContentCaptureEvent event2 = new ContentCaptureEvent(17, TYPE_VIEW_TEXT_CHANGED)
                 .setText("empty").setAutofillId(new AutofillId(2));
 
         event.mergeEvent(event2);
@@ -296,8 +298,8 @@
     private void assertContextUpdatedEvent(ContentCaptureEvent event) {
         assertThat(event.getType()).isEqualTo(TYPE_CONTEXT_UPDATED);
         assertThat(event.getEventTime()).isAtLeast(MY_EPOCH);
-        assertThat(event.getSessionId()).isEqualTo("42");
-        assertThat(event.getParentSessionId()).isNull();
+        assertThat(event.getSessionId()).isEqualTo(42);
+        assertThat(event.getParentSessionId()).isEqualTo(NO_SESSION_ID);
         assertThat(event.getId()).isNull();
         assertThat(event.getIds()).isNull();
         assertThat(event.getText()).isNull();
diff --git a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java
index 013408e..81ce15a4 100644
--- a/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java
+++ b/core/tests/coretests/src/android/view/contentcapture/ContentCaptureSessionTest.java
@@ -39,9 +39,9 @@
 @RunWith(MockitoJUnitRunner.class)
 public class ContentCaptureSessionTest {
 
-    private ContentCaptureSession mSession1 = new MyContentCaptureSession("111");
+    private ContentCaptureSession mSession1 = new MyContentCaptureSession(111);
 
-    private ContentCaptureSession mSession2 = new MyContentCaptureSession("2222");
+    private ContentCaptureSession mSession2 = new MyContentCaptureSession(2222);
 
     @Mock
     private View mMockView;
@@ -60,12 +60,12 @@
         assertThat(childId.getViewId()).isEqualTo(42);
         assertThat(childId.getVirtualChildLongId()).isEqualTo(108L);
         assertThat(childId.getVirtualChildIntId()).isEqualTo(View.NO_ID);
-        assertThat(childId.getSessionId()).isEqualTo(mSession1.getIdAsInt());
+        assertThat(childId.getSessionId()).isEqualTo(mSession1.getId());
     }
 
     @Test
     public void testNewAutofillId_differentSessions() {
-        assertThat(mSession1.getIdAsInt()).isNotSameAs(mSession2.getIdAsInt()); //sanity check
+        assertThat(mSession1.getId()).isNotEqualTo(mSession2.getId()); //sanity check
         final AutofillId parentId = new AutofillId(42);
         final AutofillId childId1 = mSession1.newAutofillId(parentId, 108L);
         final AutofillId childId2 = mSession2.newAutofillId(parentId, 108L);
@@ -117,7 +117,7 @@
     // Cannot use @Spy because we need to pass the session id on constructor
     private class MyContentCaptureSession extends ContentCaptureSession {
 
-        private MyContentCaptureSession(String id) {
+        private MyContentCaptureSession(int id) {
             super(id);
         }
 
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 8c2375e..185fa07 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
@@ -599,7 +599,7 @@
 
         mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
         waitForIdle();
-        verify(mockLogger, Mockito.times(3)).write(logMakerCaptor.capture());
+        verify(mockLogger, Mockito.times(2)).write(logMakerCaptor.capture());
         // First invocation is from onCreate
         assertThat(logMakerCaptor.getAllValues().get(1).getCategory(),
                 is(MetricsEvent.ACTION_SHARE_WITH_PREVIEW));
@@ -629,7 +629,7 @@
         ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class);
         mActivityRule.launchActivity(Intent.createChooser(sendIntent, null));
         waitForIdle();
-        verify(mockLogger, Mockito.times(3)).write(logMakerCaptor.capture());
+        verify(mockLogger, Mockito.times(2)).write(logMakerCaptor.capture());
         // First invocation is from onCreate
         assertThat(logMakerCaptor.getAllValues().get(1).getCategory(),
                 is(MetricsEvent.ACTION_SHARE_WITH_PREVIEW));
diff --git a/core/xsd/Android.bp b/core/xsd/Android.bp
index 81669eb..738f330 100644
--- a/core/xsd/Android.bp
+++ b/core/xsd/Android.bp
@@ -2,5 +2,5 @@
     name: "permission",
     srcs: ["permission.xsd"],
     api_dir: "schema",
-    package_name: "com.android.xml.permission",
+    package_name: "com.android.xml.permission.configfile",
 }
diff --git a/core/xsd/permission.xsd b/core/xsd/permission.xsd
index d90863b..2ef2d04 100644
--- a/core/xsd/permission.xsd
+++ b/core/xsd/permission.xsd
@@ -60,8 +60,6 @@
         <xs:attribute name="uid" type="xs:int"/>
     </xs:complexType>
     <xs:complexType name="split-permission">
-        <xs:attribute name="name" type="xs:string"/>
-        <xs:attribute name="targetSdk" type="xs:int"/>
         <xs:sequence>
             <xs:element name="library" maxOccurs="unbounded">
                 <xs:complexType>
@@ -69,6 +67,8 @@
                 </xs:complexType>
             </xs:element>
         </xs:sequence>
+        <xs:attribute name="name" type="xs:string"/>
+        <xs:attribute name="targetSdk" type="xs:int"/>
     </xs:complexType>
     <xs:complexType name="library">
         <xs:attribute name="name" type="xs:string"/>
@@ -78,6 +78,7 @@
     <xs:complexType name="feature">
         <xs:attribute name="name" type="xs:string"/>
         <xs:attribute name="notLowRam" type="xs:string"/>
+        <xs:attribute name="version" type="xs:int"/>
     </xs:complexType>
     <xs:complexType name="unavailable-feature">
         <xs:attribute name="name" type="xs:string"/>
@@ -124,7 +125,6 @@
         <xs:attribute name="package" type="xs:string"/>
     </xs:complexType>
     <xs:complexType name="privapp-permissions">
-        <xs:attribute name="package" type="xs:string"/>
         <xs:sequence>
             <xs:element name="permission" maxOccurs="unbounded">
                 <xs:complexType>
@@ -137,9 +137,9 @@
                 </xs:complexType>
             </xs:element>
         </xs:sequence>
+        <xs:attribute name="package" type="xs:string"/>
     </xs:complexType>
     <xs:complexType name="oem-permissions">
-        <xs:attribute name="package" type="xs:string"/>
         <xs:sequence>
             <xs:element name="permission" maxOccurs="unbounded">
                 <xs:complexType>
@@ -152,6 +152,7 @@
                 </xs:complexType>
             </xs:element>
         </xs:sequence>
+        <xs:attribute name="package" type="xs:string"/>
     </xs:complexType>
     <xs:complexType name="hidden-api-whitelisted-app">
         <xs:attribute name="package" type="xs:string"/>
diff --git a/core/xsd/schema/current.txt b/core/xsd/schema/current.txt
index 82bb0fea..c25bc14 100644
--- a/core/xsd/schema/current.txt
+++ b/core/xsd/schema/current.txt
@@ -1,5 +1,5 @@
 // Signature format: 2.0
-package com.android.xml.permission {
+package com.android.xml.permission.configfile {
 
   public class AllowAssociation {
     ctor public AllowAssociation();
@@ -97,8 +97,10 @@
     ctor public Feature();
     method public String getName();
     method public String getNotLowRam();
+    method public int getVersion();
     method public void setName(String);
     method public void setNotLowRam(String);
+    method public void setVersion(int);
   }
 
   public class Group {
@@ -125,8 +127,8 @@
 
   public class OemPermissions {
     ctor public OemPermissions();
-    method public java.util.List<com.android.xml.permission.OemPermissions.DenyPermission> getDenyPermission();
-    method public java.util.List<com.android.xml.permission.OemPermissions.Permission> getPermission();
+    method public java.util.List<com.android.xml.permission.configfile.OemPermissions.DenyPermission> getDenyPermission();
+    method public java.util.List<com.android.xml.permission.configfile.OemPermissions.Permission> getPermission();
     method public String get_package();
     method public void set_package(String);
   }
@@ -151,37 +153,37 @@
 
   public class Permissions {
     ctor public Permissions();
-    method public java.util.List<com.android.xml.permission.AllowAssociation> getAllowAssociation();
-    method public java.util.List<com.android.xml.permission.AllowIgnoreLocationSettings> getAllowIgnoreLocationSettings();
-    method public java.util.List<com.android.xml.permission.AllowImplicitBroadcast> getAllowImplicitBroadcast();
-    method public java.util.List<com.android.xml.permission.AllowInDataUsageSave> getAllowInDataUsageSave();
-    method public java.util.List<com.android.xml.permission.AllowInPowerSave> getAllowInPowerSave();
-    method public java.util.List<com.android.xml.permission.AllowInPowerSaveExceptIdle> getAllowInPowerSaveExceptIdle();
-    method public java.util.List<com.android.xml.permission.AllowUnthrottledLocation> getAllowUnthrottledLocation();
-    method public java.util.List<com.android.xml.permission.AppLink> getAppLink();
-    method public java.util.List<com.android.xml.permission.AssignPermission> getAssignPermission();
-    method public java.util.List<com.android.xml.permission.BackupTransportWhitelistedService> getBackupTransportWhitelistedService();
-    method public java.util.List<com.android.xml.permission.BugreportWhitelisted> getBugreportWhitelisted();
-    method public java.util.List<com.android.xml.permission.DefaultEnabledVrApp> getDefaultEnabledVrApp();
-    method public java.util.List<com.android.xml.permission.DisabledUntilUsedPreinstalledCarrierApp> getDisabledUntilUsedPreinstalledCarrierApp();
-    method public java.util.List<com.android.xml.permission.DisabledUntilUsedPreinstalledCarrierAssociatedApp> getDisabledUntilUsedPreinstalledCarrierAssociatedApp();
-    method public java.util.List<com.android.xml.permission.Feature> getFeature();
-    method public java.util.List<com.android.xml.permission.Group> getGroup();
-    method public java.util.List<com.android.xml.permission.HiddenApiWhitelistedApp> getHiddenApiWhitelistedApp();
-    method public java.util.List<com.android.xml.permission.Library> getLibrary();
-    method public java.util.List<com.android.xml.permission.OemPermissions> getOemPermissions();
-    method public java.util.List<com.android.xml.permission.Permission> getPermission();
-    method public java.util.List<com.android.xml.permission.PrivappPermissions> getPrivappPermissions();
-    method public java.util.List<com.android.xml.permission.SplitPermission> getSplitPermission();
-    method public java.util.List<com.android.xml.permission.SystemUserBlacklistedApp> getSystemUserBlacklistedApp();
-    method public java.util.List<com.android.xml.permission.SystemUserWhitelistedApp> getSystemUserWhitelistedApp();
-    method public java.util.List<com.android.xml.permission.UnavailableFeature> getUnavailableFeature();
+    method public java.util.List<com.android.xml.permission.configfile.AllowAssociation> getAllowAssociation();
+    method public java.util.List<com.android.xml.permission.configfile.AllowIgnoreLocationSettings> getAllowIgnoreLocationSettings();
+    method public java.util.List<com.android.xml.permission.configfile.AllowImplicitBroadcast> getAllowImplicitBroadcast();
+    method public java.util.List<com.android.xml.permission.configfile.AllowInDataUsageSave> getAllowInDataUsageSave();
+    method public java.util.List<com.android.xml.permission.configfile.AllowInPowerSave> getAllowInPowerSave();
+    method public java.util.List<com.android.xml.permission.configfile.AllowInPowerSaveExceptIdle> getAllowInPowerSaveExceptIdle();
+    method public java.util.List<com.android.xml.permission.configfile.AllowUnthrottledLocation> getAllowUnthrottledLocation();
+    method public java.util.List<com.android.xml.permission.configfile.AppLink> getAppLink();
+    method public java.util.List<com.android.xml.permission.configfile.AssignPermission> getAssignPermission();
+    method public java.util.List<com.android.xml.permission.configfile.BackupTransportWhitelistedService> getBackupTransportWhitelistedService();
+    method public java.util.List<com.android.xml.permission.configfile.BugreportWhitelisted> getBugreportWhitelisted();
+    method public java.util.List<com.android.xml.permission.configfile.DefaultEnabledVrApp> getDefaultEnabledVrApp();
+    method public java.util.List<com.android.xml.permission.configfile.DisabledUntilUsedPreinstalledCarrierApp> getDisabledUntilUsedPreinstalledCarrierApp();
+    method public java.util.List<com.android.xml.permission.configfile.DisabledUntilUsedPreinstalledCarrierAssociatedApp> getDisabledUntilUsedPreinstalledCarrierAssociatedApp();
+    method public java.util.List<com.android.xml.permission.configfile.Feature> getFeature();
+    method public java.util.List<com.android.xml.permission.configfile.Group> getGroup();
+    method public java.util.List<com.android.xml.permission.configfile.HiddenApiWhitelistedApp> getHiddenApiWhitelistedApp();
+    method public java.util.List<com.android.xml.permission.configfile.Library> getLibrary();
+    method public java.util.List<com.android.xml.permission.configfile.OemPermissions> getOemPermissions();
+    method public java.util.List<com.android.xml.permission.configfile.Permission> getPermission();
+    method public java.util.List<com.android.xml.permission.configfile.PrivappPermissions> getPrivappPermissions();
+    method public java.util.List<com.android.xml.permission.configfile.SplitPermission> getSplitPermission();
+    method public java.util.List<com.android.xml.permission.configfile.SystemUserBlacklistedApp> getSystemUserBlacklistedApp();
+    method public java.util.List<com.android.xml.permission.configfile.SystemUserWhitelistedApp> getSystemUserWhitelistedApp();
+    method public java.util.List<com.android.xml.permission.configfile.UnavailableFeature> getUnavailableFeature();
   }
 
   public class PrivappPermissions {
     ctor public PrivappPermissions();
-    method public java.util.List<com.android.xml.permission.PrivappPermissions.DenyPermission> getDenyPermission();
-    method public java.util.List<com.android.xml.permission.PrivappPermissions.Permission> getPermission();
+    method public java.util.List<com.android.xml.permission.configfile.PrivappPermissions.DenyPermission> getDenyPermission();
+    method public java.util.List<com.android.xml.permission.configfile.PrivappPermissions.Permission> getPermission();
     method public String get_package();
     method public void set_package(String);
   }
@@ -200,7 +202,7 @@
 
   public class SplitPermission {
     ctor public SplitPermission();
-    method public java.util.List<com.android.xml.permission.SplitPermission.Library> getLibrary();
+    method public java.util.List<com.android.xml.permission.configfile.SplitPermission.Library> getLibrary();
     method public String getName();
     method public int getTargetSdk();
     method public void setName(String);
@@ -233,7 +235,7 @@
 
   public class XmlParser {
     ctor public XmlParser();
-    method public static com.android.xml.permission.Permissions read(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static com.android.xml.permission.configfile.Permissions read(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public static String readText(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public static void skip(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
   }
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 347edc5..3c8794f 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -271,7 +271,10 @@
         <permission name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
         <permission name="android.permission.MOVE_PACKAGE"/>
         <permission name="android.permission.OBSERVE_APP_USAGE"/>
+        <permission name="android.permission.NETWORK_SCAN"/>
         <permission name="android.permission.PACKAGE_USAGE_STATS" />
+        <!-- Needed for test only -->
+        <permission name="android.permission.PACKET_KEEPALIVE_OFFLOAD" />
         <permission name="android.permission.POWER_SAVER" />
         <permission name="android.permission.READ_FRAME_BUFFER"/>
         <permission name="android.permission.READ_LOWPAN_CREDENTIAL"/>
diff --git a/graphics/java/android/graphics/BaseCanvas.java b/graphics/java/android/graphics/BaseCanvas.java
index fd37735..c9431e3 100644
--- a/graphics/java/android/graphics/BaseCanvas.java
+++ b/graphics/java/android/graphics/BaseCanvas.java
@@ -112,14 +112,14 @@
     public void drawBitmap(@NonNull Bitmap bitmap, float left, float top, @Nullable Paint paint) {
         throwIfCannotDraw(bitmap);
         throwIfHasHwBitmapInSwMode(paint);
-        nDrawBitmap(mNativeCanvasWrapper, bitmap, left, top,
+        nDrawBitmap(mNativeCanvasWrapper, bitmap.getNativeInstance(), left, top,
                 paint != null ? paint.getNativeInstance() : 0, mDensity, mScreenDensity,
                 bitmap.mDensity);
     }
 
     public void drawBitmap(@NonNull Bitmap bitmap, @NonNull Matrix matrix, @Nullable Paint paint) {
         throwIfHasHwBitmapInSwMode(paint);
-        nDrawBitmapMatrix(mNativeCanvasWrapper, bitmap, matrix.ni(),
+        nDrawBitmapMatrix(mNativeCanvasWrapper, bitmap.getNativeInstance(), matrix.ni(),
                 paint != null ? paint.getNativeInstance() : 0);
     }
 
@@ -144,7 +144,7 @@
             bottom = src.bottom;
         }
 
-        nDrawBitmap(mNativeCanvasWrapper, bitmap, left, top, right, bottom,
+        nDrawBitmap(mNativeCanvasWrapper, bitmap.getNativeInstance(), left, top, right, bottom,
                 dst.left, dst.top, dst.right, dst.bottom, nativePaint, mScreenDensity,
                 bitmap.mDensity);
     }
@@ -170,7 +170,7 @@
             bottom = src.bottom;
         }
 
-        nDrawBitmap(mNativeCanvasWrapper, bitmap, left, top, right, bottom,
+        nDrawBitmap(mNativeCanvasWrapper, bitmap.getNativeInstance(), left, top, right, bottom,
                 dst.left, dst.top, dst.right, dst.bottom, nativePaint, mScreenDensity,
                 bitmap.mDensity);
     }
@@ -229,7 +229,7 @@
             // no mul by 2, since we need only 1 color per vertex
             checkRange(colors.length, colorOffset, count);
         }
-        nDrawBitmapMesh(mNativeCanvasWrapper, bitmap, meshWidth, meshHeight,
+        nDrawBitmapMesh(mNativeCanvasWrapper, bitmap.getNativeInstance(), meshWidth, meshHeight,
                 verts, vertOffset, colors, colorOffset,
                 paint != null ? paint.getNativeInstance() : 0);
     }
@@ -240,7 +240,7 @@
     }
 
     public void drawColor(@ColorInt int color) {
-        nDrawColor(mNativeCanvasWrapper, color, PorterDuff.Mode.SRC_OVER.nativeInt);
+        nDrawColor(mNativeCanvasWrapper, color, BlendMode.SRC_OVER.getXfermode().porterDuffMode);
     }
 
     /**
@@ -664,10 +664,11 @@
         }
     }
 
-    private static native void nDrawBitmap(long nativeCanvas, Bitmap bitmap, float left, float top,
-            long nativePaintOrZero, int canvasDensity, int screenDensity, int bitmapDensity);
+    private static native void nDrawBitmap(long nativeCanvas, long bitmapHandle, float left,
+            float top, long nativePaintOrZero, int canvasDensity, int screenDensity,
+            int bitmapDensity);
 
-    private static native void nDrawBitmap(long nativeCanvas, Bitmap bitmap, float srcLeft,
+    private static native void nDrawBitmap(long nativeCanvas, long bitmapHandle, float srcLeft,
             float srcTop,
             float srcRight, float srcBottom, float dstLeft, float dstTop, float dstRight,
             float dstBottom, long nativePaintOrZero, int screenDensity, int bitmapDensity);
@@ -726,10 +727,10 @@
             float dstLeft, float dstTop, float dstRight, float dstBottom, long nativePaintOrZero,
             int screenDensity, int bitmapDensity);
 
-    private static native void nDrawBitmapMatrix(long nativeCanvas, Bitmap bitmap,
+    private static native void nDrawBitmapMatrix(long nativeCanvas, long bitmapHandle,
             long nativeMatrix, long nativePaint);
 
-    private static native void nDrawBitmapMesh(long nativeCanvas, Bitmap bitmap, int meshWidth,
+    private static native void nDrawBitmapMesh(long nativeCanvas, long bitmapHandle, int meshWidth,
             int meshHeight, float[] verts, int vertOffset, int[] colors, int colorOffset,
             long nativePaint);
 
diff --git a/graphics/java/android/graphics/BaseRecordingCanvas.java b/graphics/java/android/graphics/BaseRecordingCanvas.java
index 3e11741..028b784 100644
--- a/graphics/java/android/graphics/BaseRecordingCanvas.java
+++ b/graphics/java/android/graphics/BaseRecordingCanvas.java
@@ -67,7 +67,7 @@
     public final void drawBitmap(@NonNull Bitmap bitmap, float left, float top,
             @Nullable Paint paint) {
         throwIfCannotDraw(bitmap);
-        nDrawBitmap(mNativeCanvasWrapper, bitmap, left, top,
+        nDrawBitmap(mNativeCanvasWrapper, bitmap.getNativeInstance(), left, top,
                 paint != null ? paint.getNativeInstance() : 0, mDensity, mScreenDensity,
                 bitmap.mDensity);
     }
@@ -75,7 +75,7 @@
     @Override
     public final void drawBitmap(@NonNull Bitmap bitmap, @NonNull Matrix matrix,
             @Nullable Paint paint) {
-        nDrawBitmapMatrix(mNativeCanvasWrapper, bitmap, matrix.ni(),
+        nDrawBitmapMatrix(mNativeCanvasWrapper, bitmap.getNativeInstance(), matrix.ni(),
                 paint != null ? paint.getNativeInstance() : 0);
     }
 
@@ -100,7 +100,7 @@
             bottom = src.bottom;
         }
 
-        nDrawBitmap(mNativeCanvasWrapper, bitmap, left, top, right, bottom,
+        nDrawBitmap(mNativeCanvasWrapper, bitmap.getNativeInstance(), left, top, right, bottom,
                 dst.left, dst.top, dst.right, dst.bottom, nativePaint, mScreenDensity,
                 bitmap.mDensity);
     }
@@ -126,7 +126,7 @@
             bottom = src.bottom;
         }
 
-        nDrawBitmap(mNativeCanvasWrapper, bitmap, left, top, right, bottom,
+        nDrawBitmap(mNativeCanvasWrapper, bitmap.getNativeInstance(), left, top, right, bottom,
                 dst.left, dst.top, dst.right, dst.bottom, nativePaint, mScreenDensity,
                 bitmap.mDensity);
     }
@@ -188,7 +188,7 @@
             // no mul by 2, since we need only 1 color per vertex
             checkRange(colors.length, colorOffset, count);
         }
-        nDrawBitmapMesh(mNativeCanvasWrapper, bitmap, meshWidth, meshHeight,
+        nDrawBitmapMesh(mNativeCanvasWrapper, bitmap.getNativeInstance(), meshWidth, meshHeight,
                 verts, vertOffset, colors, colorOffset,
                 paint != null ? paint.getNativeInstance() : 0);
     }
@@ -200,7 +200,7 @@
 
     @Override
     public final void drawColor(@ColorInt int color) {
-        nDrawColor(mNativeCanvasWrapper, color, PorterDuff.Mode.SRC_OVER.nativeInt);
+        nDrawColor(mNativeCanvasWrapper, color, BlendMode.SRC_OVER.getXfermode().porterDuffMode);
     }
 
     /**
@@ -581,11 +581,12 @@
     }
 
     @FastNative
-    private static native void nDrawBitmap(long nativeCanvas, Bitmap bitmap, float left, float top,
-            long nativePaintOrZero, int canvasDensity, int screenDensity, int bitmapDensity);
+    private static native void nDrawBitmap(long nativeCanvas, long bitmapHandle, float left,
+            float top, long nativePaintOrZero, int canvasDensity, int screenDensity,
+            int bitmapDensity);
 
     @FastNative
-    private static native void nDrawBitmap(long nativeCanvas, Bitmap bitmap,
+    private static native void nDrawBitmap(long nativeCanvas, long bitmapHandle,
             float srcLeft, float srcTop, float srcRight, float srcBottom,
             float dstLeft, float dstTop, float dstRight, float dstBottom,
             long nativePaintOrZero, int screenDensity, int bitmapDensity);
@@ -663,11 +664,11 @@
             int screenDensity, int bitmapDensity);
 
     @FastNative
-    private static native void nDrawBitmapMatrix(long nativeCanvas, Bitmap bitmap,
+    private static native void nDrawBitmapMatrix(long nativeCanvas, long bitmapHandle,
             long nativeMatrix, long nativePaint);
 
     @FastNative
-    private static native void nDrawBitmapMesh(long nativeCanvas, Bitmap bitmap, int meshWidth,
+    private static native void nDrawBitmapMesh(long nativeCanvas, long bitmapHandle, int meshWidth,
             int meshHeight, float[] verts, int vertOffset, int[] colors, int colorOffset,
             long nativePaint);
 
diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java
index 49c3a3b..5623a8a 100644
--- a/graphics/java/android/graphics/BitmapFactory.java
+++ b/graphics/java/android/graphics/BitmapFactory.java
@@ -436,9 +436,15 @@
         static void validate(Options opts) {
             if (opts == null) return;
 
-            if (opts.inBitmap != null && opts.inBitmap.getConfig() == Bitmap.Config.HARDWARE) {
-                throw new IllegalArgumentException(
-                        "Bitmaps with Config.HARDWARE are always immutable");
+            if (opts.inBitmap != null) {
+                if (opts.inBitmap.getConfig() == Bitmap.Config.HARDWARE) {
+                    throw new IllegalArgumentException(
+                            "Bitmaps with Config.HARDWARE are always immutable");
+                }
+                if (opts.inBitmap.isRecycled()) {
+                    throw new IllegalArgumentException(
+                            "Cannot reuse a recycled Bitmap");
+                }
             }
 
             if (opts.inMutable && opts.inPreferredConfig == Bitmap.Config.HARDWARE) {
@@ -459,6 +465,17 @@
         }
 
         /**
+         *  Helper for passing inBitmap's native pointer to native.
+         */
+        static long nativeInBitmap(Options opts) {
+            if (opts == null || opts.inBitmap == null) {
+                return 0;
+            }
+
+            return opts.inBitmap.getNativeInstance();
+        }
+
+        /**
          *  Helper for passing SkColorSpace pointer to native.
          *
          *  @throws IllegalArgumentException if the ColorSpace is not Rgb or does
@@ -646,6 +663,7 @@
         Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "decodeBitmap");
         try {
             bm = nativeDecodeByteArray(data, offset, length, opts,
+                    Options.nativeInBitmap(opts),
                     Options.nativeColorSpace(opts));
 
             if (bm == null && opts != null && opts.inBitmap != null) {
@@ -741,7 +759,8 @@
         try {
             if (is instanceof AssetManager.AssetInputStream) {
                 final long asset = ((AssetManager.AssetInputStream) is).getNativeAsset();
-                bm = nativeDecodeAsset(asset, outPadding, opts, Options.nativeColorSpace(opts));
+                bm = nativeDecodeAsset(asset, outPadding, opts, Options.nativeInBitmap(opts),
+                    Options.nativeColorSpace(opts));
             } else {
                 bm = decodeStreamInternal(is, outPadding, opts);
             }
@@ -769,6 +788,7 @@
         if (opts != null) tempStorage = opts.inTempStorage;
         if (tempStorage == null) tempStorage = new byte[DECODE_BUFFER_SIZE];
         return nativeDecodeStream(is, tempStorage, outPadding, opts,
+                Options.nativeInBitmap(opts),
                 Options.nativeColorSpace(opts));
     }
 
@@ -813,6 +833,7 @@
         try {
             if (nativeIsSeekable(fd)) {
                 bm = nativeDecodeFileDescriptor(fd, outPadding, opts,
+                        Options.nativeInBitmap(opts),
                         Options.nativeColorSpace(opts));
             } else {
                 FileInputStream fis = new FileInputStream(fd);
@@ -850,15 +871,15 @@
 
     @UnsupportedAppUsage
     private static native Bitmap nativeDecodeStream(InputStream is, byte[] storage,
-            Rect padding, Options opts, long colorSpaceHandle);
+            Rect padding, Options opts, long inBitmapHandle, long colorSpaceHandle);
     @UnsupportedAppUsage
     private static native Bitmap nativeDecodeFileDescriptor(FileDescriptor fd,
-            Rect padding, Options opts, long colorSpaceHandle);
+            Rect padding, Options opts, long inBitmapHandle, long colorSpaceHandle);
     @UnsupportedAppUsage
     private static native Bitmap nativeDecodeAsset(long nativeAsset, Rect padding, Options opts,
-            long colorSpaceHandle);
+            long inBitmapHandle, long colorSpaceHandle);
     @UnsupportedAppUsage
     private static native Bitmap nativeDecodeByteArray(byte[] data, int offset,
-            int length, Options opts, long colorSpaceHandle);
+            int length, Options opts, long inBitmapHandle, long colorSpaceHandle);
     private static native boolean nativeIsSeekable(FileDescriptor fd);
 }
diff --git a/graphics/java/android/graphics/BitmapRegionDecoder.java b/graphics/java/android/graphics/BitmapRegionDecoder.java
index 1410423..629d8c1 100644
--- a/graphics/java/android/graphics/BitmapRegionDecoder.java
+++ b/graphics/java/android/graphics/BitmapRegionDecoder.java
@@ -196,6 +196,7 @@
                 throw new IllegalArgumentException("rectangle is outside the image");
             return nativeDecodeRegion(mNativeBitmapRegionDecoder, rect.left, rect.top,
                     rect.right - rect.left, rect.bottom - rect.top, options,
+                    BitmapFactory.Options.nativeInBitmap(options),
                     BitmapFactory.Options.nativeColorSpace(options));
         }
     }
@@ -266,7 +267,8 @@
 
     private static native Bitmap nativeDecodeRegion(long lbm,
             int start_x, int start_y, int width, int height,
-            BitmapFactory.Options options, long colorSpaceHandle);
+            BitmapFactory.Options options, long inBitmapHandle,
+            long colorSpaceHandle);
     private static native int nativeGetWidth(long lbm);
     private static native int nativeGetHeight(long lbm);
     private static native void nativeClean(long lbm);
diff --git a/graphics/java/android/graphics/BitmapShader.java b/graphics/java/android/graphics/BitmapShader.java
index eb0f2e1..198d1e7 100644
--- a/graphics/java/android/graphics/BitmapShader.java
+++ b/graphics/java/android/graphics/BitmapShader.java
@@ -62,9 +62,9 @@
 
     @Override
     long createNativeInstance(long nativeMatrix) {
-        return nativeCreate(nativeMatrix, mBitmap, mTileX, mTileY);
+        return nativeCreate(nativeMatrix, mBitmap.getNativeInstance(), mTileX, mTileY);
     }
 
-    private static native long nativeCreate(long nativeMatrix, Bitmap bitmap,
+    private static native long nativeCreate(long nativeMatrix, long bitmapHandle,
             int shaderTileModeX, int shaderTileModeY);
 }
diff --git a/graphics/java/android/graphics/BlendMode.java b/graphics/java/android/graphics/BlendMode.java
index 39392c8..0b26704 100644
--- a/graphics/java/android/graphics/BlendMode.java
+++ b/graphics/java/android/graphics/BlendMode.java
@@ -454,6 +454,64 @@
         return null;
     }
 
+    /**
+     * @hide
+     */
+    public static int toValue(BlendMode mode) {
+        return mode.getXfermode().porterDuffMode;
+    }
+
+    /**
+     * @hide
+     */
+    public static @Nullable PorterDuff.Mode blendModeToPorterDuffMode(@Nullable BlendMode mode) {
+        if (mode != null) {
+            switch (mode) {
+                case CLEAR:
+                    return PorterDuff.Mode.CLEAR;
+                case SRC:
+                    return PorterDuff.Mode.SRC;
+                case DST:
+                    return PorterDuff.Mode.DST;
+                case SRC_OVER:
+                    return PorterDuff.Mode.SRC_OVER;
+                case DST_OVER:
+                    return PorterDuff.Mode.DST_OVER;
+                case SRC_IN:
+                    return PorterDuff.Mode.SRC_IN;
+                case DST_IN:
+                    return PorterDuff.Mode.DST_IN;
+                case SRC_OUT:
+                    return PorterDuff.Mode.SRC_OUT;
+                case DST_OUT:
+                    return PorterDuff.Mode.DST_OUT;
+                case SRC_ATOP:
+                    return PorterDuff.Mode.SRC_ATOP;
+                case DST_ATOP:
+                    return PorterDuff.Mode.DST_ATOP;
+                case XOR:
+                    return PorterDuff.Mode.XOR;
+                case DARKEN:
+                    return PorterDuff.Mode.DARKEN;
+                case LIGHTEN:
+                    return PorterDuff.Mode.LIGHTEN;
+                // b/73224934 PorterDuff Multiply maps to Skia Modulate
+                case MODULATE:
+                    return PorterDuff.Mode.MULTIPLY;
+                case SCREEN:
+                    return PorterDuff.Mode.SCREEN;
+                case PLUS:
+                    return PorterDuff.Mode.ADD;
+                case OVERLAY:
+                    return PorterDuff.Mode.OVERLAY;
+                default:
+                    return null;
+            }
+        } else {
+            return null;
+        }
+    }
+
     @NonNull
     private final Xfermode mXfermode;
 
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index df64204..6f00fc90 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -95,7 +95,7 @@
     public Canvas() {
         if (!isHardwareAccelerated()) {
             // 0 means no native bitmap
-            mNativeCanvasWrapper = nInitRaster(null);
+            mNativeCanvasWrapper = nInitRaster(0);
             mFinalizer = NoImagePreloadHolder.sRegistry.registerNativeAllocation(
                     this, mNativeCanvasWrapper);
         } else {
@@ -117,7 +117,7 @@
             throw new IllegalStateException("Immutable bitmap passed to Canvas constructor");
         }
         throwIfCannotDraw(bitmap);
-        mNativeCanvasWrapper = nInitRaster(bitmap);
+        mNativeCanvasWrapper = nInitRaster(bitmap.getNativeInstance());
         mFinalizer = NoImagePreloadHolder.sRegistry.registerNativeAllocation(
                 this, mNativeCanvasWrapper);
         mBitmap = bitmap;
@@ -185,7 +185,7 @@
         }
 
         if (bitmap == null) {
-            nSetBitmap(mNativeCanvasWrapper, null);
+            nSetBitmap(mNativeCanvasWrapper, 0);
             mDensity = Bitmap.DENSITY_NONE;
         } else {
             if (!bitmap.isMutable()) {
@@ -193,7 +193,7 @@
             }
             throwIfCannotDraw(bitmap);
 
-            nSetBitmap(mNativeCanvasWrapper, bitmap);
+            nSetBitmap(mNativeCanvasWrapper, bitmap.getNativeInstance());
             mDensity = bitmap.mDensity;
         }
 
@@ -1364,14 +1364,16 @@
 
     private static native void nFreeCaches();
     private static native void nFreeTextLayoutCaches();
-    private static native long nInitRaster(Bitmap bitmap);
     private static native long nGetNativeFinalizer();
     private static native void nSetCompatibilityVersion(int apiLevel);
 
     // ---------------- @FastNative -------------------
 
     @FastNative
-    private static native void nSetBitmap(long canvasHandle, Bitmap bitmap);
+    private static native long nInitRaster(long bitmapHandle);
+
+    @FastNative
+    private static native void nSetBitmap(long canvasHandle, long bitmapHandle);
 
     @FastNative
     private static native boolean nGetClipBounds(long nativeCanvas, Rect bounds);
diff --git a/graphics/java/android/graphics/ComposeShader.java b/graphics/java/android/graphics/ComposeShader.java
index 189e174..93ddb10 100644
--- a/graphics/java/android/graphics/ComposeShader.java
+++ b/graphics/java/android/graphics/ComposeShader.java
@@ -39,7 +39,10 @@
      * @param shaderB  The colors from this shader are seen as the "src" by the mode
      * @param mode     The mode that combines the colors from the two shaders. If mode
      *                 is null, then SRC_OVER is assumed.
+     *
+     * @deprecated use {@link #ComposeShader(Shader, Shader, BlendMode)} instead
     */
+    @Deprecated
     public ComposeShader(@NonNull Shader shaderA, @NonNull Shader shaderB, @NonNull Xfermode mode) {
         this(shaderA, shaderB, mode.porterDuffMode);
     }
@@ -52,12 +55,29 @@
      * @param shaderA  The colors from this shader are seen as the "dst" by the mode
      * @param shaderB  The colors from this shader are seen as the "src" by the mode
      * @param mode     The PorterDuff mode that combines the colors from the two shaders.
-    */
+     *
+     * @deprecated use {@link #ComposeShader(Shader, Shader, BlendMode)} instead
+     */
+    @Deprecated
     public ComposeShader(@NonNull Shader shaderA, @NonNull Shader shaderB,
             @NonNull PorterDuff.Mode mode) {
         this(shaderA, shaderB, mode.nativeInt);
     }
 
+    /**
+     * Create a new compose shader, given shaders A, B, and a combining PorterDuff mode.
+     * When the mode is applied, it will be given the result from shader A as its
+     * "dst", and the result from shader B as its "src".
+     *
+     * @param shaderA  The colors from this shader are seen as the "dst" by the mode
+     * @param shaderB  The colors from this shader are seen as the "src" by the mode
+     * @param blendMode The blend mode that combines the colors from the two shaders.
+    */
+    public ComposeShader(@NonNull Shader shaderA, @NonNull Shader shaderB,
+            @NonNull BlendMode blendMode) {
+        this(shaderA, shaderB, blendMode.getXfermode().porterDuffMode);
+    }
+
     private ComposeShader(Shader shaderA, Shader shaderB, int nativeMode) {
         if (shaderA == null || shaderB == null) {
             throw new IllegalArgumentException("Shader parameters must not be null");
diff --git a/graphics/java/android/graphics/HardwareRenderer.java b/graphics/java/android/graphics/HardwareRenderer.java
index bc744cc..b6b2d4e 100644
--- a/graphics/java/android/graphics/HardwareRenderer.java
+++ b/graphics/java/android/graphics/HardwareRenderer.java
@@ -682,8 +682,8 @@
 
     /** @hide */
     public boolean copyLayerInto(final TextureLayer layer, final Bitmap bitmap) {
-        return nCopyLayerInto(mNativeProxy,
-                layer.getDeferredLayerUpdater(), bitmap);
+        return nCopyLayerInto(mNativeProxy, layer.getDeferredLayerUpdater(),
+            bitmap.getNativeInstance());
     }
 
     /**
@@ -910,10 +910,10 @@
     public static int copySurfaceInto(Surface surface, Rect srcRect, Bitmap bitmap) {
         if (srcRect == null) {
             // Empty rect means entire surface
-            return nCopySurfaceInto(surface, 0, 0, 0, 0, bitmap);
+            return nCopySurfaceInto(surface, 0, 0, 0, 0, bitmap.getNativeInstance());
         } else {
             return nCopySurfaceInto(surface, srcRect.left, srcRect.top,
-                    srcRect.right, srcRect.bottom, bitmap);
+                    srcRect.right, srcRect.bottom, bitmap.getNativeInstance());
         }
     }
 
@@ -1115,7 +1115,7 @@
 
     private static native void nBuildLayer(long nativeProxy, long node);
 
-    private static native boolean nCopyLayerInto(long nativeProxy, long layer, Bitmap bitmap);
+    private static native boolean nCopyLayerInto(long nativeProxy, long layer, long bitmapHandle);
 
     private static native void nPushLayerUpdate(long nativeProxy, long layer);
 
@@ -1162,7 +1162,7 @@
     private static native void nRemoveFrameMetricsObserver(long nativeProxy, long nativeObserver);
 
     private static native int nCopySurfaceInto(Surface surface,
-            int srcLeft, int srcTop, int srcRight, int srcBottom, Bitmap bitmap);
+            int srcLeft, int srcTop, int srcRight, int srcBottom, long bitmapHandle);
 
     private static native Bitmap nCreateHardwareBitmap(long renderNode, int width, int height);
 
diff --git a/graphics/java/android/graphics/NinePatch.java b/graphics/java/android/graphics/NinePatch.java
index 800247a..c4c1eac 100644
--- a/graphics/java/android/graphics/NinePatch.java
+++ b/graphics/java/android/graphics/NinePatch.java
@@ -261,7 +261,8 @@
      * that are transparent.
      */
     public final Region getTransparentRegion(Rect bounds) {
-        long r = nativeGetTransparentRegion(mBitmap, mNativeChunk, bounds);
+        long r = nativeGetTransparentRegion(mBitmap.getNativeInstance(),
+                mNativeChunk, bounds);
         return r != 0 ? new Region(r) : null;
     }
 
@@ -282,5 +283,6 @@
      */
     private static native long validateNinePatchChunk(byte[] chunk);
     private static native void nativeFinalize(long chunk);
-    private static native long nativeGetTransparentRegion(Bitmap bitmap, long chunk, Rect location);
+    private static native long nativeGetTransparentRegion(long bitmapHandle, long chunk,
+        Rect location);
 }
diff --git a/graphics/java/android/graphics/PorterDuff.java b/graphics/java/android/graphics/PorterDuff.java
index fba5043..459291b 100644
--- a/graphics/java/android/graphics/PorterDuff.java
+++ b/graphics/java/android/graphics/PorterDuff.java
@@ -23,7 +23,10 @@
  * that can be passed to {@link PorterDuffXfermode}, a specialized implementation
  * of {@link Paint}'s {@link Paint#setXfermode(Xfermode) transfer mode}.
  * All the available modes can be found in the {@link Mode} enum.</p>
+ *
+ * @deprecated Use {@link BlendMode} with {@link Paint#setBlendMode(BlendMode)} instead
  */
+@Deprecated
 public class PorterDuff {
     /**
      * {@usesMathJax}
diff --git a/graphics/java/android/graphics/PorterDuffXfermode.java b/graphics/java/android/graphics/PorterDuffXfermode.java
index 84d953d..5b933c4 100644
--- a/graphics/java/android/graphics/PorterDuffXfermode.java
+++ b/graphics/java/android/graphics/PorterDuffXfermode.java
@@ -21,6 +21,11 @@
  * {@link Paint#setXfermode(Xfermode) transfer mode}. Refer to the
  * documentation of the {@link PorterDuff.Mode} enum for more
  * information on the available alpha compositing and blending modes.</p>
+ *
+ *  @deprecated Consider using {@link BlendMode} instead as it supports a wider
+ * set of blend modes than those defined in {@link PorterDuff.Mode}
+ *
+ * @see Paint#setBlendMode(BlendMode)
  */
 public class PorterDuffXfermode extends Xfermode {
     /**
diff --git a/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java b/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java
index cb12a7c..7def322 100644
--- a/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java
+++ b/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java
@@ -27,6 +27,7 @@
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
 import android.graphics.BitmapShader;
+import android.graphics.BlendMode;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.ColorFilter;
@@ -35,7 +36,6 @@
 import android.graphics.Paint;
 import android.graphics.Path;
 import android.graphics.PixelFormat;
-import android.graphics.PorterDuff.Mode;
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.graphics.Shader;
@@ -701,13 +701,13 @@
     }
 
     @Override
-    public void setTintMode(Mode tintMode) {
+    public void setTintMode(@NonNull BlendMode blendMode) {
         final ChildDrawable[] array = mLayerState.mChildren;
         final int N = mLayerState.N_CHILDREN;
         for (int i = 0; i < N; i++) {
             final Drawable dr = array[i].mDrawable;
             if (dr != null) {
-                dr.setTintMode(tintMode);
+                dr.setTintMode(blendMode);
             }
         }
     }
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index d9dab98..f45bf9b 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -33,12 +33,12 @@
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
 import android.content.res.TypedArray;
+import android.graphics.BlendMode;
 import android.graphics.Canvas;
 import android.graphics.ColorFilter;
 import android.graphics.Insets;
 import android.graphics.Outline;
 import android.graphics.PixelFormat;
-import android.graphics.PorterDuff;
 import android.graphics.RecordingCanvas;
 import android.graphics.Rect;
 import android.graphics.RenderNode;
@@ -477,8 +477,8 @@
     }
 
     @Override
-    public void setTintMode(PorterDuff.Mode tintMode) {
-        mAnimatedVectorState.mVectorDrawable.setTintMode(tintMode);
+    public void setTintMode(@NonNull BlendMode blendMode) {
+        mAnimatedVectorState.mVectorDrawable.setTintMode(blendMode);
     }
 
     @Override
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index 9761901..6b30158 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -25,6 +25,8 @@
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
 import android.graphics.BitmapShader;
+import android.graphics.BlendMode;
+import android.graphics.BlendModeColorFilter;
 import android.graphics.Canvas;
 import android.graphics.ColorFilter;
 import android.graphics.ImageDecoder;
@@ -33,9 +35,7 @@
 import android.graphics.Outline;
 import android.graphics.Paint;
 import android.graphics.PixelFormat;
-import android.graphics.PorterDuff;
 import android.graphics.PorterDuff.Mode;
-import android.graphics.PorterDuffColorFilter;
 import android.graphics.Rect;
 import android.graphics.Shader;
 import android.graphics.Xfermode;
@@ -90,7 +90,7 @@
 
     @UnsupportedAppUsage
     private BitmapState mBitmapState;
-    private PorterDuffColorFilter mTintFilter;
+    private BlendModeColorFilter mBlendModeFilter;
 
     @UnsupportedAppUsage
     private int mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
@@ -527,8 +527,8 @@
         }
 
         final boolean clearColorFilter;
-        if (mTintFilter != null && paint.getColorFilter() == null) {
-            paint.setColorFilter(mTintFilter);
+        if (mBlendModeFilter != null && paint.getColorFilter() == null) {
+            paint.setColorFilter(mBlendModeFilter);
             clearColorFilter = true;
         } else {
             clearColorFilter = false;
@@ -678,17 +678,19 @@
         final BitmapState state = mBitmapState;
         if (state.mTint != tint) {
             state.mTint = tint;
-            mTintFilter = updateTintFilter(mTintFilter, tint, mBitmapState.mTintMode);
+            mBlendModeFilter = updateBlendModeFilter(mBlendModeFilter, tint,
+                      mBitmapState.mBlendMode);
             invalidateSelf();
         }
     }
 
     @Override
-    public void setTintMode(PorterDuff.Mode tintMode) {
+    public void setTintMode(@NonNull BlendMode blendMode) {
         final BitmapState state = mBitmapState;
-        if (state.mTintMode != tintMode) {
-            state.mTintMode = tintMode;
-            mTintFilter = updateTintFilter(mTintFilter, mBitmapState.mTint, tintMode);
+        if (state.mBlendMode != blendMode) {
+            state.mBlendMode = blendMode;
+            mBlendModeFilter = updateBlendModeFilter(mBlendModeFilter, mBitmapState.mTint,
+                    blendMode);
             invalidateSelf();
         }
     }
@@ -706,7 +708,7 @@
      */
     @UnsupportedAppUsage
     public Mode getTintMode() {
-        return mBitmapState.mTintMode;
+        return BlendMode.blendModeToPorterDuffMode(mBitmapState.mBlendMode);
     }
 
     /**
@@ -744,8 +746,9 @@
     @Override
     protected boolean onStateChange(int[] stateSet) {
         final BitmapState state = mBitmapState;
-        if (state.mTint != null && state.mTintMode != null) {
-            mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
+        if (state.mTint != null && state.mBlendMode != null) {
+            mBlendModeFilter = updateBlendModeFilter(mBlendModeFilter, state.mTint,
+                    state.mBlendMode);
             return true;
         }
         return false;
@@ -864,7 +867,7 @@
 
         final int tintMode = a.getInt(R.styleable.BitmapDrawable_tintMode, -1);
         if (tintMode != -1) {
-            state.mTintMode = Drawable.parseTintMode(tintMode, Mode.SRC_IN);
+            state.mBlendMode = Drawable.parseBlendMode(tintMode, BlendMode.SRC_IN);
         }
 
         final ColorStateList tint = a.getColorStateList(R.styleable.BitmapDrawable_tint);
@@ -979,7 +982,8 @@
         int[] mThemeAttrs = null;
         Bitmap mBitmap = null;
         ColorStateList mTint = null;
-        Mode mTintMode = DEFAULT_TINT_MODE;
+        BlendMode mBlendMode = DEFAULT_BLEND_MODE;
+
         int mGravity = Gravity.FILL;
         float mBaseAlpha = 1.0f;
         Shader.TileMode mTileModeX = null;
@@ -1005,7 +1009,7 @@
         BitmapState(BitmapState bitmapState) {
             mBitmap = bitmapState.mBitmap;
             mTint = bitmapState.mTint;
-            mTintMode = bitmapState.mTintMode;
+            mBlendMode = bitmapState.mBlendMode;
             mThemeAttrs = bitmapState.mThemeAttrs;
             mChangingConfigurations = bitmapState.mChangingConfigurations;
             mGravity = bitmapState.mGravity;
@@ -1065,7 +1069,8 @@
      */
     private void updateLocalState(Resources res) {
         mTargetDensity = resolveDensity(res, mBitmapState.mTargetDensity);
-        mTintFilter = updateTintFilter(mTintFilter, mBitmapState.mTint, mBitmapState.mTintMode);
+        mBlendModeFilter = updateBlendModeFilter(mBlendModeFilter, mBitmapState.mTint,
+                mBitmapState.mBlendMode);
         computeBitmapSize();
     }
 }
diff --git a/graphics/java/android/graphics/drawable/ColorDrawable.java b/graphics/java/android/graphics/drawable/ColorDrawable.java
index 3c44916..efa806a 100644
--- a/graphics/java/android/graphics/drawable/ColorDrawable.java
+++ b/graphics/java/android/graphics/drawable/ColorDrawable.java
@@ -26,13 +26,13 @@
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
 import android.content.res.TypedArray;
+import android.graphics.BlendMode;
+import android.graphics.BlendModeColorFilter;
 import android.graphics.Canvas;
 import android.graphics.ColorFilter;
 import android.graphics.Outline;
 import android.graphics.Paint;
 import android.graphics.PixelFormat;
-import android.graphics.PorterDuff.Mode;
-import android.graphics.PorterDuffColorFilter;
 import android.graphics.Xfermode;
 import android.util.AttributeSet;
 import android.view.ViewDebug;
@@ -58,7 +58,7 @@
 
     @ViewDebug.ExportedProperty(deepExport = true, prefix = "state_")
     private ColorState mColorState;
-    private PorterDuffColorFilter mTintFilter;
+    private BlendModeColorFilter mBlendModeColorFilter;
 
     private boolean mMutated;
 
@@ -111,9 +111,10 @@
     @Override
     public void draw(Canvas canvas) {
         final ColorFilter colorFilter = mPaint.getColorFilter();
-        if ((mColorState.mUseColor >>> 24) != 0 || colorFilter != null || mTintFilter != null) {
+        if ((mColorState.mUseColor >>> 24) != 0 || colorFilter != null
+                || mBlendModeColorFilter != null) {
             if (colorFilter == null) {
-                mPaint.setColorFilter(mTintFilter);
+                mPaint.setColorFilter(mBlendModeColorFilter);
             }
 
             mPaint.setColor(mColorState.mUseColor);
@@ -208,22 +209,25 @@
     @Override
     public void setTintList(ColorStateList tint) {
         mColorState.mTint = tint;
-        mTintFilter = updateTintFilter(mTintFilter, tint, mColorState.mTintMode);
+        mBlendModeColorFilter = updateBlendModeFilter(mBlendModeColorFilter, tint,
+                mColorState.mBlendMode);
         invalidateSelf();
     }
 
     @Override
-    public void setTintMode(Mode tintMode) {
-        mColorState.mTintMode = tintMode;
-        mTintFilter = updateTintFilter(mTintFilter, mColorState.mTint, tintMode);
+    public void setTintMode(@NonNull BlendMode blendMode) {
+        mColorState.mBlendMode = blendMode;
+        mBlendModeColorFilter = updateBlendModeFilter(mBlendModeColorFilter, mColorState.mTint,
+                blendMode);
         invalidateSelf();
     }
 
     @Override
     protected boolean onStateChange(int[] stateSet) {
         final ColorState state = mColorState;
-        if (state.mTint != null && state.mTintMode != null) {
-            mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
+        if (state.mTint != null && state.mBlendMode != null) {
+            mBlendModeColorFilter = updateBlendModeFilter(mBlendModeColorFilter, state.mTint,
+                    state.mBlendMode);
             return true;
         }
         return false;
@@ -261,7 +265,7 @@
 
     @Override
     public int getOpacity() {
-        if (mTintFilter != null || mPaint.getColorFilter() != null) {
+        if (mBlendModeColorFilter != null || mPaint.getColorFilter() != null) {
             return PixelFormat.TRANSLUCENT;
         }
 
@@ -348,7 +352,7 @@
         int mUseColor;  // basecolor modulated by setAlpha()
         @Config int mChangingConfigurations;
         ColorStateList mTint = null;
-        Mode mTintMode = DEFAULT_TINT_MODE;
+        BlendMode mBlendMode = DEFAULT_BLEND_MODE;
 
         ColorState() {
             // Empty constructor.
@@ -360,7 +364,7 @@
             mUseColor = state.mUseColor;
             mChangingConfigurations = state.mChangingConfigurations;
             mTint = state.mTint;
-            mTintMode = state.mTintMode;
+            mBlendMode = state.mBlendMode;
         }
 
         @Override
@@ -398,6 +402,7 @@
      * after inflating or applying a theme.
      */
     private void updateLocalState(Resources r) {
-        mTintFilter = updateTintFilter(mTintFilter, mColorState.mTint, mColorState.mTintMode);
+        mBlendModeColorFilter = updateBlendModeFilter(mBlendModeColorFilter, mColorState.mTint,
+                mColorState.mBlendMode);
     }
 }
diff --git a/graphics/java/android/graphics/drawable/ColorStateListDrawable.java b/graphics/java/android/graphics/drawable/ColorStateListDrawable.java
index ee4d1e7..b94b114 100644
--- a/graphics/java/android/graphics/drawable/ColorStateListDrawable.java
+++ b/graphics/java/android/graphics/drawable/ColorStateListDrawable.java
@@ -21,10 +21,10 @@
 import android.content.pm.ActivityInfo;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
+import android.graphics.BlendMode;
 import android.graphics.Canvas;
 import android.graphics.ColorFilter;
 import android.graphics.PixelFormat;
-import android.graphics.PorterDuff;
 import android.util.MathUtils;
 
 /**
@@ -114,9 +114,9 @@
     }
 
     @Override
-    public void setTintMode(@NonNull PorterDuff.Mode tintMode) {
-        mState.mTintMode = tintMode;
-        mColorDrawable.setTintMode(tintMode);
+    public void setTintMode(@NonNull BlendMode blendMode) {
+        mState.mBlendMode = blendMode;
+        mColorDrawable.setTintMode(blendMode);
         onStateChange(getState());
     }
 
@@ -236,7 +236,7 @@
         ColorStateList mColor = null;
         ColorStateList mTint = null;
         int mAlpha = -1;
-        PorterDuff.Mode mTintMode = DEFAULT_TINT_MODE;
+        BlendMode mBlendMode = DEFAULT_BLEND_MODE;
         @ActivityInfo.Config int mChangingConfigurations = 0;
 
         ColorStateListDrawableState() {
@@ -246,7 +246,7 @@
             mColor = state.mColor;
             mTint = state.mTint;
             mAlpha = state.mAlpha;
-            mTintMode = state.mTintMode;
+            mBlendMode = state.mBlendMode;
             mChangingConfigurations = state.mChangingConfigurations;
         }
 
@@ -292,8 +292,8 @@
             mColorDrawable.setTintList(mState.mTint);
         }
 
-        if (mState.mTintMode != DEFAULT_TINT_MODE) {
-            mColorDrawable.setTintMode(mState.mTintMode);
+        if (mState.mBlendMode != DEFAULT_BLEND_MODE) {
+            mColorDrawable.setTintMode(mState.mBlendMode);
         }
     }
 }
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 49d3530..e4142a9 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -30,6 +30,8 @@
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
+import android.graphics.BlendMode;
+import android.graphics.BlendModeColorFilter;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.ColorFilter;
@@ -182,6 +184,7 @@
     private static final Rect ZERO_BOUNDS_RECT = new Rect();
 
     static final PorterDuff.Mode DEFAULT_TINT_MODE = PorterDuff.Mode.SRC_IN;
+    static final BlendMode DEFAULT_BLEND_MODE = BlendMode.SRC_IN;
 
     private int[] mStateSet = StateSet.WILD_CARD;
     private int mLevel = 0;
@@ -210,6 +213,24 @@
     protected int mSrcDensityOverride = 0;
 
     /**
+     * Flag used to break the recursive loop between setTintMode(PorterDuff.Mode) and
+     * setTintMode(BlendMode) as each default implementation invokes the other in order to
+     * support new use cases that utilize the new blending modes as well as support the legacy
+     * use cases. This flag tracks that {@link #setTintMode(BlendMode)} is only invoked once
+     * per invocation.
+     */
+    private boolean mSetBlendModeInvoked = false;
+
+    /**
+     * Flag used to break the recursive loop between setTintMode(PorterDuff.Mode) and
+     * setTintMode(BlendMode) as each default implementation invokes the other in order to
+     * support new use cases that utilize the new blending modes as well as support the legacy
+     * use cases. This flag tracks that {@link #setTintMode(Mode)} is only invoked once
+     * per invocation;
+     */
+    private boolean mSetTintModeInvoked = false;
+
+    /**
      * Draw in its bounds (set via setBounds) respecting optional effects such
      * as alpha (set via setAlpha) and color filter (set via setColorFilter).
      *
@@ -630,6 +651,7 @@
      * @param tintColor Color to use for tinting this drawable
      * @see #setTintList(ColorStateList)
      * @see #setTintMode(PorterDuff.Mode)
+     * @see #setTintMode(BlendMode)
      */
     public void setTint(@ColorInt int tintColor) {
         setTintList(ColorStateList.valueOf(tintColor));
@@ -651,6 +673,7 @@
      *            {@code null} to clear the tint
      * @see #setTint(int)
      * @see #setTintMode(PorterDuff.Mode)
+     * @see #setTintMode(BlendMode)
      */
     public void setTintList(@Nullable ColorStateList tint) {}
 
@@ -668,8 +691,45 @@
      * @param tintMode A Porter-Duff blending mode
      * @see #setTint(int)
      * @see #setTintList(ColorStateList)
+     *
+     * @deprecated use {@link #setTintMode(BlendMode)} instead
      */
-    public void setTintMode(@NonNull PorterDuff.Mode tintMode) {}
+    @Deprecated
+    public void setTintMode(@NonNull PorterDuff.Mode tintMode) {
+        if (!mSetTintModeInvoked) {
+            mSetTintModeInvoked = true;
+            BlendMode mode = BlendMode.fromValue(tintMode.nativeInt);
+            if (mode != null) {
+                setTintMode(mode);
+            }
+            mSetTintModeInvoked = false;
+        }
+    }
+
+    /**
+     * Specifies a tint blending mode for this drawable.
+     * <p>
+     * Defines how this drawable's tint color should be blended into the drawable
+     * before it is drawn to screen. Default tint mode is {@link BlendMode#SRC_IN}.
+     * </p>
+     * <p class="note"><strong>Note:</strong> Setting a color filter via
+     * {@link #setColorFilter(ColorFilter)}
+     * </p>
+     *
+     * @param blendMode
+     * @see #setTint(int)
+     * @see #setTintList(ColorStateList)
+     */
+    public void setTintMode(@NonNull BlendMode blendMode) {
+        if (!mSetBlendModeInvoked) {
+            mSetBlendModeInvoked = true;
+            PorterDuff.Mode mode = BlendMode.blendModeToPorterDuffMode(blendMode);
+            if (mode != null) {
+                setTintMode(mode);
+            }
+            mSetBlendModeInvoked = false;
+        }
+    }
 
     /**
      * Returns the current color filter, or {@code null} if none set.
@@ -1540,6 +1600,20 @@
         return tintFilter;
     }
 
+    @Nullable BlendModeColorFilter updateBlendModeFilter(@Nullable BlendModeColorFilter blendFilter,
+            @Nullable ColorStateList tint, @Nullable BlendMode blendMode) {
+        if (tint == null || blendMode == null) {
+            return null;
+        }
+
+        final int color = tint.getColorForState(getState(), Color.TRANSPARENT);
+        if (blendFilter == null || blendFilter.getColor() != color
+                || blendFilter.getMode() != blendMode) {
+            return new BlendModeColorFilter(color, blendMode);
+        }
+        return blendFilter;
+    }
+
     /**
      * Obtains styled attributes from the theme, if available, or unstyled
      * resources if the theme is null.
@@ -1642,5 +1716,26 @@
             default: return defaultMode;
         }
     }
+
+    /**
+     * Parses a {@link android.graphics.BlendMode} from a tintMode
+     * attribute's enum value.
+     *
+     * @hide
+     */
+    @UnsupportedAppUsage
+    public static BlendMode parseBlendMode(int value, BlendMode defaultMode) {
+        switch (value) {
+            case 3: return BlendMode.SRC_OVER;
+            case 5: return BlendMode.SRC_IN;
+            case 9: return BlendMode.SRC_ATOP;
+            // b/73224934 PorterDuff Multiply maps to Skia Modulate so actually
+            // return BlendMode.MODULATE here
+            case 14: return BlendMode.MODULATE;
+            case 15: return BlendMode.SCREEN;
+            case 16: return BlendMode.PLUS;
+            default: return defaultMode;
+        }
+    }
 }
 
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index 77e77c4..3e0881a 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -22,12 +22,12 @@
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
+import android.graphics.BlendMode;
 import android.graphics.Canvas;
 import android.graphics.ColorFilter;
 import android.graphics.Insets;
 import android.graphics.Outline;
 import android.graphics.PixelFormat;
-import android.graphics.PorterDuff.Mode;
 import android.graphics.Rect;
 import android.os.Build;
 import android.os.SystemClock;
@@ -196,14 +196,14 @@
     }
 
     @Override
-    public void setTintMode(Mode tintMode) {
+    public void setTintMode(@NonNull BlendMode blendMode) {
         mDrawableContainerState.mHasTintMode = true;
 
-        if (mDrawableContainerState.mTintMode != tintMode) {
-            mDrawableContainerState.mTintMode = tintMode;
+        if (mDrawableContainerState.mBlendMode != blendMode) {
+            mDrawableContainerState.mBlendMode = blendMode;
 
             if (mCurrDrawable != null) {
-                mCurrDrawable.setTintMode(tintMode);
+                mCurrDrawable.setTintMode(blendMode);
             }
         }
     }
@@ -544,7 +544,7 @@
                     d.setTintList(mDrawableContainerState.mTintList);
                 }
                 if (mDrawableContainerState.mHasTintMode) {
-                    d.setTintMode(mDrawableContainerState.mTintMode);
+                    d.setTintMode(mDrawableContainerState.mBlendMode);
                 }
             }
 
@@ -730,7 +730,7 @@
         boolean mHasColorFilter;
 
         ColorStateList mTintList;
-        Mode mTintMode;
+        BlendMode mBlendMode;
         boolean mHasTintList;
         boolean mHasTintMode;
 
@@ -762,7 +762,7 @@
                 mColorFilter = orig.mColorFilter;
                 mHasColorFilter = orig.mHasColorFilter;
                 mTintList = orig.mTintList;
-                mTintMode = orig.mTintMode;
+                mBlendMode = orig.mBlendMode;
                 mHasTintList = orig.mHasTintList;
                 mHasTintMode = orig.mHasTintMode;
 
diff --git a/graphics/java/android/graphics/drawable/DrawableWrapper.java b/graphics/java/android/graphics/drawable/DrawableWrapper.java
index 70c90eb..d81401d 100644
--- a/graphics/java/android/graphics/drawable/DrawableWrapper.java
+++ b/graphics/java/android/graphics/drawable/DrawableWrapper.java
@@ -24,12 +24,12 @@
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
 import android.content.res.TypedArray;
+import android.graphics.BlendMode;
 import android.graphics.Canvas;
 import android.graphics.ColorFilter;
 import android.graphics.Insets;
 import android.graphics.Outline;
 import android.graphics.PixelFormat;
-import android.graphics.PorterDuff;
 import android.graphics.Rect;
 import android.graphics.Xfermode;
 import android.util.AttributeSet;
@@ -324,9 +324,9 @@
     }
 
     @Override
-    public void setTintMode(@Nullable PorterDuff.Mode tintMode) {
+    public void setTintMode(@NonNull BlendMode blendMode) {
         if (mDrawable != null) {
-            mDrawable.setTintMode(tintMode);
+            mDrawable.setTintMode(blendMode);
         }
     }
 
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index e58e802..6948bc4 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -28,6 +28,8 @@
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
 import android.content.res.TypedArray;
+import android.graphics.BlendMode;
+import android.graphics.BlendModeColorFilter;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.ColorFilter;
@@ -38,8 +40,6 @@
 import android.graphics.Paint;
 import android.graphics.Path;
 import android.graphics.PixelFormat;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuffColorFilter;
 import android.graphics.RadialGradient;
 import android.graphics.Rect;
 import android.graphics.RectF;
@@ -169,7 +169,7 @@
     @UnsupportedAppUsage
     private Paint mStrokePaint;   // optional, set by the caller
     private ColorFilter mColorFilter;   // optional, set by the caller
-    private PorterDuffColorFilter mTintFilter;
+    private BlendModeColorFilter mBlendModeColorFilter;
     private int mAlpha = 0xFF;  // modified by the caller
 
     private final Path mPath = new Path();
@@ -731,7 +731,7 @@
                 mStrokePaint.getStrokeWidth() > 0;
         final boolean haveFill = currFillAlpha > 0;
         final GradientState st = mGradientState;
-        final ColorFilter colorFilter = mColorFilter != null ? mColorFilter : mTintFilter;
+        final ColorFilter colorFilter = mColorFilter != null ? mColorFilter : mBlendModeColorFilter;
 
         /*  we need a layer iff we're drawing both a fill and stroke, and the
             stroke is non-opaque, and our shapetype actually supports
@@ -1130,8 +1130,9 @@
             }
         }
 
-        if (s.mTint != null && s.mTintMode != null) {
-            mTintFilter = updateTintFilter(mTintFilter, s.mTint, s.mTintMode);
+        if (s.mTint != null && s.mBlendMode != null) {
+            mBlendModeColorFilter = updateBlendModeFilter(mBlendModeColorFilter, s.mTint,
+                    s.mBlendMode);
             invalidateSelf = true;
         }
 
@@ -1204,14 +1205,16 @@
     @Override
     public void setTintList(@Nullable ColorStateList tint) {
         mGradientState.mTint = tint;
-        mTintFilter = updateTintFilter(mTintFilter, tint, mGradientState.mTintMode);
+        mBlendModeColorFilter =
+                updateBlendModeFilter(mBlendModeColorFilter, tint, mGradientState.mBlendMode);
         invalidateSelf();
     }
 
     @Override
-    public void setTintMode(@Nullable PorterDuff.Mode tintMode) {
-        mGradientState.mTintMode = tintMode;
-        mTintFilter = updateTintFilter(mTintFilter, mGradientState.mTint, tintMode);
+    public void setTintMode(@NonNull BlendMode blendMode) {
+        mGradientState.mBlendMode = blendMode;
+        mBlendModeColorFilter = updateBlendModeFilter(mBlendModeColorFilter, mGradientState.mTint,
+                blendMode);
         invalidateSelf();
     }
 
@@ -1309,6 +1312,10 @@
                     y0 = r.top + (r.bottom - r.top) * st.mCenterY;
 
                     float radius = st.mGradientRadius;
+                    if (Float.compare(radius, 0.0f) == -1 || Float.isNaN(radius)) {
+                        throw new IllegalArgumentException("Gradient radius must be a valid "
+                                + "number greater than or equal to 0");
+                    }
                     if (st.mGradientRadiusType == RADIUS_TYPE_FRACTION) {
                         // Fall back to parent width or height if intrinsic
                         // size is not specified.
@@ -1465,7 +1472,7 @@
 
         final int tintMode = a.getInt(R.styleable.GradientDrawable_tintMode, -1);
         if (tintMode != -1) {
-            state.mTintMode = Drawable.parseTintMode(tintMode, PorterDuff.Mode.SRC_IN);
+            state.mBlendMode = Drawable.parseBlendMode(tintMode, BlendMode.SRC_IN);
         }
 
         final ColorStateList tint = a.getColorStateList(R.styleable.GradientDrawable_tint);
@@ -1756,75 +1763,68 @@
             st.mGradientColors[1] = endColor;
         }
 
-        if (st.mGradient == LINEAR_GRADIENT) {
-            int angle = (int) a.getFloat(R.styleable.GradientDrawableGradient_angle, st.mAngle);
-            angle %= 360;
+        int angle = (int) a.getFloat(R.styleable.GradientDrawableGradient_angle, st.mAngle);
+        angle %= 360;
 
-            if (angle % 45 != 0) {
-                throw new XmlPullParserException(a.getPositionDescription()
-                        + "<gradient> tag requires 'angle' attribute to "
-                        + "be a multiple of 45");
-            }
+        if (angle % 45 != 0) {
+            throw new XmlPullParserException(a.getPositionDescription()
+                    + "<gradient> tag requires 'angle' attribute to "
+                    + "be a multiple of 45");
+        }
 
-            st.mAngle = angle;
+        st.mAngle = angle;
 
-            switch (angle) {
-                case 0:
-                    st.mOrientation = Orientation.LEFT_RIGHT;
-                    break;
-                case 45:
-                    st.mOrientation = Orientation.BL_TR;
-                    break;
-                case 90:
-                    st.mOrientation = Orientation.BOTTOM_TOP;
-                    break;
-                case 135:
-                    st.mOrientation = Orientation.BR_TL;
-                    break;
-                case 180:
-                    st.mOrientation = Orientation.RIGHT_LEFT;
-                    break;
-                case 225:
-                    st.mOrientation = Orientation.TR_BL;
-                    break;
-                case 270:
-                    st.mOrientation = Orientation.TOP_BOTTOM;
-                    break;
-                case 315:
-                    st.mOrientation = Orientation.TL_BR;
-                    break;
-            }
-        } else {
-            final TypedValue tv = a.peekValue(R.styleable.GradientDrawableGradient_gradientRadius);
-            if (tv != null) {
-                final float radius;
-                final @RadiusType int radiusType;
-                if (tv.type == TypedValue.TYPE_FRACTION) {
-                    radius = tv.getFraction(1.0f, 1.0f);
+        switch (angle) {
+            case 0:
+                st.mOrientation = Orientation.LEFT_RIGHT;
+                break;
+            case 45:
+                st.mOrientation = Orientation.BL_TR;
+                break;
+            case 90:
+                st.mOrientation = Orientation.BOTTOM_TOP;
+                break;
+            case 135:
+                st.mOrientation = Orientation.BR_TL;
+                break;
+            case 180:
+                st.mOrientation = Orientation.RIGHT_LEFT;
+                break;
+            case 225:
+                st.mOrientation = Orientation.TR_BL;
+                break;
+            case 270:
+                st.mOrientation = Orientation.TOP_BOTTOM;
+                break;
+            case 315:
+                st.mOrientation = Orientation.TL_BR;
+                break;
+        }
 
-                    final int unit = (tv.data >> TypedValue.COMPLEX_UNIT_SHIFT)
-                            & TypedValue.COMPLEX_UNIT_MASK;
-                    if (unit == TypedValue.COMPLEX_UNIT_FRACTION_PARENT) {
-                        radiusType = RADIUS_TYPE_FRACTION_PARENT;
-                    } else {
-                        radiusType = RADIUS_TYPE_FRACTION;
-                    }
-                } else if (tv.type == TypedValue.TYPE_DIMENSION) {
-                    radius = tv.getDimension(r.getDisplayMetrics());
-                    radiusType = RADIUS_TYPE_PIXELS;
+        final TypedValue tv = a.peekValue(R.styleable.GradientDrawableGradient_gradientRadius);
+        if (tv != null) {
+            final float radius;
+            final @RadiusType int radiusType;
+            if (tv.type == TypedValue.TYPE_FRACTION) {
+                radius = tv.getFraction(1.0f, 1.0f);
+
+                final int unit = (tv.data >> TypedValue.COMPLEX_UNIT_SHIFT)
+                        & TypedValue.COMPLEX_UNIT_MASK;
+                if (unit == TypedValue.COMPLEX_UNIT_FRACTION_PARENT) {
+                    radiusType = RADIUS_TYPE_FRACTION_PARENT;
                 } else {
-                    radius = tv.getFloat();
-                    radiusType = RADIUS_TYPE_PIXELS;
+                    radiusType = RADIUS_TYPE_FRACTION;
                 }
-
-                st.mGradientRadius = radius;
-                st.mGradientRadiusType = radiusType;
-            } else if (st.mGradient == RADIAL_GRADIENT) {
-                throw new XmlPullParserException(
-                        a.getPositionDescription()
-                        + "<gradient> tag requires 'gradientRadius' "
-                        + "attribute with radial type");
+            } else if (tv.type == TypedValue.TYPE_DIMENSION) {
+                radius = tv.getDimension(r.getDisplayMetrics());
+                radiusType = RADIUS_TYPE_PIXELS;
+            } else {
+                radius = tv.getFloat();
+                radiusType = RADIUS_TYPE_PIXELS;
             }
+
+            st.mGradientRadius = radius;
+            st.mGradientRadiusType = radiusType;
         }
     }
 
@@ -2010,7 +2010,7 @@
         boolean mOpaqueOverShape;
 
         ColorStateList mTint = null;
-        PorterDuff.Mode mTintMode = DEFAULT_TINT_MODE;
+        BlendMode mBlendMode = DEFAULT_BLEND_MODE;
 
         int mDensity = DisplayMetrics.DENSITY_DEFAULT;
 
@@ -2068,7 +2068,7 @@
             mOpaqueOverBounds = orig.mOpaqueOverBounds;
             mOpaqueOverShape = orig.mOpaqueOverShape;
             mTint = orig.mTint;
-            mTintMode = orig.mTintMode;
+            mBlendMode = orig.mBlendMode;
             mThemeAttrs = orig.mThemeAttrs;
             mAttrSize = orig.mAttrSize;
             mAttrGradient = orig.mAttrGradient;
@@ -2355,7 +2355,8 @@
             }
         }
 
-        mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
+        mBlendModeColorFilter = updateBlendModeFilter(mBlendModeColorFilter, state.mTint,
+                state.mBlendMode);
         mGradientIsDirty = true;
 
         state.computeOpacity();
diff --git a/graphics/java/android/graphics/drawable/Icon.java b/graphics/java/android/graphics/drawable/Icon.java
index 71dd7a2..5fd18a1 100644
--- a/graphics/java/android/graphics/drawable/Icon.java
+++ b/graphics/java/android/graphics/drawable/Icon.java
@@ -30,6 +30,7 @@
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
+import android.graphics.BlendMode;
 import android.graphics.PorterDuff;
 import android.net.Uri;
 import android.os.AsyncTask;
@@ -105,8 +106,8 @@
     private final int mType;
 
     private ColorStateList mTintList;
-    static final PorterDuff.Mode DEFAULT_TINT_MODE = Drawable.DEFAULT_TINT_MODE; // SRC_IN
-    private PorterDuff.Mode mTintMode = DEFAULT_TINT_MODE;
+    static final BlendMode DEFAULT_BLEND_MODE = Drawable.DEFAULT_BLEND_MODE; // SRC_IN
+    private BlendMode mBlendMode = Drawable.DEFAULT_BLEND_MODE;
 
     // To avoid adding unnecessary overhead, we have a few basic objects that get repurposed
     // based on the value of mType.
@@ -320,10 +321,10 @@
      */
     public Drawable loadDrawable(Context context) {
         final Drawable result = loadDrawableInner(context);
-        if (result != null && (mTintList != null || mTintMode != DEFAULT_TINT_MODE)) {
+        if (result != null && (mTintList != null || mBlendMode != DEFAULT_BLEND_MODE)) {
             result.mutate();
             result.setTintList(mTintList);
-            result.setTintMode(mTintMode);
+            result.setTintMode(mBlendMode);
         }
         return result;
     }
@@ -695,16 +696,30 @@
      *
      * @param mode a blending mode, as in {@link Drawable#setTintMode(PorterDuff.Mode)}, may be null
      * @return this same object, for use in chained construction
+     *
+     * @deprecated use {@link #setTintMode(BlendMode)} instead
      */
-    public Icon setTintMode(PorterDuff.Mode mode) {
-        mTintMode = mode;
+    @Deprecated
+    public @NonNull Icon setTintMode(@NonNull PorterDuff.Mode mode) {
+        mBlendMode = BlendMode.fromValue(mode.nativeInt);
+        return this;
+    }
+
+    /**
+     * Store a blending mode to use whenever this Icon is drawn.
+     *
+     * @param mode a blending mode, as in {@link Drawable#setTintMode(PorterDuff.Mode)}, may be null
+     * @return this same object, for use in chained construction
+     */
+    public @NonNull Icon setTintMode(@NonNull BlendMode mode) {
+        mBlendMode = mode;
         return this;
     }
 
     /** @hide */
     @UnsupportedAppUsage
     public boolean hasTint() {
-        return (mTintList != null) || (mTintMode != DEFAULT_TINT_MODE);
+        return (mTintList != null) || (mBlendMode != DEFAULT_BLEND_MODE);
     }
 
     /**
@@ -757,7 +772,7 @@
                 sep = "|";
             }
         }
-        if (mTintMode != DEFAULT_TINT_MODE) sb.append(" mode=").append(mTintMode);
+        if (mBlendMode != DEFAULT_BLEND_MODE) sb.append(" mode=").append(mBlendMode);
         sb.append(")");
         return sb.toString();
     }
@@ -807,7 +822,7 @@
         if (in.readInt() == 1) {
             mTintList = ColorStateList.CREATOR.createFromParcel(in);
         }
-        mTintMode = PorterDuff.intToMode(in.readInt());
+        mBlendMode = BlendMode.fromValue(in.readInt());
     }
 
     @Override
@@ -837,7 +852,7 @@
             dest.writeInt(1);
             mTintList.writeToParcel(dest, flags);
         }
-        dest.writeInt(PorterDuff.modeToInt(mTintMode));
+        dest.writeInt(BlendMode.toValue(mBlendMode));
     }
 
     public static final @android.annotation.NonNull Parcelable.Creator<Icon> CREATOR
diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
index b4392c8..e2c8492 100644
--- a/graphics/java/android/graphics/drawable/LayerDrawable.java
+++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
@@ -24,11 +24,11 @@
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
 import android.content.res.TypedArray;
+import android.graphics.BlendMode;
 import android.graphics.Canvas;
 import android.graphics.ColorFilter;
 import android.graphics.Outline;
 import android.graphics.PixelFormat;
-import android.graphics.PorterDuff.Mode;
 import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
@@ -1397,13 +1397,13 @@
     }
 
     @Override
-    public void setTintMode(Mode tintMode) {
+    public void setTintMode(@NonNull BlendMode blendMode) {
         final ChildDrawable[] array = mLayerState.mChildren;
         final int N = mLayerState.mNumChildren;
         for (int i = 0; i < N; i++) {
             final Drawable dr = array[i].mDrawable;
             if (dr != null) {
-                dr.setTintMode(tintMode);
+                dr.setTintMode(blendMode);
             }
         }
     }
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
index b534771..4972e6a 100644
--- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -25,6 +25,8 @@
 import android.content.res.Resources.Theme;
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
+import android.graphics.BlendMode;
+import android.graphics.BlendModeColorFilter;
 import android.graphics.Canvas;
 import android.graphics.ColorFilter;
 import android.graphics.ImageDecoder;
@@ -33,9 +35,6 @@
 import android.graphics.Outline;
 import android.graphics.Paint;
 import android.graphics.PixelFormat;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuff.Mode;
-import android.graphics.PorterDuffColorFilter;
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.util.AttributeSet;
@@ -73,7 +72,7 @@
 
     @UnsupportedAppUsage
     private NinePatchState mNinePatchState;
-    private PorterDuffColorFilter mTintFilter;
+    private BlendModeColorFilter mBlendModeFilter;
     private Rect mPadding;
     private Insets mOpticalInsets = Insets.NONE;
     private Rect mOutlineInsets;
@@ -198,8 +197,8 @@
         int restoreToCount = -1;
 
         final boolean clearColorFilter;
-        if (mTintFilter != null && getPaint().getColorFilter() == null) {
-            mPaint.setColorFilter(mTintFilter);
+        if (mBlendModeFilter != null && getPaint().getColorFilter() == null) {
+            mPaint.setColorFilter(mBlendModeFilter);
             clearColorFilter = true;
         } else {
             clearColorFilter = false;
@@ -344,14 +343,16 @@
     @Override
     public void setTintList(@Nullable ColorStateList tint) {
         mNinePatchState.mTint = tint;
-        mTintFilter = updateTintFilter(mTintFilter, tint, mNinePatchState.mTintMode);
+        mBlendModeFilter = updateBlendModeFilter(mBlendModeFilter, tint,
+                mNinePatchState.mBlendMode);
         invalidateSelf();
     }
 
     @Override
-    public void setTintMode(@Nullable PorterDuff.Mode tintMode) {
-        mNinePatchState.mTintMode = tintMode;
-        mTintFilter = updateTintFilter(mTintFilter, mNinePatchState.mTint, tintMode);
+    public void setTintMode(@Nullable BlendMode blendMode) {
+        mNinePatchState.mBlendMode = blendMode;
+        mBlendModeFilter = updateBlendModeFilter(mBlendModeFilter, mNinePatchState.mTint,
+                blendMode);
         invalidateSelf();
     }
 
@@ -467,7 +468,7 @@
 
         final int tintMode = a.getInt(R.styleable.NinePatchDrawable_tintMode, -1);
         if (tintMode != -1) {
-            state.mTintMode = Drawable.parseTintMode(tintMode, Mode.SRC_IN);
+            state.mBlendMode = Drawable.parseBlendMode(tintMode, BlendMode.SRC_IN);
         }
 
         final ColorStateList tint = a.getColorStateList(R.styleable.NinePatchDrawable_tint);
@@ -566,8 +567,9 @@
     @Override
     protected boolean onStateChange(int[] stateSet) {
         final NinePatchState state = mNinePatchState;
-        if (state.mTint != null && state.mTintMode != null) {
-            mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
+        if (state.mTint != null && state.mBlendMode != null) {
+            mBlendModeFilter = updateBlendModeFilter(mBlendModeFilter, state.mTint,
+                    state.mBlendMode);
             return true;
         }
 
@@ -593,7 +595,7 @@
         @UnsupportedAppUsage
         NinePatch mNinePatch = null;
         ColorStateList mTint = null;
-        Mode mTintMode = DEFAULT_TINT_MODE;
+        BlendMode mBlendMode = DEFAULT_BLEND_MODE;
         Rect mPadding = null;
         Insets mOpticalInsets = Insets.NONE;
         float mBaseAlpha = 1.0f;
@@ -628,7 +630,7 @@
             mChangingConfigurations = orig.mChangingConfigurations;
             mNinePatch = orig.mNinePatch;
             mTint = orig.mTint;
-            mTintMode = orig.mTintMode;
+            mBlendMode = orig.mBlendMode;
             mPadding = orig.mPadding;
             mOpticalInsets = orig.mOpticalInsets;
             mBaseAlpha = orig.mBaseAlpha;
@@ -751,7 +753,7 @@
         } else {
             mTargetDensity = Drawable.resolveDensity(res, mTargetDensity);
         }
-        mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
+        mBlendModeFilter = updateBlendModeFilter(mBlendModeFilter, state.mTint, state.mBlendMode);
         computeBitmapSize();
     }
 }
diff --git a/graphics/java/android/graphics/drawable/ShapeDrawable.java b/graphics/java/android/graphics/drawable/ShapeDrawable.java
index 7bfb4c3..b5fe7f9 100644
--- a/graphics/java/android/graphics/drawable/ShapeDrawable.java
+++ b/graphics/java/android/graphics/drawable/ShapeDrawable.java
@@ -24,14 +24,13 @@
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
 import android.content.res.TypedArray;
+import android.graphics.BlendMode;
+import android.graphics.BlendModeColorFilter;
 import android.graphics.Canvas;
 import android.graphics.ColorFilter;
 import android.graphics.Outline;
 import android.graphics.Paint;
 import android.graphics.PixelFormat;
-import android.graphics.PorterDuff;
-import android.graphics.PorterDuff.Mode;
-import android.graphics.PorterDuffColorFilter;
 import android.graphics.Rect;
 import android.graphics.Shader;
 import android.graphics.Xfermode;
@@ -75,7 +74,7 @@
  */
 public class ShapeDrawable extends Drawable {
     private @NonNull ShapeState mShapeState;
-    private PorterDuffColorFilter mTintFilter;
+    private BlendModeColorFilter mBlendModeColorFilter;
     private boolean mMutated;
 
     /**
@@ -238,8 +237,8 @@
         // only draw shape if it may affect output
         if (paint.getAlpha() != 0 || paint.getXfermode() != null || paint.hasShadowLayer()) {
             final boolean clearColorFilter;
-            if (mTintFilter != null && paint.getColorFilter() == null) {
-                paint.setColorFilter(mTintFilter);
+            if (mBlendModeColorFilter != null && paint.getColorFilter() == null) {
+                paint.setColorFilter(mBlendModeColorFilter);
                 clearColorFilter = true;
             } else {
                 clearColorFilter = false;
@@ -292,14 +291,16 @@
     @Override
     public void setTintList(ColorStateList tint) {
         mShapeState.mTint = tint;
-        mTintFilter = updateTintFilter(mTintFilter, tint, mShapeState.mTintMode);
+        mBlendModeColorFilter = updateBlendModeFilter(mBlendModeColorFilter, tint,
+                mShapeState.mBlendMode);
         invalidateSelf();
     }
 
     @Override
-    public void setTintMode(PorterDuff.Mode tintMode) {
-        mShapeState.mTintMode = tintMode;
-        mTintFilter = updateTintFilter(mTintFilter, mShapeState.mTint, tintMode);
+    public void setTintMode(@NonNull BlendMode blendMode) {
+        mShapeState.mBlendMode = blendMode;
+        mBlendModeColorFilter = updateBlendModeFilter(mBlendModeColorFilter, mShapeState.mTint,
+                blendMode);
         invalidateSelf();
     }
 
@@ -352,8 +353,9 @@
     @Override
     protected boolean onStateChange(int[] stateSet) {
         final ShapeState state = mShapeState;
-        if (state.mTint != null && state.mTintMode != null) {
-            mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
+        if (state.mTint != null && state.mBlendMode != null) {
+            mBlendModeColorFilter = updateBlendModeFilter(mBlendModeColorFilter, state.mTint,
+                    state.mBlendMode);
             return true;
         }
         return false;
@@ -475,7 +477,7 @@
 
         final int tintMode = a.getInt(R.styleable.ShapeDrawable_tintMode, -1);
         if (tintMode != -1) {
-            state.mTintMode = Drawable.parseTintMode(tintMode, Mode.SRC_IN);
+            state.mBlendMode = Drawable.parseBlendMode(tintMode, BlendMode.SRC_IN);
         }
 
         final ColorStateList tint = a.getColorStateList(R.styleable.ShapeDrawable_tint);
@@ -540,7 +542,7 @@
         int[] mThemeAttrs;
         Shape mShape;
         ColorStateList mTint;
-        Mode mTintMode = DEFAULT_TINT_MODE;
+        BlendMode mBlendMode = DEFAULT_BLEND_MODE;
         Rect mPadding;
         int mIntrinsicWidth;
         int mIntrinsicHeight;
@@ -573,7 +575,7 @@
                 }
             }
             mTint = orig.mTint;
-            mTintMode = orig.mTintMode;
+            mBlendMode = orig.mBlendMode;
             if (orig.mPadding != null) {
                 mPadding = new Rect(orig.mPadding);
             }
@@ -625,7 +627,8 @@
      * after inflating or applying a theme.
      */
     private void updateLocalState() {
-        mTintFilter = updateTintFilter(mTintFilter, mShapeState.mTint, mShapeState.mTintMode);
+        mBlendModeColorFilter = updateBlendModeFilter(mBlendModeColorFilter, mShapeState.mTint,
+                mShapeState.mBlendMode);
     }
 
     /**
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index 7325b85..43772ec 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -24,11 +24,13 @@
 import android.content.res.Resources;
 import android.content.res.Resources.Theme;
 import android.content.res.TypedArray;
+import android.graphics.BlendMode;
+import android.graphics.BlendModeColorFilter;
 import android.graphics.Canvas;
 import android.graphics.ColorFilter;
 import android.graphics.Insets;
 import android.graphics.PixelFormat;
-import android.graphics.PorterDuff.Mode;
+import android.graphics.PorterDuff;
 import android.graphics.PorterDuffColorFilter;
 import android.graphics.Rect;
 import android.graphics.Shader;
@@ -324,6 +326,8 @@
 
     @UnsupportedAppUsage
     private PorterDuffColorFilter mTintFilter;
+
+    private BlendModeColorFilter mBlendModeColorFilter;
     private ColorFilter mColorFilter;
 
     private boolean mMutated;
@@ -371,7 +375,7 @@
             mDpiScaledDirty = true;
         }
 
-        mTintFilter = updateTintFilter(mTintFilter, mVectorState.mTint, mVectorState.mTintMode);
+        updateColorFilters(mVectorState.mBlendMode, mVectorState.mTint);
     }
 
     @Override
@@ -413,7 +417,8 @@
         }
 
         // Color filters always override tint filters.
-        final ColorFilter colorFilter = (mColorFilter == null ? mTintFilter : mColorFilter);
+        final ColorFilter colorFilter = (mColorFilter == null ? mBlendModeColorFilter :
+                mColorFilter);
         final long colorFilterNativeInstance = colorFilter == null ? 0 :
                 colorFilter.getNativeInstance();
         boolean canReuseCache = mVectorState.canReuseCache();
@@ -475,17 +480,19 @@
         final VectorDrawableState state = mVectorState;
         if (state.mTint != tint) {
             state.mTint = tint;
-            mTintFilter = updateTintFilter(mTintFilter, tint, state.mTintMode);
+
+            updateColorFilters(mVectorState.mBlendMode, tint);
             invalidateSelf();
         }
     }
 
     @Override
-    public void setTintMode(Mode tintMode) {
+    public void setTintMode(@NonNull BlendMode blendMode) {
         final VectorDrawableState state = mVectorState;
-        if (state.mTintMode != tintMode) {
-            state.mTintMode = tintMode;
-            mTintFilter = updateTintFilter(mTintFilter, state.mTint, tintMode);
+        if (state.mBlendMode != blendMode) {
+            state.mBlendMode = blendMode;
+
+            updateColorFilters(state.mBlendMode, state.mTint);
             invalidateSelf();
         }
     }
@@ -515,14 +522,22 @@
             changed = true;
             state.mCacheDirty = true;
         }
-        if (state.mTint != null && state.mTintMode != null) {
-            mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
+        if (state.mTint != null && state.mBlendMode != null) {
+            BlendMode blendMode = state.mBlendMode;
+            ColorStateList tint = state.mTint;
+            updateColorFilters(blendMode, tint);
             changed = true;
         }
 
         return changed;
     }
 
+    private void updateColorFilters(@Nullable BlendMode blendMode, ColorStateList tint) {
+        PorterDuff.Mode mode = BlendMode.blendModeToPorterDuffMode(blendMode);
+        mTintFilter = updateTintFilter(mTintFilter, tint, mode);
+        mBlendModeColorFilter = updateBlendModeFilter(mBlendModeColorFilter, tint, blendMode);
+    }
+
     @Override
     public int getOpacity() {
         // We can't tell whether the drawable is fully opaque unless we examine all the pixels,
@@ -737,7 +752,7 @@
 
         final int tintMode = a.getInt(R.styleable.VectorDrawable_tintMode, -1);
         if (tintMode != -1) {
-            state.mTintMode = Drawable.parseTintMode(tintMode, Mode.SRC_IN);
+            state.mBlendMode = Drawable.parseBlendMode(tintMode, BlendMode.SRC_IN);
         }
 
         final ColorStateList tint = a.getColorStateList(R.styleable.VectorDrawable_tint);
@@ -911,7 +926,7 @@
         int[] mThemeAttrs;
         @Config int mChangingConfigurations;
         ColorStateList mTint = null;
-        Mode mTintMode = DEFAULT_TINT_MODE;
+        BlendMode mBlendMode = DEFAULT_BLEND_MODE;
         boolean mAutoMirrored;
 
         int mBaseWidth = 0;
@@ -929,7 +944,7 @@
         // Fields for cache
         int[] mCachedThemeAttrs;
         ColorStateList mCachedTint;
-        Mode mCachedTintMode;
+        BlendMode mCachedBlendMode;
         boolean mCachedAutoMirrored;
         boolean mCacheDirty;
 
@@ -970,7 +985,7 @@
                 mThemeAttrs = copy.mThemeAttrs;
                 mChangingConfigurations = copy.mChangingConfigurations;
                 mTint = copy.mTint;
-                mTintMode = copy.mTintMode;
+                mBlendMode = copy.mBlendMode;
                 mAutoMirrored = copy.mAutoMirrored;
                 mRootGroup = new VGroup(copy.mRootGroup, mVGTargetsMap);
                 createNativeTreeFromCopy(copy, mRootGroup);
@@ -1026,7 +1041,7 @@
             if (!mCacheDirty
                     && mCachedThemeAttrs == mThemeAttrs
                     && mCachedTint == mTint
-                    && mCachedTintMode == mTintMode
+                    && mCachedBlendMode == mBlendMode
                     && mCachedAutoMirrored == mAutoMirrored) {
                 return true;
             }
@@ -1039,7 +1054,7 @@
             // likely hit cache miss more, but practically not much difference.
             mCachedThemeAttrs = mThemeAttrs;
             mCachedTint = mTint;
-            mCachedTintMode = mTintMode;
+            mCachedBlendMode = mBlendMode;
             mCachedAutoMirrored = mAutoMirrored;
             mCacheDirty = false;
         }
diff --git a/graphics/java/android/graphics/pdf/PdfRenderer.java b/graphics/java/android/graphics/pdf/PdfRenderer.java
index 1836f00..bd1a492 100644
--- a/graphics/java/android/graphics/pdf/PdfRenderer.java
+++ b/graphics/java/android/graphics/pdf/PdfRenderer.java
@@ -435,8 +435,9 @@
             final long transformPtr = transform.native_instance;
 
             synchronized (sPdfiumLock) {
-                nativeRenderPage(mNativeDocument, mNativePage, destination, contentLeft,
-                        contentTop, contentRight, contentBottom, transformPtr, renderMode);
+                nativeRenderPage(mNativeDocument, mNativePage, destination.getNativeInstance(),
+                        contentLeft, contentTop, contentRight, contentBottom, transformPtr,
+                        renderMode);
             }
         }
 
@@ -487,7 +488,7 @@
     private static native void nativeClose(long documentPtr);
     private static native int nativeGetPageCount(long documentPtr);
     private static native boolean nativeScaleForPrinting(long documentPtr);
-    private static native void nativeRenderPage(long documentPtr, long pagePtr, Bitmap dest,
+    private static native void nativeRenderPage(long documentPtr, long pagePtr, long bitmapHandle,
             int clipLeft, int clipTop, int clipRight, int clipBottom, long transformPtr,
             int renderMode);
     private static native long nativeOpenPageAndGetSize(long documentPtr, int pageIndex,
diff --git a/keystore/tests/Android.bp b/keystore/tests/Android.bp
new file mode 100644
index 0000000..e9b22c1
--- /dev/null
+++ b/keystore/tests/Android.bp
@@ -0,0 +1,26 @@
+// Copyright (C) 2017 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+android_test {
+    name: "KeystoreTests",
+    // LOCAL_MODULE := keystore
+    srcs: ["src/**/*.java"],
+    static_libs: [
+        "androidx.test.rules",
+        "hamcrest-library",
+    ],
+    platform_apis: true,
+    libs: ["android.test.runner"],
+    certificate: "platform",
+}
diff --git a/keystore/tests/Android.mk b/keystore/tests/Android.mk
deleted file mode 100644
index 99d3197..0000000
--- a/keystore/tests/Android.mk
+++ /dev/null
@@ -1,34 +0,0 @@
-# Copyright (C) 2017 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-# LOCAL_MODULE := keystore
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    androidx.test.rules hamcrest-library
-
-LOCAL_PACKAGE_NAME := KeystoreTests
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_JAVA_LIBRARIES := android.test.runner
-
-LOCAL_CERTIFICATE := platform
-
-include $(BUILD_PACKAGE)
-
diff --git a/libs/hwui/HardwareBitmapUploader.cpp b/libs/hwui/HardwareBitmapUploader.cpp
index 8f7e814..9bb6031 100644
--- a/libs/hwui/HardwareBitmapUploader.cpp
+++ b/libs/hwui/HardwareBitmapUploader.cpp
@@ -349,8 +349,7 @@
     } else {
         SkBitmap bitmap;
         const SkImageInfo& info = source.info();
-        bitmap.allocPixels(
-                SkImageInfo::MakeN32(info.width(), info.height(), info.alphaType(), nullptr));
+        bitmap.allocPixels(info.makeColorType(kN32_SkColorType));
 
         SkCanvas canvas(bitmap);
         canvas.drawColor(0);
@@ -416,7 +415,9 @@
 }
 
 void HardwareBitmapUploader::terminate() {
-    sUploader->destroy();
+    if (sUploader) {
+        sUploader->destroy();
+    }
 }
 
 }  // namespace android::uirenderer
diff --git a/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp b/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
index ceab407..1b9e53b 100644
--- a/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
+++ b/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
@@ -19,6 +19,7 @@
 
 #include "renderthread/VulkanManager.h"
 #include "renderthread/RenderThread.h"
+#include <SkAndroidFrameworkUtils.h>
 #include <GrBackendDrawableInfo.h>
 #include <SkImage.h>
 #include <utils/Color.h>
@@ -89,9 +90,29 @@
 VkFunctorDrawable::~VkFunctorDrawable() {
 }
 
-void VkFunctorDrawable::onDraw(SkCanvas* /*canvas*/) {
-    LOG_ALWAYS_FATAL("VkFunctorDrawable::onDraw() should never be called.");
-    // Instead of calling onDraw(), the call should come from onSnapGpuDrawHandler.
+void VkFunctorDrawable::onDraw(SkCanvas* canvas) {
+    // "canvas" is either SkNWayCanvas created by SkiaPipeline::tryCapture (SKP capture use case) or
+    // AlphaFilterCanvas (used by RenderNodeDrawable to apply alpha in certain cases).
+    // "VkFunctorDrawable::onDraw" is not invoked for the most common case, when drawing in a GPU
+    // canvas.
+
+    if (canvas->getGrContext() == nullptr) {
+        // We're dumping a picture, render a light-blue rectangle instead
+        SkPaint paint;
+        paint.setColor(0xFF81D4FA);
+        canvas->drawRect(mBounds, paint);
+    } else {
+        // Handle the case when "canvas" is AlphaFilterCanvas. Find the wrapped GPU canvas.
+        SkCanvas* gpuCanvas = SkAndroidFrameworkUtils::getBaseWrappedCanvas(canvas);
+        // Enforce "canvas" must be an AlphaFilterCanvas. For GPU canvas, the call should come from
+        // onSnapGpuDrawHandler.
+        LOG_ALWAYS_FATAL_IF(
+                gpuCanvas == canvas,
+                "VkFunctorDrawable::onDraw() should not be called with a GPU canvas!");
+
+        // This will invoke onSnapGpuDrawHandler and regular draw flow.
+        gpuCanvas->drawDrawable(this);
+    }
 }
 
 std::unique_ptr<FunctorDrawable::GpuDrawHandler> VkFunctorDrawable::onSnapGpuDrawHandler(
diff --git a/location/Android.mk b/location/Android.mk
deleted file mode 100644
index 50509c6..0000000
--- a/location/Android.mk
+++ /dev/null
@@ -1,17 +0,0 @@
-# Copyright (C) 2010 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-LOCAL_PATH := $(call my-dir)
-
-include $(call all-subdir-makefiles, $(LOCAL_PATH))
\ No newline at end of file
diff --git a/location/java/android/location/ILocationManager.aidl b/location/java/android/location/ILocationManager.aidl
index 93dc6fa..97bc404 100644
--- a/location/java/android/location/ILocationManager.aidl
+++ b/location/java/android/location/ILocationManager.aidl
@@ -93,10 +93,10 @@
     ProviderProperties getProviderProperties(String provider);
     boolean isProviderPackage(String packageName);
 
-    void setLocationControllerExtraPackage(String packageName);
-    String getLocationControllerExtraPackage();
-    void setLocationControllerExtraPackageEnabled(boolean enabled);
-    boolean isLocationControllerExtraPackageEnabled();
+    void setExtraLocationControllerPackage(String packageName);
+    String getExtraLocationControllerPackage();
+    void setExtraLocationControllerPackageEnabled(boolean enabled);
+    boolean isExtraLocationControllerPackageEnabled();
 
     boolean isProviderEnabledForUser(String provider, int userId);
     boolean isLocationEnabledForUser(int userId);
diff --git a/location/java/android/location/LocationManager.java b/location/java/android/location/LocationManager.java
index edf304c..af60e3c 100644
--- a/location/java/android/location/LocationManager.java
+++ b/location/java/android/location/LocationManager.java
@@ -2328,9 +2328,27 @@
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.LOCATION_HARDWARE)
-    public void setLocationControllerExtraPackage(@NonNull String packageName) {
+    public void setExtraLocationControllerPackage(@Nullable String packageName) {
         try {
-            mService.setLocationControllerExtraPackage(packageName);
+            mService.setExtraLocationControllerPackage(packageName);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Set the extra location controller package for location services on the device.
+     *
+     * @removed
+     * @deprecated Use {@link #setExtraLocationControllerPackage} instead.
+     * @hide
+     */
+    @Deprecated
+    @SystemApi
+    @RequiresPermission(Manifest.permission.LOCATION_HARDWARE)
+    public void setLocationControllerExtraPackage(String packageName) {
+        try {
+            mService.setExtraLocationControllerPackage(packageName);
         } catch (RemoteException e) {
             e.rethrowFromSystemServer();
         }
@@ -2342,9 +2360,9 @@
      * @hide
      */
     @SystemApi
-    public @Nullable String getLocationControllerExtraPackage() {
+    public @Nullable String getExtraLocationControllerPackage() {
         try {
-            return mService.getLocationControllerExtraPackage();
+            return mService.getExtraLocationControllerPackage();
         } catch (RemoteException e) {
             e.rethrowFromSystemServer();
             return null;
@@ -2354,13 +2372,31 @@
     /**
      * Set whether the extra location controller package is currently enabled on the device.
      *
+     * @removed
+     * @deprecated Use {@link #setExtraLocationControllerPackageEnabled} instead.
+     * @hide
+     */
+    @SystemApi
+    @Deprecated
+    @RequiresPermission(Manifest.permission.LOCATION_HARDWARE)
+    public void setLocationControllerExtraPackageEnabled(boolean enabled) {
+        try {
+            mService.setExtraLocationControllerPackageEnabled(enabled);
+        } catch (RemoteException e) {
+            e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Set whether the extra location controller package is currently enabled on the device.
+     *
      * @hide
      */
     @SystemApi
     @RequiresPermission(Manifest.permission.LOCATION_HARDWARE)
-    public void setLocationControllerExtraPackageEnabled(boolean enabled) {
+    public void setExtraLocationControllerPackageEnabled(boolean enabled) {
         try {
-            mService.setLocationControllerExtraPackageEnabled(enabled);
+            mService.setExtraLocationControllerPackageEnabled(enabled);
         } catch (RemoteException e) {
             e.rethrowFromSystemServer();
         }
@@ -2372,9 +2408,9 @@
      * @hide
      */
     @SystemApi
-    public boolean isLocationControllerExtraPackageEnabled() {
+    public boolean isExtraLocationControllerPackageEnabled() {
         try {
-            return mService.isLocationControllerExtraPackageEnabled();
+            return mService.isExtraLocationControllerPackageEnabled();
         } catch (RemoteException e) {
             e.rethrowFromSystemServer();
             return false;
diff --git a/location/tests/Android.bp b/location/tests/Android.bp
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/location/tests/Android.bp
@@ -0,0 +1 @@
+
diff --git a/location/tests/Android.mk b/location/tests/Android.mk
deleted file mode 100644
index 57848f3..0000000
--- a/location/tests/Android.mk
+++ /dev/null
@@ -1,3 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-include $(call all-makefiles-under, $(LOCAL_PATH))
\ No newline at end of file
diff --git a/location/tests/locationtests/Android.bp b/location/tests/locationtests/Android.bp
new file mode 100644
index 0000000..1a4e2c7
--- /dev/null
+++ b/location/tests/locationtests/Android.bp
@@ -0,0 +1,19 @@
+android_test {
+    name: "FrameworksLocationTests",
+    // Include all test java files.
+    srcs: ["src/**/*.java"],
+    libs: [
+        "android.test.runner",
+        "android.test.base",
+    ],
+    platform_apis: true,
+    static_libs: [
+        "androidx.test.rules",
+        "core-test-rules",
+        "guava",
+        "mockito-target-minus-junit4",
+        "frameworks-base-testutils",
+        "truth-prebuilt",
+    ],
+    test_suites: ["device-tests"],
+}
diff --git a/location/tests/locationtests/Android.mk b/location/tests/locationtests/Android.mk
deleted file mode 100644
index 3dcf694..0000000
--- a/location/tests/locationtests/Android.mk
+++ /dev/null
@@ -1,23 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-# We only want this apk build for tests.
-LOCAL_MODULE_TAGS := tests
-
-# Include all test java files.
-LOCAL_SRC_FILES := $(call all-java-files-under, src)
-
-LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base
-LOCAL_PACKAGE_NAME := FrameworksLocationTests
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    androidx.test.rules \
-    core-test-rules \
-    guava \
-    mockito-target-minus-junit4 \
-    frameworks-base-testutils \
-    truth-prebuilt \
-
-LOCAL_COMPATIBILITY_SUITE := device-tests
-include $(BUILD_PACKAGE)
diff --git a/media/apex/java/android/media/MediaPlayer2.java b/media/apex/java/android/media/MediaPlayer2.java
index 19bb258..87035da 100644
--- a/media/apex/java/android/media/MediaPlayer2.java
+++ b/media/apex/java/android/media/MediaPlayer2.java
@@ -1546,7 +1546,7 @@
      * Returns the size of the video.
      *
      * @return the size of the video. The width and height of size could be 0 if there is no video,
-     * no display surface was set, or the size has not been determined yet.
+     * or the size has not been determined yet.
      * The {@code EventCallback} can be registered via
      * {@link #registerEventCallback(Executor, EventCallback)} to provide a
      * notification {@code EventCallback.onVideoSizeChanged} when the size
@@ -2870,7 +2870,7 @@
          * Called to indicate the video size
          *
          * The video size (width and height) could be 0 if there was no video,
-         * no display surface was set, or the value was not determined yet.
+         * or the value was not determined yet.
          *
          * @param mp the MediaPlayer2 associated with this callback
          * @param dsd the DataSourceDesc of this data source
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index c2f29bc..a3eee0a 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -20,6 +20,7 @@
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
+import android.media.audiopolicy.AudioProductStrategies;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Parcel;
@@ -370,9 +371,10 @@
 
     /**
      * @hide
-     * Flag specifying that the audio shall not be captured by other apps.
+     * Flag specifying that the audio shall not be captured by third-party apps
+     * with a MediaProjection.
      */
-    public static final int FLAG_NO_CAPTURE = 0x1 << 10;
+    public static final int FLAG_NO_MEDIA_PROJECTION = 0x1 << 10;
 
     /**
      * @hide
@@ -380,12 +382,63 @@
      */
     public static final int FLAG_MUTE_HAPTIC = 0x1 << 11;
 
+    /**
+     * @hide
+     * Flag specifying that the audio shall not be captured by any apps, not even system apps.
+     */
+    public static final int FLAG_NO_SYSTEM_CAPTURE = 0x1 << 12;
+
     private final static int FLAG_ALL = FLAG_AUDIBILITY_ENFORCED | FLAG_SECURE | FLAG_SCO |
             FLAG_BEACON | FLAG_HW_AV_SYNC | FLAG_HW_HOTWORD | FLAG_BYPASS_INTERRUPTION_POLICY |
             FLAG_BYPASS_MUTE | FLAG_LOW_LATENCY | FLAG_DEEP_BUFFER | FLAG_MUTE_HAPTIC;
     private final static int FLAG_ALL_PUBLIC = FLAG_AUDIBILITY_ENFORCED |
             FLAG_HW_AV_SYNC | FLAG_LOW_LATENCY;
 
+    /**
+     * Indicates that the audio may be captured by any app.
+     *
+     * For privacy, the following usages can not be recorded: VOICE_COMMUNICATION*,
+     * USAGE_NOTIFICATION*, USAGE_ASSISTANCE* and USAGE_ASSISTANT.
+     *
+     * On {@link android.os.Build.VERSION_CODES#Q}, this means only {@link #USAGE_UNKNOWN},
+     * {@link #USAGE_MEDIA} and {@link #USAGE_GAME} may be captured.
+     *
+     * See {@link android.media.projection.MediaProjection} and
+     * {@link Builder#setAllowedCapturePolicy}.
+     */
+    public static final int ALLOW_CAPTURE_BY_ALL = 1;
+    /**
+     * Indicates that the audio may only be captured by system apps.
+     *
+     * System apps can capture for many purposes like accessibility, user guidance...
+     * but abide to the following restrictions:
+     *  - the audio can not leave the device
+     *  - the audio can not be passed to a third party app
+     *  - the audio can not be recorded at a higher quality then 16kHz 16bit mono
+     *
+     * See {@link Builder#setAllowedCapturePolicy}.
+     */
+    public static final int ALLOW_CAPTURE_BY_SYSTEM = 2;
+    /**
+     * Indicates that the audio is not to be recorded by any app, even if it is a system app.
+     *
+     * It is encouraged to use {@link #ALLOW_CAPTURE_BY_SYSTEM} instead of this value as system apps
+     * provide significant and useful features for the user (such as live captioning
+     * and accessibility).
+     *
+     * See {@link Builder#setAllowedCapturePolicy}.
+     */
+    public static final int ALLOW_CAPTURE_BY_NONE = 3;
+
+    /** @hide */
+    @IntDef({
+        ALLOW_CAPTURE_BY_ALL,
+        ALLOW_CAPTURE_BY_SYSTEM,
+        ALLOW_CAPTURE_BY_NONE,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface CapturePolicy {}
+
     @UnsupportedAppUsage
     private int mUsage = USAGE_UNKNOWN;
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
@@ -593,10 +646,10 @@
                 case USAGE_GAME:
                 case USAGE_VIRTUAL_SOURCE:
                 case USAGE_ASSISTANT:
-                     mUsage = usage;
-                     break;
+                    mUsage = usage;
+                    break;
                 default:
-                     mUsage = USAGE_UNKNOWN;
+                    mUsage = USAGE_UNKNOWN;
             }
             return this;
         }
@@ -642,18 +695,22 @@
         }
 
         /**
-         * Specifying if audio shall or shall not be captured by other apps.
-         * By default, capture is allowed.
-         * @param allowCapture false to forbid capture of the audio by any apps,
-         *                     true to allow apps to capture the audio
+         * Specifying if audio may or may not be captured by other apps or the system.
+         *
+         * The default is {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL}.
+         *
+         * Note that an application can also set its global policy, in which case the most
+         * restrictive policy is always applied.
+         *
+         * @param capturePolicy one of
+         *     {@link #ALLOW_CAPTURE_BY_ALL},
+         *     {@link #ALLOW_CAPTURE_BY_SYSTEM},
+         *     {@link #ALLOW_CAPTURE_BY_NONE}.
          * @return the same Builder instance
+         * @throws IllegalArgumentException if the argument is not a valid value.
          */
-        public @NonNull Builder setAllowCapture(boolean allowCapture) {
-            if (allowCapture) {
-                mFlags &= ~FLAG_NO_CAPTURE;
-            } else {
-                mFlags |= FLAG_NO_CAPTURE;
-            }
+        public @NonNull Builder setAllowedCapturePolicy(@CapturePolicy int capturePolicy) {
+            mFlags = capturePolicyToFlags(capturePolicy, mFlags);
             return this;
         }
 
@@ -725,6 +782,13 @@
          */
         @UnsupportedAppUsage
         public Builder setInternalLegacyStreamType(int streamType) {
+            final AudioProductStrategies ps = new AudioProductStrategies();
+            if (ps.size() > 0) {
+                AudioAttributes attributes = ps.getAudioAttributesForLegacyStreamType(streamType);
+                if (attributes != null) {
+                    return new Builder(attributes);
+                }
+            }
             switch(streamType) {
                 case AudioSystem.STREAM_VOICE_CALL:
                     mContentType = CONTENT_TYPE_SPEECH;
@@ -1100,6 +1164,10 @@
                     AudioSystem.STREAM_MUSIC : AudioSystem.STREAM_TTS;
         }
 
+        final AudioProductStrategies ps = new AudioProductStrategies();
+        if (ps.size() > 0) {
+            return ps.getLegacyStreamTypeForAudioAttributes(aa);
+        }
         // usage to stream type mapping
         switch (aa.getUsage()) {
             case USAGE_MEDIA:
@@ -1138,6 +1206,24 @@
         }
     }
 
+    static int capturePolicyToFlags(@CapturePolicy int capturePolicy, int flags) {
+        switch (capturePolicy) {
+            case ALLOW_CAPTURE_BY_NONE:
+                flags |= FLAG_NO_MEDIA_PROJECTION | FLAG_NO_SYSTEM_CAPTURE;
+                break;
+            case ALLOW_CAPTURE_BY_SYSTEM:
+                flags |= FLAG_NO_MEDIA_PROJECTION;
+                flags &= ~FLAG_NO_SYSTEM_CAPTURE;
+                break;
+            case ALLOW_CAPTURE_BY_ALL:
+                flags &= ~FLAG_NO_SYSTEM_CAPTURE & ~FLAG_NO_MEDIA_PROJECTION;
+                break;
+            default:
+                throw new IllegalArgumentException("Unknown allow playback capture policy");
+        }
+        return flags;
+    }
+
     /** @hide */
     @IntDef({
         USAGE_UNKNOWN,
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 7cb5e00..dc5c663 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1478,6 +1478,30 @@
         }
      }
 
+    /**
+     * Specifying if this audio may or may not be captured by other apps or the system.
+     *
+     * The default is {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL}.
+     *
+     * Note that each audio track can also set its policy, in which case the most
+     * restrictive policy is always applied.
+     *
+     * @param capturePolicy one of
+     *     {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL},
+     *     {@link AudioAttributes#ALLOW_CAPTURE_BY_SYSTEM},
+     *     {@link AudioAttributes#ALLOW_CAPTURE_BY_NONE}.
+     * @throws IllegalArgumentException if the argument is not a valid value.
+     */
+    public void setAllowedCapturePolicy(@AudioAttributes.CapturePolicy int capturePolicy) {
+        int flags = AudioAttributes.capturePolicyToFlags(capturePolicy, 0x0);
+        // TODO: got trough AudioService and save a cache to restore in case of AP crash
+        // TODO: also pass the package in case multiple packages have the same UID
+        int result = AudioSystem.setAllowedCapturePolicy(Process.myUid(), flags);
+        if (result != AudioSystem.AUDIO_STATUS_OK) {
+            Log.e(TAG, "Could not setAllowedCapturePolicy: " + result);
+        }
+    }
+
     //====================================================================
     // Offload query
     /**
diff --git a/media/java/android/media/AudioPlaybackCaptureConfiguration.java b/media/java/android/media/AudioPlaybackCaptureConfiguration.java
index 4aa0b90..bcaef03 100644
--- a/media/java/android/media/AudioPlaybackCaptureConfiguration.java
+++ b/media/java/android/media/AudioPlaybackCaptureConfiguration.java
@@ -28,14 +28,18 @@
 /**
  * Configuration for capturing audio played by other apps.
  *
- * For privacy and copyright reason, only the following audio can be captured:
- *  - usage MUST be UNKNOWN or GAME or MEDIA. All other usages CAN NOT be capturable.
- *  - audio attributes MUST NOT have the FLAG_NO_CAPTURE
+ * Only the following audio can be captured:
+ *  - usage MUST be {@link AudioAttributes#USAGE_UNKNOWN} or {@link AudioAttributes#USAGE_GAME}
+ *    or {@link AudioAttributes#USAGE_MEDIA}. All other usages CAN NOT be captured.
+ *  - audio attributes MUST have its ${@link AudioAttributes.Builder#setAllowedCapturePolicy}
+ *    to {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL}.
  *  - played by apps that MUST be in the same user profile as the capturing app
  *    (eg work profile can not capture user profile apps and vice-versa).
- *  - played by apps that MUST NOT have in their manifest.xml the application
- *    attribute android:allowAudioPlaybackCapture="false"
- *  - played by apps that MUST have a targetSdkVersion higher or equal to 29 (Q).
+ *  - played by apps for which the attribute allowAudioPlaybackCapture in their manifest
+ *    MUST either be:
+ *      * set to "true"
+ *      * not set, and their targetSdkVersion MUST be equal or higher to
+ *        {@link android.os.Build.VERSION_CODES#Q}.
  *
  * <p>An example for creating a capture configuration for capturing all media playback:
  *
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index a7760a80..2dd7f0f 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -25,6 +25,7 @@
 import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityThread;
+import android.media.MediaRecorder.Source;
 import android.media.audiopolicy.AudioMix;
 import android.media.audiopolicy.AudioPolicy;
 import android.media.projection.MediaProjection;
@@ -539,7 +540,7 @@
          * @return the same Builder instance.
          * @throws IllegalArgumentException
          */
-        public Builder setAudioSource(int source) throws IllegalArgumentException {
+        public Builder setAudioSource(@Source int source) throws IllegalArgumentException {
             Preconditions.checkState(
                     mAudioPlaybackCaptureConfiguration == null,
                     ERROR_MESSAGE_SOURCE_MISMATCH);
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index ad255fe..d105fa3 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -1022,6 +1022,11 @@
 
     public static native float getStreamVolumeDB(int stream, int index, int device);
 
+    /**
+     * @see AudioManager#setAllowedCapturePolicy()
+     */
+    public static native int setAllowedCapturePolicy(int uid, int flags);
+
     static boolean isOffloadSupported(@NonNull AudioFormat format, @NonNull AudioAttributes attr) {
         return native_is_offload_supported(format.getEncoding(), format.getSampleRate(),
                 format.getChannelMask(), format.getChannelIndexMask(),
diff --git a/media/java/android/media/HwAudioSource.java b/media/java/android/media/HwAudioSource.java
index e53b7e8..01a02f1 100644
--- a/media/java/android/media/HwAudioSource.java
+++ b/media/java/android/media/HwAudioSource.java
@@ -224,14 +224,4 @@
             return new HwAudioSource(mAudioDeviceInfo, mAudioAttributes);
         }
     }
-
-    /**
-     * Eliminate {@link #deprecateStreamTypeForPlayback(int, String, String)} in API list.
-     * TODO: remove this pseudo-override function
-     * @hide
-     */
-    public static void deprecateStreamTypeForPlayback(int streamType, String className,
-            String opName) throws IllegalArgumentException {
-        // Do nothing.
-    }
 }
diff --git a/media/java/android/media/MediaFormat.java b/media/java/android/media/MediaFormat.java
index a22c8d0..4d63cc8 100644
--- a/media/java/android/media/MediaFormat.java
+++ b/media/java/android/media/MediaFormat.java
@@ -1060,7 +1060,7 @@
      * that no B frames are allowed. Note that non-zero value does not guarantee
      * B frames; it's up to the encoder to decide.
      */
-    public static final String KEY_MAX_BFRAMES = "max-bframes";
+    public static final String KEY_MAX_B_FRAMES = "max-bframes";
 
     /* package private */ MediaFormat(@NonNull Map<String, Object> map) {
         mMap = map;
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 575a0bb..63b22df 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -18,6 +18,7 @@
 
 import android.annotation.CallbackExecutor;
 import android.annotation.FloatRange;
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
@@ -42,6 +43,8 @@
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.RandomAccessFile;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.List;
@@ -355,6 +358,22 @@
         public static final int HOTWORD = 1999;
     }
 
+    /** @hide */
+    @IntDef({
+        AudioSource.DEFAULT,
+        AudioSource.MIC,
+        AudioSource.VOICE_UPLINK,
+        AudioSource.VOICE_DOWNLINK,
+        AudioSource.VOICE_CALL,
+        AudioSource.CAMCORDER,
+        AudioSource.VOICE_RECOGNITION,
+        AudioSource.VOICE_COMMUNICATION,
+        AudioSource.UNPROCESSED,
+        AudioSource.VOICE_PERFORMANCE,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Source {}
+
     // TODO make AudioSource static (API change) and move this method inside the AudioSource class
     /**
      * @hide
@@ -547,11 +566,11 @@
      * to be specified before setting recording-parameters or encoders. Call
      * this only before setOutputFormat().
      *
-     * @param audio_source the audio source to use
+     * @param audioSource the audio source to use
      * @throws IllegalStateException if it is called after setOutputFormat()
      * @see android.media.MediaRecorder.AudioSource
      */
-    public native void setAudioSource(int audio_source)
+    public native void setAudioSource(@Source int audioSource)
             throws IllegalStateException;
 
     /**
diff --git a/media/java/android/media/audiopolicy/AudioMix.java b/media/java/android/media/audiopolicy/AudioMix.java
index 6fd6298..09f17c0 100644
--- a/media/java/android/media/audiopolicy/AudioMix.java
+++ b/media/java/android/media/audiopolicy/AudioMix.java
@@ -142,7 +142,8 @@
         return mFormat;
     }
 
-    AudioMixingRule getRule() {
+    /** @hide */
+    public AudioMixingRule getRule() {
         return mRule;
     }
 
diff --git a/media/java/android/media/audiopolicy/AudioMixingRule.java b/media/java/android/media/audiopolicy/AudioMixingRule.java
index d41f416..947b06c 100644
--- a/media/java/android/media/audiopolicy/AudioMixingRule.java
+++ b/media/java/android/media/audiopolicy/AudioMixingRule.java
@@ -16,6 +16,7 @@
 
 package android.media.audiopolicy;
 
+import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.annotation.UnsupportedAppUsage;
 import android.media.AudioAttributes;
@@ -43,9 +44,11 @@
 @SystemApi
 public class AudioMixingRule {
 
-    private AudioMixingRule(int mixType, ArrayList<AudioMixMatchCriterion> criteria) {
+    private AudioMixingRule(int mixType, ArrayList<AudioMixMatchCriterion> criteria,
+                            boolean allowPrivilegedPlaybackCapture) {
         mCriteria = criteria;
         mTargetMixType = mixType;
+        mAllowPrivilegedPlaybackCapture = allowPrivilegedPlaybackCapture;
     }
 
     /**
@@ -161,6 +164,13 @@
     @UnsupportedAppUsage
     private final ArrayList<AudioMixMatchCriterion> mCriteria;
     ArrayList<AudioMixMatchCriterion> getCriteria() { return mCriteria; }
+    @UnsupportedAppUsage
+    private boolean mAllowPrivilegedPlaybackCapture = false;
+
+    /** @hide */
+    public boolean allowPrivilegedPlaybackCapture() {
+        return mAllowPrivilegedPlaybackCapture;
+    }
 
     /** @hide */
     @Override
@@ -170,12 +180,13 @@
 
         final AudioMixingRule that = (AudioMixingRule) o;
         return (this.mTargetMixType == that.mTargetMixType)
-                && (areCriteriaEquivalent(this.mCriteria, that.mCriteria));
+                && (areCriteriaEquivalent(this.mCriteria, that.mCriteria)
+                && this.mAllowPrivilegedPlaybackCapture == that.mAllowPrivilegedPlaybackCapture);
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(mTargetMixType, mCriteria);
+        return Objects.hash(mTargetMixType, mCriteria, mAllowPrivilegedPlaybackCapture);
     }
 
     private static boolean isValidSystemApiRule(int rule) {
@@ -239,6 +250,7 @@
     public static class Builder {
         private ArrayList<AudioMixMatchCriterion> mCriteria;
         private int mTargetMixType = AudioMix.MIX_TYPE_INVALID;
+        private boolean mAllowPrivilegedPlaybackCapture = false;
 
         /**
          * Constructs a new Builder with no rules.
@@ -343,6 +355,21 @@
         }
 
         /**
+         * Set if the audio of app that opted out of audio playback capture should be captured.
+         *
+         * The permission {@link CAPTURE_AUDIO_OUTPUT} or {@link CAPTURE_MEDIA_OUTPUT} is needed
+         * to ignore the opt-out.
+         *
+         * Only affects LOOPBACK|RENDER mix.
+         *
+         * @return the same Builder instance.
+         */
+        public @NonNull Builder allowPrivilegedPlaybackCapture(boolean allow) {
+            mAllowPrivilegedPlaybackCapture = allow;
+            return this;
+        }
+
+        /**
          * Add or exclude a rule for the selection of which streams are mixed together.
          * Does error checking on the parameters.
          * @param rule
@@ -507,7 +534,7 @@
          * @return a new {@link AudioMixingRule} object
          */
         public AudioMixingRule build() {
-            return new AudioMixingRule(mTargetMixType, mCriteria);
+            return new AudioMixingRule(mTargetMixType, mCriteria, mAllowPrivilegedPlaybackCapture);
         }
     }
 }
diff --git a/media/java/android/media/audiopolicy/AudioPolicyConfig.java b/media/java/android/media/audiopolicy/AudioPolicyConfig.java
index a6e63c7..c4ba0c1 100644
--- a/media/java/android/media/audiopolicy/AudioPolicyConfig.java
+++ b/media/java/android/media/audiopolicy/AudioPolicyConfig.java
@@ -96,6 +96,8 @@
             dest.writeInt(mix.getFormat().getSampleRate());
             dest.writeInt(mix.getFormat().getEncoding());
             dest.writeInt(mix.getFormat().getChannelMask());
+            // write opt-out respect
+            dest.writeBoolean(mix.getRule().allowPrivilegedPlaybackCapture());
             // write mix rules
             final ArrayList<AudioMixMatchCriterion> criteria = mix.getRule().getCriteria();
             dest.writeInt(criteria.size());
@@ -124,9 +126,12 @@
             final AudioFormat format = new AudioFormat.Builder().setSampleRate(sampleRate)
                     .setChannelMask(channelMask).setEncoding(encoding).build();
             mixBuilder.setFormat(format);
+
+            AudioMixingRule.Builder ruleBuilder = new AudioMixingRule.Builder();
+            // write opt-out respect
+            ruleBuilder.allowPrivilegedPlaybackCapture(in.readBoolean());
             // read mix rules
             int nbRules = in.readInt();
-            AudioMixingRule.Builder ruleBuilder = new AudioMixingRule.Builder();
             for (int j = 0 ; j < nbRules ; j++) {
                 // read the matching rules
                 ruleBuilder.addRuleFromParcel(in);
@@ -161,7 +166,9 @@
             textDump += "  rate=" + mix.getFormat().getSampleRate() + "Hz\n";
             textDump += "  encoding=" + mix.getFormat().getEncoding() + "\n";
             textDump += "  channels=0x";
-            textDump += Integer.toHexString(mix.getFormat().getChannelMask()).toUpperCase() +"\n";
+            textDump += Integer.toHexString(mix.getFormat().getChannelMask()).toUpperCase() + "\n";
+            textDump += "  ignore playback capture opt out="
+                    + mix.getRule().allowPrivilegedPlaybackCapture() + "\n";
             // write mix rules
             final ArrayList<AudioMixMatchCriterion> criteria = mix.getRule().getCriteria();
             for (AudioMixMatchCriterion criterion : criteria) {
diff --git a/media/tests/MediaFrameworkTest/Android.bp b/media/tests/MediaFrameworkTest/Android.bp
new file mode 100644
index 0000000..f0fbc50
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/Android.bp
@@ -0,0 +1,14 @@
+android_test {
+    name: "mediaframeworktest",
+    srcs: ["**/*.java"],
+    libs: [
+        "android.test.runner",
+        "android.test.base",
+    ],
+    static_libs: [
+        "mockito-target-minus-junit4",
+        "androidx.test.rules",
+        "android-ex-camera2",
+    ],
+    platform_apis: true,
+}
diff --git a/media/tests/MediaFrameworkTest/Android.mk b/media/tests/MediaFrameworkTest/Android.mk
deleted file mode 100644
index 167d255..0000000
--- a/media/tests/MediaFrameworkTest/Android.mk
+++ /dev/null
@@ -1,18 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    mockito-target-minus-junit4 \
-    androidx.test.rules \
-    android-ex-camera2
-
-LOCAL_PACKAGE_NAME := mediaframeworktest
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-include $(BUILD_PACKAGE)
diff --git a/media/tests/MtpTests/Android.bp b/media/tests/MtpTests/Android.bp
new file mode 100644
index 0000000..7d2c7c6
--- /dev/null
+++ b/media/tests/MtpTests/Android.bp
@@ -0,0 +1,6 @@
+android_test {
+    name: "MtpTests",
+    srcs: ["**/*.java"],
+    static_libs: ["androidx.test.rules"],
+    platform_apis: true,
+}
diff --git a/media/tests/MtpTests/Android.mk b/media/tests/MtpTests/Android.mk
deleted file mode 100644
index 4cee62e..0000000
--- a/media/tests/MtpTests/Android.mk
+++ /dev/null
@@ -1,13 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_STATIC_JAVA_LIBRARIES := androidx.test.rules
-
-LOCAL_PACKAGE_NAME := MtpTests
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-include $(BUILD_PACKAGE)
diff --git a/opengl/java/android/opengl/GLUtils.java b/opengl/java/android/opengl/GLUtils.java
index d097335..ca8d5ac 100644
--- a/opengl/java/android/opengl/GLUtils.java
+++ b/opengl/java/android/opengl/GLUtils.java
@@ -44,7 +44,7 @@
         if (bitmap.isRecycled()) {
             throw new IllegalArgumentException("bitmap is recycled");
         }
-        int result = native_getInternalFormat(bitmap);
+        int result = native_getInternalFormat(bitmap.getNativeInstance());
         if (result < 0) {
             throw new IllegalArgumentException("Unknown internalformat");
         }
@@ -66,7 +66,7 @@
         if (bitmap.isRecycled()) {
             throw new IllegalArgumentException("bitmap is recycled");
         }
-        int result = native_getType(bitmap);
+        int result = native_getType(bitmap.getNativeInstance());
         if (result < 0) {
             throw new IllegalArgumentException("Unknown type");
         }
@@ -103,7 +103,8 @@
         if (bitmap.isRecycled()) {
             throw new IllegalArgumentException("bitmap is recycled");
         }
-        if (native_texImage2D(target, level, internalformat, bitmap, -1, border)!=0) {
+        if (native_texImage2D(target, level, internalformat, bitmap.getNativeInstance(), -1,
+                border) != 0) {
             throw new IllegalArgumentException("invalid Bitmap format");
         }
     }
@@ -129,7 +130,8 @@
         if (bitmap.isRecycled()) {
             throw new IllegalArgumentException("bitmap is recycled");
         }
-        if (native_texImage2D(target, level, internalformat, bitmap, type, border)!=0) {
+        if (native_texImage2D(target, level, internalformat, bitmap.getNativeInstance(), type,
+              border) != 0) {
             throw new IllegalArgumentException("invalid Bitmap format");
         }
     }
@@ -151,7 +153,7 @@
         if (bitmap.isRecycled()) {
             throw new IllegalArgumentException("bitmap is recycled");
         }
-        if (native_texImage2D(target, level, -1, bitmap, -1, border)!=0) {
+        if (native_texImage2D(target, level, -1, bitmap.getNativeInstance(), -1, border) != 0) {
             throw new IllegalArgumentException("invalid Bitmap format");
         }
     }
@@ -187,7 +189,8 @@
             throw new IllegalArgumentException("bitmap is recycled");
         }
         int type = getType(bitmap);
-        if (native_texSubImage2D(target, level, xoffset, yoffset, bitmap, -1, type)!=0) {
+        if (native_texSubImage2D(target, level, xoffset, yoffset, bitmap.getNativeInstance(), -1,
+                type) != 0) {
             throw new IllegalArgumentException("invalid Bitmap format");
         }
     }
@@ -211,7 +214,8 @@
         if (bitmap.isRecycled()) {
             throw new IllegalArgumentException("bitmap is recycled");
         }
-        if (native_texSubImage2D(target, level, xoffset, yoffset, bitmap, format, type)!=0) {
+        if (native_texSubImage2D(target, level, xoffset, yoffset, bitmap.getNativeInstance(),
+                format, type) != 0) {
             throw new IllegalArgumentException("invalid Bitmap format");
         }
     }
@@ -261,10 +265,10 @@
         }
     }
 
-    native private static int native_getInternalFormat(Bitmap bitmap);
-    native private static int native_getType(Bitmap bitmap);
+    native private static int native_getInternalFormat(long bitmapHandle);
+    native private static int native_getType(long bitmapHandle);
     native private static int native_texImage2D(int target, int level, int internalformat,
-            Bitmap bitmap, int type, int border);
+            long bitmapHandle, int type, int border);
     native private static int native_texSubImage2D(int target, int level, int xoffset, int yoffset,
-            Bitmap bitmap, int format, int type);
+            long bitmapHandle, int format, int type);
 }
diff --git a/packages/ExtServices/AndroidManifest.xml b/packages/ExtServices/AndroidManifest.xml
index 76e2fe7..d409758 100644
--- a/packages/ExtServices/AndroidManifest.xml
+++ b/packages/ExtServices/AndroidManifest.xml
@@ -26,6 +26,7 @@
 
     <uses-permission android:name="android.permission.MONITOR_DEFAULT_SMS_PACKAGE" />
     <uses-permission android:name="android.permission.REQUEST_NOTIFICATION_ASSISTANT_SERVICE" />
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
 
     <uses-sdk
         android:targetSdkVersion="28"
@@ -78,6 +79,13 @@
             </intent-filter>
         </service>
 
+        <service android:name=".watchdog.ExplicitHealthCheckServiceImpl"
+                 android:permission="android.permission.BIND_EXPLICIT_HEALTH_CHECK_SERVICE">
+            <intent-filter>
+                <action android:name="android.service.watchdog.ExplicitHealthCheckService" />
+            </intent-filter>
+        </service>
+
         <activity android:name=".notification.CopyCodeActivity"
                   android:exported="false"
                   android:theme="@android:style/Theme.NoDisplay"/>
diff --git a/packages/ExtServices/src/android/ext/services/watchdog/ExplicitHealthCheckServiceImpl.java b/packages/ExtServices/src/android/ext/services/watchdog/ExplicitHealthCheckServiceImpl.java
new file mode 100644
index 0000000..040e2ab
--- /dev/null
+++ b/packages/ExtServices/src/android/ext/services/watchdog/ExplicitHealthCheckServiceImpl.java
@@ -0,0 +1,104 @@
+/*
+ * 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.ext.services.watchdog;
+
+import android.content.ComponentName;
+import android.content.Intent;
+import android.service.watchdog.ExplicitHealthCheckService;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Routes explicit health check requests to the appropriate {@link ExplicitHealthChecker}.
+ */
+public final class ExplicitHealthCheckServiceImpl extends ExplicitHealthCheckService {
+    private static final String TAG = "ExplicitHealthCheckServiceImpl";
+    // TODO: Add build dependency on NetworkStack stable AIDL so we can stop hard coding class name
+    private static final String NETWORK_STACK_CONNECTOR_CLASS =
+            "android.net.INetworkStackConnector";
+    // Modified only #onCreate, using concurrent collection to ensure thread visibility
+    private final Map<String, ExplicitHealthChecker> mSupportedCheckers = new ConcurrentHashMap<>();
+
+    @Override
+    public void onCreate() {
+        super.onCreate();
+        initHealthCheckers();
+    }
+
+    @Override
+    public void onRequestHealthCheck(String packageName) {
+        ExplicitHealthChecker checker = mSupportedCheckers.get(packageName);
+        if (checker != null) {
+            checker.request();
+        } else {
+            Log.w(TAG, "Ignoring request for explicit health check for unsupported package "
+                    + packageName);
+        }
+    }
+
+    @Override
+    public void onCancelHealthCheck(String packageName) {
+        ExplicitHealthChecker checker = mSupportedCheckers.get(packageName);
+        if (checker != null) {
+            checker.cancel();
+        } else {
+            Log.w(TAG, "Ignoring request to cancel explicit health check for unsupported package "
+                    + packageName);
+        }
+    }
+
+    @Override
+    public List<String> onGetSupportedPackages() {
+        return new ArrayList<>(mSupportedCheckers.keySet());
+    }
+
+    @Override
+    public List<String> onGetRequestedPackages() {
+        List<String> packages = new ArrayList<>();
+        Iterator<ExplicitHealthChecker> it = mSupportedCheckers.values().iterator();
+        // Could potentially race, where we read a checker#isPending and it changes before we
+        // return list. However, if it races and it is in the list, the caller might call #cancel
+        // which would fail, but that is fine. If it races and it ends up *not* in the list, it was
+        // already cancelled, so there's no need for the caller to cancel it
+        while (it.hasNext()) {
+            ExplicitHealthChecker checker = it.next();
+            if (checker.isPending()) {
+                packages.add(checker.getPackageName());
+            }
+        }
+        return packages;
+    }
+
+    private void initHealthCheckers() {
+        Intent intent = new Intent(NETWORK_STACK_CONNECTOR_CLASS);
+        ComponentName comp = intent.resolveSystemService(getPackageManager(), 0);
+        if (comp != null) {
+            String networkStackPackageName = comp.getPackageName();
+            mSupportedCheckers.put(networkStackPackageName,
+                    new NetworkChecker(this, networkStackPackageName));
+        } else {
+            // On Go devices, or any device that does not ship the network stack module.
+            // The network stack will live in system_server process, so no need to monitor.
+            Log.i(TAG, "Network stack module not found");
+        }
+    }
+}
diff --git a/packages/ExtServices/src/android/ext/services/watchdog/ExplicitHealthChecker.java b/packages/ExtServices/src/android/ext/services/watchdog/ExplicitHealthChecker.java
new file mode 100644
index 0000000..650878e
--- /dev/null
+++ b/packages/ExtServices/src/android/ext/services/watchdog/ExplicitHealthChecker.java
@@ -0,0 +1,44 @@
+/*
+ * 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.ext.services.watchdog;
+
+/**
+ * A type of explicit health check that can be performed on a device, e.g network health check
+ */
+interface ExplicitHealthChecker {
+    /**
+     * Requests a checker to listen to explicit health checks for {@link #getPackageName}.
+     *  {@link #isPending} will now return {@code true}.
+     */
+    void request();
+
+    /**
+     * Cancels a pending explicit health check request for {@link #getPackageName}.
+     * {@link #isPending} will now return {@code false}.
+     */
+    void cancel();
+
+    /**
+     * Returns {@code true} if a request is pending, {@code false} otherwise.
+     */
+    boolean isPending();
+
+    /**
+     * Returns the package name this checker can make requests for.
+     */
+    String getPackageName();
+}
diff --git a/packages/ExtServices/src/android/ext/services/watchdog/NetworkChecker.java b/packages/ExtServices/src/android/ext/services/watchdog/NetworkChecker.java
new file mode 100644
index 0000000..32375e6
--- /dev/null
+++ b/packages/ExtServices/src/android/ext/services/watchdog/NetworkChecker.java
@@ -0,0 +1,92 @@
+/*
+ * 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.ext.services.watchdog;
+
+import android.net.ConnectivityManager;
+import android.net.Network;
+import android.net.NetworkCapabilities;
+import android.net.NetworkRequest;
+import android.service.watchdog.ExplicitHealthCheckService;
+
+import com.android.internal.annotations.GuardedBy;
+
+/**
+ * Observes the network stack via the ConnectivityManager.
+ */
+final class NetworkChecker extends ConnectivityManager.NetworkCallback
+        implements ExplicitHealthChecker {
+    private static final String TAG = "NetworkChecker";
+
+    private final Object mLock = new Object();
+    private final ExplicitHealthCheckService mService;
+    private final String mPackageName;
+    @GuardedBy("mLock")
+    private boolean mIsPending;
+
+    NetworkChecker(ExplicitHealthCheckService service, String packageName) {
+        mService = service;
+        mPackageName = packageName;
+    }
+
+    @Override
+    public void request() {
+        synchronized (mLock) {
+            if (mIsPending) {
+                return;
+            }
+            mService.getSystemService(ConnectivityManager.class).registerNetworkCallback(
+                    new NetworkRequest.Builder().build(), this);
+            mIsPending = true;
+        }
+    }
+
+    @Override
+    public void cancel() {
+        synchronized (mLock) {
+            if (!mIsPending) {
+                return;
+            }
+            mService.getSystemService(ConnectivityManager.class).unregisterNetworkCallback(this);
+            mIsPending = false;
+        }
+    }
+
+    @Override
+    public boolean isPending() {
+        synchronized (mLock) {
+            return mIsPending;
+        }
+    }
+
+    @Override
+    public String getPackageName() {
+        return mPackageName;
+    }
+
+    // TODO(b/120598832): Also monitor NetworkCallback#onAvailable to see if we have any
+    // available networks that may be unusable. This could be additional signal to our heuristics
+    @Override
+    public void onCapabilitiesChanged(Network network, NetworkCapabilities capabilities) {
+        synchronized (mLock) {
+            if (mIsPending
+                    && capabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)) {
+                mService.notifyHealthCheckPassed(mPackageName);
+                cancel();
+            }
+        }
+    }
+}
diff --git a/packages/NetworkStack/Android.bp b/packages/NetworkStack/Android.bp
index 52534a8..0bd5c5f 100644
--- a/packages/NetworkStack/Android.bp
+++ b/packages/NetworkStack/Android.bp
@@ -49,6 +49,9 @@
     // Resources already included in NetworkStackBase
     resource_dirs: [],
     jarjar_rules: "jarjar-rules-shared.txt",
+    optimize: {
+        proguard_flags_files: ["proguard.flags"],
+    },
     // The permission configuration *must* be included to ensure security of the device
     required: ["NetworkStackPermissionStub"],
 }
diff --git a/packages/NetworkStack/AndroidManifest.xml b/packages/NetworkStack/AndroidManifest.xml
index b0a7923..9b60dc3 100644
--- a/packages/NetworkStack/AndroidManifest.xml
+++ b/packages/NetworkStack/AndroidManifest.xml
@@ -20,6 +20,17 @@
           package="com.android.networkstack"
           android:sharedUserId="android.uid.networkstack">
     <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="28" />
+
+    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+    <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
+    <!-- Send latency broadcast as current user -->
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
+    <uses-permission android:name="android.permission.WAKE_LOCK" />
+    <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
+
     <!-- Signature permission defined in NetworkStackStub -->
     <uses-permission android:name="android.permission.MAINLINE_NETWORK_STACK" />
     <application>
diff --git a/packages/NetworkStack/AndroidManifestBase.xml b/packages/NetworkStack/AndroidManifestBase.xml
index f69e4b2..69a4da4 100644
--- a/packages/NetworkStack/AndroidManifestBase.xml
+++ b/packages/NetworkStack/AndroidManifestBase.xml
@@ -20,15 +20,6 @@
           package="com.android.networkstack"
           android:versionCode="11"
           android:versionName="Q-initial">
-    <uses-permission android:name="android.permission.INTERNET" />
-    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
-    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
-    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
-    <uses-permission android:name="android.permission.CONNECTIVITY_INTERNAL" />
-    <!-- Send latency broadcast as current user -->
-    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
-    <uses-permission android:name="android.permission.WAKE_LOCK" />
-    <uses-permission android:name="android.permission.READ_PRIVILEGED_PHONE_STATE" />
     <application
         android:label="NetworkStack"
         android:defaultToDeviceProtectedStorage="true"
diff --git a/packages/NetworkStack/proguard.flags b/packages/NetworkStack/proguard.flags
new file mode 100644
index 0000000..c60f6c3
--- /dev/null
+++ b/packages/NetworkStack/proguard.flags
@@ -0,0 +1,9 @@
+-keepclassmembers class android.net.ip.IpClient {
+    static final int CMD_*;
+    static final int EVENT_*;
+}
+
+-keepclassmembers class android.net.dhcp.DhcpClient {
+    static final int CMD_*;
+    static final int EVENT_*;
+}
diff --git a/packages/NetworkStack/src/android/net/apf/ApfFilter.java b/packages/NetworkStack/src/android/net/apf/ApfFilter.java
index 3dd90ee..d2f3259 100644
--- a/packages/NetworkStack/src/android/net/apf/ApfFilter.java
+++ b/packages/NetworkStack/src/android/net/apf/ApfFilter.java
@@ -74,6 +74,7 @@
 import java.net.UnknownHostException;
 import java.nio.BufferUnderflowException;
 import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
 import java.util.ArrayList;
 import java.util.Arrays;
 
@@ -282,6 +283,7 @@
     private static final byte[] ETH_BROADCAST_MAC_ADDRESS =
             {(byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff, (byte) 0xff };
     // TODO: Make these offsets relative to end of link-layer header; don't include ETH_HEADER_LEN.
+    private static final int IPV4_TOTAL_LENGTH_OFFSET = ETH_HEADER_LEN + 2;
     private static final int IPV4_FRAGMENT_OFFSET_OFFSET = ETH_HEADER_LEN + 6;
     // Endianness is not an issue for this constant because the APF interpreter always operates in
     // network byte order.
@@ -881,10 +883,23 @@
 
         protected final TcpKeepaliveAckData mPacket;
         protected final byte[] mSrcDstAddr;
+        protected final byte[] mPortSeqAckFingerprint;
 
         TcpKeepaliveAck(final TcpKeepaliveAckData packet, final byte[] srcDstAddr) {
             mPacket = packet;
             mSrcDstAddr = srcDstAddr;
+            mPortSeqAckFingerprint = generatePortSeqAckFingerprint(mPacket.srcPort,
+                    mPacket.dstPort, mPacket.seq, mPacket.ack);
+        }
+
+        static byte[] generatePortSeqAckFingerprint(int srcPort, int dstPort, int seq, int ack) {
+            final ByteBuffer fp = ByteBuffer.allocate(12);
+            fp.order(ByteOrder.BIG_ENDIAN);
+            fp.putShort((short) srcPort);
+            fp.putShort((short) dstPort);
+            fp.putInt(seq);
+            fp.putInt(ack);
+            return fp.array();
         }
 
         static byte[] concatArrays(final byte[]... arr) {
@@ -919,10 +934,6 @@
 
     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));
@@ -934,12 +945,12 @@
         @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 :
+            // Skip to the next filter if it's not zero-sized :
+            // TCP_HEADER_SIZE + IPV4_HEADER_SIZE - ipv4_total_length == 0
             // 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)
@@ -947,27 +958,18 @@
             // 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
+            // R0 += R1 -> R0 contains TCP + IP headers length
             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);
+            // Load IPv4 total length
+            gen.addLoad16(Register.R1, IPV4_TOTAL_LENGTH_OFFSET);
             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);
+            gen.addLoadImmediate(Register.R0, ETH_HEADER_LEN);
+            gen.addAddR1();
+            gen.addJumpIfBytesNotEqual(Register.R0, mPortSeqAckFingerprint, nextFilterLabel);
 
             maybeSetupCounter(gen, Counter.DROPPED_IPV4_KEEPALIVE_ACK);
             gen.addJump(mCountAndDropLabel);
@@ -1169,9 +1171,10 @@
                 gen.addJumpIfR0Equals(broadcastAddr, mCountAndDropLabel);
             }
 
-            // If any keepalive filters,
-            generateKeepaliveFilter(gen);
+            // If any keepalive filter matches, drop
+            generateV4KeepaliveFilters(gen);
 
+            // Otherwise, this is an IPv4 unicast, pass
             // 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);
@@ -1180,7 +1183,7 @@
             maybeSetupCounter(gen, Counter.DROPPED_IPV4_L2_BROADCAST);
             gen.addJump(mCountAndDropLabel);
         } else {
-            generateKeepaliveFilter(gen);
+            generateV4KeepaliveFilters(gen);
         }
 
         // Otherwise, pass
@@ -1188,12 +1191,25 @@
         gen.addJump(mCountAndPassLabel);
     }
 
-    private void generateKeepaliveFilter(ApfGenerator gen) throws IllegalInstructionException {
+    private void generateV4KeepaliveFilters(ApfGenerator gen) throws IllegalInstructionException {
+        final String skipV4KeepaliveFilter = "skip_v4_keepalive_filter";
+        final boolean haveV4KeepaliveAcks = NetworkStackUtils.any(mKeepaliveAcks,
+                ack -> ack instanceof TcpKeepaliveAckV4);
+
+        // If no keepalive acks
+        if (!haveV4KeepaliveAcks) return;
+
+        // If not tcp, skip keepalive filters
+        gen.addLoad8(Register.R0, IPV4_PROTOCOL_OFFSET);
+        gen.addJumpIfR0NotEquals(IPPROTO_TCP, skipV4KeepaliveFilter);
+
         // 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);
         }
+
+        gen.defineLabel(skipV4KeepaliveFilter);
     }
 
     /**
@@ -1244,11 +1260,14 @@
             maybeSetupCounter(gen, Counter.DROPPED_IPV6_NON_ICMP_MULTICAST);
             gen.addLoad8(Register.R0, IPV6_DEST_ADDR_OFFSET);
             gen.addJumpIfR0Equals(0xff, mCountAndDropLabel);
+            // If any keepalive filter matches, drop
+            generateV6KeepaliveFilters(gen);
             // Not multicast. Pass.
             maybeSetupCounter(gen, Counter.PASSED_IPV6_UNICAST_NON_ICMP);
             gen.addJump(mCountAndPassLabel);
             gen.defineLabel(skipIPv6MulticastFilterLabel);
         } else {
+            generateV6KeepaliveFilters(gen);
             // If not ICMPv6, pass.
             maybeSetupCounter(gen, Counter.PASSED_IPV6_NON_ICMP);
             gen.addJumpIfR0NotEquals(IPPROTO_ICMPV6, mCountAndPassLabel);
@@ -1272,12 +1291,27 @@
         maybeSetupCounter(gen, Counter.DROPPED_IPV6_MULTICAST_NA);
         gen.addJump(mCountAndDropLabel);
         gen.defineLabel(skipUnsolicitedMulticastNALabel);
+    }
+
+    private void generateV6KeepaliveFilters(ApfGenerator gen) throws IllegalInstructionException {
+        final String skipV6KeepaliveFilter = "skip_v6_keepalive_filter";
+        final boolean haveV6KeepaliveAcks = NetworkStackUtils.any(mKeepaliveAcks,
+                ack -> ack instanceof TcpKeepaliveAckV6);
+
+        // If no keepalive acks
+        if (!haveV6KeepaliveAcks) return;
+
+        // If not tcp, skip keepalive filters
+        gen.addLoad8(Register.R0, IPV6_NEXT_HEADER_OFFSET);
+        gen.addJumpIfR0NotEquals(IPPROTO_TCP, skipV6KeepaliveFilter);
 
         // 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);
         }
+
+        gen.defineLabel(skipV6KeepaliveFilter);
     }
 
     /**
@@ -1294,6 +1328,8 @@
      * <li>Pass all non-IPv4 and non-IPv6 packets,
      * <li>Drop IPv6 ICMPv6 NAs to ff02::1.
      * <li>Drop IPv6 ICMPv6 RSs.
+     * <li>Filter IPv4 packets (see generateIPv4FilterLocked())
+     * <li>Filter IPv6 packets (see generateIPv6FilterLocked())
      * <li>Let execution continue off the end of the program for IPv6 ICMPv6 packets. This allows
      *     insertion of RA filters here, or if there aren't any, just passes the packets.
      * </ul>
@@ -1737,7 +1773,7 @@
         }
         pw.decreaseIndent();
 
-        pw.println("Keepalive filter:");
+        pw.println("Keepalive filters:");
         pw.increaseIndent();
         for (int i = 0; i < mKeepaliveAcks.size(); ++i) {
             final TcpKeepaliveAck keepaliveAck = mKeepaliveAcks.valueAt(i);
diff --git a/packages/NetworkStack/src/android/net/apf/ApfGenerator.java b/packages/NetworkStack/src/android/net/apf/ApfGenerator.java
index 809327a..44ce2db 100644
--- a/packages/NetworkStack/src/android/net/apf/ApfGenerator.java
+++ b/packages/NetworkStack/src/android/net/apf/ApfGenerator.java
@@ -108,7 +108,7 @@
         private String mLabel;
         // When mOpcode == Opcodes.JNEBS:
         private byte[] mCompareBytes;
-        // Offset in bytes from the begining of this program. Set by {@link ApfGenerator#generate}.
+        // Offset in bytes from the beginning of this program. Set by {@link ApfGenerator#generate}.
         int offset;
 
         Instruction(Opcodes opcode, Register register) {
@@ -431,7 +431,7 @@
 
     /**
      * Add an instruction to the end of the program to load the byte at offset {@code offset}
-     * bytes from the begining of the packet into {@code register}.
+     * bytes from the beginning of the packet into {@code register}.
      */
     public ApfGenerator addLoad8(Register register, int offset) {
         Instruction instruction = new Instruction(Opcodes.LDB, register);
@@ -442,7 +442,7 @@
 
     /**
      * Add an instruction to the end of the program to load 16-bits at offset {@code offset}
-     * bytes from the begining of the packet into {@code register}.
+     * bytes from the beginning of the packet into {@code register}.
      */
     public ApfGenerator addLoad16(Register register, int offset) {
         Instruction instruction = new Instruction(Opcodes.LDH, register);
@@ -453,7 +453,7 @@
 
     /**
      * Add an instruction to the end of the program to load 32-bits at offset {@code offset}
-     * bytes from the begining of the packet into {@code register}.
+     * bytes from the beginning of the packet into {@code register}.
      */
     public ApfGenerator addLoad32(Register register, int offset) {
         Instruction instruction = new Instruction(Opcodes.LDW, register);
@@ -464,7 +464,7 @@
 
     /**
      * Add an instruction to the end of the program to load a byte from the packet into
-     * {@code register}. The offset of the loaded byte from the begining of the packet is
+     * {@code register}. The offset of the loaded byte from the beginning of the packet is
      * the sum of {@code offset} and the value in register R1.
      */
     public ApfGenerator addLoad8Indexed(Register register, int offset) {
diff --git a/packages/NetworkStack/src/android/net/dhcp/DhcpClient.java b/packages/NetworkStack/src/android/net/dhcp/DhcpClient.java
index c6dd0117..79d6a55 100644
--- a/packages/NetworkStack/src/android/net/dhcp/DhcpClient.java
+++ b/packages/NetworkStack/src/android/net/dhcp/DhcpClient.java
@@ -126,6 +126,7 @@
     // DhcpClient uses IpClient's handler.
     private static final int PUBLIC_BASE = IpClient.DHCPCLIENT_CMD_BASE;
 
+    // Below constants are picked up by MessageUtils and exempt from ProGuard optimization.
     /* Commands from controller to start/stop DHCP */
     public static final int CMD_START_DHCP                  = PUBLIC_BASE + 1;
     public static final int CMD_STOP_DHCP                   = PUBLIC_BASE + 2;
diff --git a/packages/NetworkStack/src/android/net/ip/IpClient.java b/packages/NetworkStack/src/android/net/ip/IpClient.java
index 346ac68..7a06af4 100644
--- a/packages/NetworkStack/src/android/net/ip/IpClient.java
+++ b/packages/NetworkStack/src/android/net/ip/IpClient.java
@@ -282,6 +282,7 @@
 
     public static final String DUMP_ARG_CONFIRM = "confirm";
 
+    // Below constants are picked up by MessageUtils and exempt from ProGuard optimization.
     private static final int CMD_TERMINATE_AFTER_STOP             = 1;
     private static final int CMD_STOP                             = 2;
     private static final int CMD_START                            = 3;
diff --git a/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java b/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java
index 481dbda..fedb8d1 100644
--- a/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java
+++ b/packages/NetworkStack/src/android/net/util/NetworkStackUtils.java
@@ -17,10 +17,13 @@
 package android.net.util;
 
 import android.annotation.NonNull;
+import android.util.SparseArray;
 
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.util.List;
+import java.util.function.Predicate;
+
 
 /**
  * Collection of utilities for the network stack.
@@ -65,4 +68,17 @@
         }
         return array;
     }
+
+    /**
+     * @return True if there exists at least one element in the sparse array for which
+     * condition {@code predicate}
+     */
+    public static <T> boolean any(SparseArray<T> array, Predicate<T> predicate) {
+        for (int i = 0; i < array.size(); ++i) {
+            if (predicate.test(array.valueAt(i))) {
+                return true;
+            }
+        }
+        return false;
+    }
 }
diff --git a/packages/NetworkStack/tests/Android.bp b/packages/NetworkStack/tests/Android.bp
index aadf99e..0535af3 100644
--- a/packages/NetworkStack/tests/Android.bp
+++ b/packages/NetworkStack/tests/Android.bp
@@ -45,6 +45,8 @@
         "libcrypto",
         "libcutils",
         "libdexfile",
+        "ld-android",
+        "libdl_android",
         "libhidl-gen-utils",
         "libhidlbase",
         "libhidltransport",
diff --git a/packages/NetworkStack/tests/src/android/net/apf/ApfTest.java b/packages/NetworkStack/tests/src/android/net/apf/ApfTest.java
index 88a05d5..a0e508f 100644
--- a/packages/NetworkStack/tests/src/android/net/apf/ApfTest.java
+++ b/packages/NetworkStack/tests/src/android/net/apf/ApfTest.java
@@ -1006,7 +1006,7 @@
 
     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_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;
diff --git a/packages/OsuLogin/res/values/strings.xml b/packages/OsuLogin/res/values/strings.xml
index 06fa8c7..14de0f5 100644
--- a/packages/OsuLogin/res/values/strings.xml
+++ b/packages/OsuLogin/res/values/strings.xml
@@ -3,4 +3,6 @@
     <string name="app_name">OsuLogin</string>
     <!-- action bar label [CHAR LIMIT=32] -->
     <string name="action_bar_label">Online Sign Up</string>
+    <!-- toast message [CHAR LIMIT=32] -->
+    <string name="sign_up_failed">Sign-up failed</string>
 </resources>
diff --git a/packages/OsuLogin/src/com/android/hotspot2/osu/OsuLoginActivity.java b/packages/OsuLogin/src/com/android/hotspot2/osu/OsuLoginActivity.java
index 82e33cc..416894b 100644
--- a/packages/OsuLogin/src/com/android/hotspot2/osu/OsuLoginActivity.java
+++ b/packages/OsuLogin/src/com/android/hotspot2/osu/OsuLoginActivity.java
@@ -38,6 +38,7 @@
 import android.webkit.WebView;
 import android.webkit.WebViewClient;
 import android.widget.ProgressBar;
+import android.widget.Toast;
 
 import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
 
@@ -141,6 +142,7 @@
                     Log.d(TAG, "Lost for the current Network, close the browser");
                 }
                 mForceDisconnect = false; // It is already disconnected.
+                showSignUpFailedToast();
                 if (mNetwork.equals(network)) {
                     finishAndRemoveTask();
                 }
@@ -229,6 +231,11 @@
         return "";
     }
 
+    private void showSignUpFailedToast() {
+        Toast.makeText(getApplicationContext(), R.string.sign_up_failed,
+                Toast.LENGTH_SHORT).show();
+    }
+
     private class OsuWebViewClient extends WebViewClient {
         boolean mPageError = false;
         boolean mRedirectResponseReceived = false;
diff --git a/packages/PackageInstaller/Android.bp b/packages/PackageInstaller/Android.bp
new file mode 100644
index 0000000..9420954
--- /dev/null
+++ b/packages/PackageInstaller/Android.bp
@@ -0,0 +1,28 @@
+// 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.
+
+android_app {
+    name: "PackageInstaller",
+
+    srcs: ["src/**/*.java"],
+
+    certificate: "platform",
+    privileged: true,
+    platform_apis: true,
+
+    static_libs: [
+        "xz-java",
+        "androidx.leanback_leanback",
+    ],
+}
diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
index 441dbac..bde1b25 100644
--- a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
+++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java
@@ -26,6 +26,7 @@
 import android.app.AppOpsManager;
 import android.app.Dialog;
 import android.app.DialogFragment;
+import android.app.admin.DevicePolicyManager;
 import android.content.ActivityNotFoundException;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -427,7 +428,7 @@
         if (mAllowUnknownSources || !isInstallRequestFromUnknownSource(getIntent())) {
             initiateInstall();
         } else {
-            // Check for unknown sources restriction
+            // Check for unknown sources restrictions.
             final int unknownSourcesRestrictionSource = mUserManager.getUserRestrictionSource(
                     UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, Process.myUserHandle());
             final int unknownSourcesGlobalRestrictionSource = mUserManager.getUserRestrictionSource(
@@ -436,16 +437,28 @@
                     & (unknownSourcesRestrictionSource | unknownSourcesGlobalRestrictionSource);
             if (systemRestriction != 0) {
                 showDialogInner(DLG_UNKNOWN_SOURCES_RESTRICTED_FOR_USER);
-            } else if (unknownSourcesRestrictionSource != UserManager.RESTRICTION_NOT_SET
-                    || unknownSourcesGlobalRestrictionSource != UserManager.RESTRICTION_NOT_SET) {
-                startActivity(new Intent(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS));
-                finish();
+            } else if (unknownSourcesRestrictionSource != UserManager.RESTRICTION_NOT_SET) {
+                startAdminSupportDetailsActivity(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);
+            } else if (unknownSourcesGlobalRestrictionSource != UserManager.RESTRICTION_NOT_SET) {
+                startAdminSupportDetailsActivity(
+                        UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES_GLOBALLY);
             } else {
                 handleUnknownSources();
             }
         }
     }
 
+    private void startAdminSupportDetailsActivity(String restriction) {
+        // If the given restriction is set by an admin, display information about the
+        // admin enforcing the restriction for the affected user.
+        final DevicePolicyManager dpm = getSystemService(DevicePolicyManager.class);
+        final Intent showAdminSupportDetailsIntent = dpm.createAdminSupportIntent(restriction);
+        if (showAdminSupportDetailsIntent != null) {
+            startActivity(showAdminSupportDetailsIntent);
+        }
+        finish();
+    }
+
     private void handleUnknownSources() {
         if (mOriginatingPackage == null) {
             Log.i(TAG, "No source found for package " + mPkgInfo.packageName);
diff --git a/packages/SettingsLib/BarChartPreference/res/layout/settings_bar_chart.xml b/packages/SettingsLib/BarChartPreference/res/layout/settings_bar_chart.xml
index 814246f..9b3d1df 100644
--- a/packages/SettingsLib/BarChartPreference/res/layout/settings_bar_chart.xml
+++ b/packages/SettingsLib/BarChartPreference/res/layout/settings_bar_chart.xml
@@ -20,8 +20,8 @@
     xmlns:settings="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
-    android:layout_marginStart="16dp"
-    android:layout_marginEnd="16dp"
+    android:layout_marginStart="10dp"
+    android:layout_marginEnd="10dp"
     android:gravity="center"
     android:orientation="vertical">
 
@@ -47,19 +47,19 @@
             <com.android.settingslib.widget.BarView
                 android:id="@+id/bar_view1"
                 style="@style/BarViewStyle"
-                settings:barColor="#FA7B17"/>
+                settings:barColor="#A142F4"/>
             <com.android.settingslib.widget.BarView
                 android:id="@+id/bar_view2"
                 style="@style/BarViewStyle"
-                settings:barColor="#F439A0"/>
+                settings:barColor="#24C1E0"/>
             <com.android.settingslib.widget.BarView
                 android:id="@+id/bar_view3"
                 style="@style/BarViewStyle"
-                settings:barColor="#A142F4"/>
+                settings:barColor="#4285F4"/>
             <com.android.settingslib.widget.BarView
                 android:id="@+id/bar_view4"
                 style="@style/BarViewStyle"
-                settings:barColor="#24C1E0"/>
+                settings:barColor="#009688"/>
         </LinearLayout>
 
         <Button
diff --git a/packages/SettingsLib/BarChartPreference/res/layout/settings_bar_view.xml b/packages/SettingsLib/BarChartPreference/res/layout/settings_bar_view.xml
index 4bc68b3..093c5de 100644
--- a/packages/SettingsLib/BarChartPreference/res/layout/settings_bar_view.xml
+++ b/packages/SettingsLib/BarChartPreference/res/layout/settings_bar_view.xml
@@ -32,15 +32,13 @@
         android:layout_width="@dimen/settings_bar_view_icon_size"
         android:layout_height="@dimen/settings_bar_view_icon_size"
         android:scaleType="fitCenter"
-        android:layout_marginTop="12dp"
-        android:layout_marginBottom="12dp"/>
+        android:layout_marginTop="12dp"/>
 
     <TextView
         android:id="@+id/bar_title"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_marginTop="10dp"
-        android:layout_marginBottom="2dp"
+        android:layout_marginTop="12dp"
         android:singleLine="true"
         android:ellipsize="marquee"
         android:textAppearance="@style/BarChart.Text.Title"/>
@@ -49,6 +47,7 @@
         android:id="@+id/bar_summary"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
+        android:layout_marginTop="4dp"
         android:layout_marginBottom="12dp"
         android:singleLine="true"
         android:ellipsize="marquee"
diff --git a/packages/SettingsLib/BarChartPreference/res/values/styles.xml b/packages/SettingsLib/BarChartPreference/res/values/styles.xml
index 5587928..094f8aa 100644
--- a/packages/SettingsLib/BarChartPreference/res/values/styles.xml
+++ b/packages/SettingsLib/BarChartPreference/res/values/styles.xml
@@ -35,12 +35,12 @@
     </style>
 
     <style name="BarChart.Text.Title">
-        <item name="android:textSize">22sp</item>
+        <item name="android:textSize">14sp</item>
     </style>
 
     <style name="BarChart.Text.Summary"
-           parent="@android:style/TextAppearance.Material.Body1">
+           parent="@*android:style/TextAppearance.DeviceDefault.Body1">
         <item name="android:textColor">?android:attr/textColorSecondary</item>
-        <item name="android:textSize">14sp</item>
+        <item name="android:textSize">12sp</item>
     </style>
 </resources>
\ No newline at end of file
diff --git a/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarView.java b/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarView.java
index 03dfd3e..fccb719 100644
--- a/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarView.java
+++ b/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarView.java
@@ -71,8 +71,7 @@
         //Set height of bar view
         mBarView.getLayoutParams().height = barViewInfo.getNormalizedHeight();
         mIcon.setImageDrawable(barViewInfo.getIcon());
-        // For now, we use the bar number as title.
-        mBarTitle.setText(Integer.toString(barViewInfo.getHeight()));
+        mBarTitle.setText(barViewInfo.getTitle());
         mBarSummary.setText(barViewInfo.getSummary());
         mIcon.setContentDescription(barViewInfo.getContentDescription());
     }
diff --git a/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarViewInfo.java b/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarViewInfo.java
index 1ef36a2..922337a 100644
--- a/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarViewInfo.java
+++ b/packages/SettingsLib/BarChartPreference/src/com/android/settingslib/widget/BarViewInfo.java
@@ -21,7 +21,6 @@
 
 import androidx.annotation.IntRange;
 import androidx.annotation.Nullable;
-import androidx.annotation.StringRes;
 
 import java.util.Comparator;
 
@@ -32,8 +31,8 @@
 
     private final Drawable mIcon;
     private View.OnClickListener mClickListener;
-    @StringRes
-    private int mSummary;
+    private CharSequence mTitle;
+    private CharSequence mSummary;
     private @Nullable CharSequence mContentDescription;
     // A number indicates this bar's height. The larger number shows a higher bar view.
     private int mHeight;
@@ -45,13 +44,16 @@
      *
      * @param icon      The icon of bar view.
      * @param barHeight The height of bar view. Larger number shows a higher bar view.
-     * @param summary   The string resource id for summary.
+     * @param title     The string for title.  If this is null, use the height of the bar.
+     * @param summary   The string for summary.
      * @param contentDescription Optional text that briefly describes the contents of the icon.
      */
-    public BarViewInfo(Drawable icon, @IntRange(from = 0) int barHeight, @StringRes int summary,
+    public BarViewInfo(Drawable icon, @IntRange(from = 0) int barHeight,
+            @Nullable CharSequence title, CharSequence summary,
             @Nullable CharSequence contentDescription) {
         mIcon = icon;
         mHeight = barHeight;
+        mTitle = title;
         mSummary = summary;
         mContentDescription = contentDescription;
     }
@@ -74,8 +76,12 @@
         mHeight = height;
     }
 
-    void setSummary(@StringRes int resId) {
-        mSummary = resId;
+    void setTitle(CharSequence title) {
+        mTitle = title;
+    }
+
+    void setSummary(CharSequence summary) {
+        mSummary = summary;
     }
 
     Drawable getIcon() {
@@ -90,8 +96,12 @@
         return mClickListener;
     }
 
-    @StringRes
-    int getSummary() {
+    @Nullable
+    CharSequence getTitle() {
+        return mTitle;
+    }
+
+    CharSequence getSummary() {
         return mSummary;
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java
index b025df4..530c73a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/BatterySaverUtils.java
@@ -31,7 +31,9 @@
  * Utilities related to battery saver.
  */
 public class BatterySaverUtils {
+
     private static final String TAG = "BatterySaverUtils";
+    public static final String EXTRA_CONFIRM_ONLY = "extra_confirm_only";
 
     private BatterySaverUtils() {
     }
@@ -96,7 +98,7 @@
         }
         final ContentResolver cr = context.getContentResolver();
 
-        if (enable && needFirstTimeWarning && maybeShowBatterySaverConfirmation(context)) {
+        if (enable && needFirstTimeWarning && maybeShowBatterySaverConfirmation(context, false)) {
             return false;
         }
         if (enable && !needFirstTimeWarning) {
@@ -116,7 +118,7 @@
                         && Global.getInt(cr, Global.LOW_POWER_MODE_TRIGGER_LEVEL, 0) == 0
                         && Secure.getInt(cr,
                         Secure.SUPPRESS_AUTO_BATTERY_SAVER_SUGGESTION, 0) == 0) {
-                    showAutoBatterySaverSuggestion(context);
+                    showAutoBatterySaverSuggestion(context, false);
                 }
             }
 
@@ -125,23 +127,36 @@
         return false;
     }
 
-    private static boolean maybeShowBatterySaverConfirmation(Context context) {
+    /**
+     * Shows the battery saver confirmation warning if it hasn't been acknowledged by the user in
+     * the past before. When confirmOnly is true, the dialog will have generic info about battery
+     * saver but will only update that the user has been shown the notification and take no
+     * further action. if confirmOnly is false it will show a more specific version of the dialog
+     * that toggles battery saver when acknowledged
+     * @param context A valid context
+     * @param confirmOnly Whether to show the actionless generic dialog (true) or the specific one
+     * that toggles battery saver (false)
+     * @return True if it showed the notification because it has not been previously acknowledged.
+     */
+    public static boolean maybeShowBatterySaverConfirmation(Context context, boolean confirmOnly) {
         if (Secure.getInt(context.getContentResolver(),
                 Secure.LOW_POWER_WARNING_ACKNOWLEDGED, 0) != 0) {
             return false; // Already shown.
         }
-        context.sendBroadcast(getSystemUiBroadcast(ACTION_SHOW_START_SAVER_CONFIRMATION));
+        context.sendBroadcast(
+                getSystemUiBroadcast(ACTION_SHOW_START_SAVER_CONFIRMATION, confirmOnly));
         return true;
     }
 
-    private static void showAutoBatterySaverSuggestion(Context context) {
-        context.sendBroadcast(getSystemUiBroadcast(ACTION_SHOW_AUTO_SAVER_SUGGESTION));
+    private static void showAutoBatterySaverSuggestion(Context context, boolean confirmOnly) {
+        context.sendBroadcast(getSystemUiBroadcast(ACTION_SHOW_AUTO_SAVER_SUGGESTION, confirmOnly));
     }
 
-    private static Intent getSystemUiBroadcast(String action) {
+    private static Intent getSystemUiBroadcast(String action, boolean confirmOnly) {
         final Intent i = new Intent(action);
         i.setFlags(Intent.FLAG_RECEIVER_FOREGROUND);
         i.setPackage(SYSUI_PACKAGE);
+        i.putExtra(EXTRA_CONFIRM_ONLY, confirmOnly);
         return i;
     }
 
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAccessesTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAccessesTest.java
index c1c5fa9..5d2a0d1d 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAccessesTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/location/RecentLocationAccessesTest.java
@@ -16,9 +16,10 @@
 import android.os.Process;
 import android.os.UserHandle;
 import android.os.UserManager;
-
 import android.util.LongSparseLongArray;
+
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
@@ -83,6 +84,7 @@
     }
 
     @Test
+    @Ignore
     public void testGetAppList_shouldFilterRecentAccesses() {
         List<RecentLocationAccesses.Access> requests = mRecentLocationAccesses.getAppList();
         // Only two of the apps have requested location within 15 min.
@@ -95,6 +97,7 @@
     }
 
     @Test
+    @Ignore
     public void testGetAppList_shouldNotShowAndroidOS() throws NameNotFoundException {
         // Add android OS to the list of apps.
         PackageOps androidSystemPackageOps =
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BarChartInfoTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BarChartInfoTest.java
index 2b27248..7faac7a 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BarChartInfoTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BarChartInfoTest.java
@@ -39,6 +39,8 @@
     private final int mDetails = 0x22222222;
     @StringRes
     private final int mEmptyText = 0x33333333;
+    private final CharSequence mTitleStr = "title";
+    private final CharSequence mSummaryStr = "summary";
     private final View.OnClickListener mClickListener = v -> {
     };
 
@@ -72,7 +74,8 @@
         final BarViewInfo barViewInfo = new BarViewInfo(
                 null /* icon */,
                 50,
-                mTitle,
+                mTitleStr,
+                mSummaryStr,
                 null);
 
         final BarChartInfo mBarChartInfo = new BarChartInfo.Builder()
@@ -92,7 +95,8 @@
         final BarViewInfo barViewInfo = new BarViewInfo(
                 null /* icon */,
                 50,
-                mTitle,
+                mTitleStr,
+                mSummaryStr,
                 null);
         final BarChartInfo mBarChartInfo = new BarChartInfo.Builder()
                 .setTitle(mTitle)
@@ -115,7 +119,8 @@
         final BarViewInfo barViewInfo = new BarViewInfo(
                 null /* icon */,
                 50,
-                mTitle,
+                mTitleStr,
+                mSummaryStr,
                 null);
         new BarChartInfo.Builder()
                 .setTitle(mTitle)
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BarChartPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BarChartPreferenceTest.java
index 266554b..567d90f 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BarChartPreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/BarChartPreferenceTest.java
@@ -39,6 +39,8 @@
 
     @Rule
     public final ExpectedException thrown = ExpectedException.none();
+    private final CharSequence mTitleStr = "title";
+    private final CharSequence mSummaryStr = "summary";
 
     private Context mContext;
     private View mBarChartView;
@@ -114,7 +116,9 @@
                 .setTitle(R.string.debug_app)
                 .setDetails(R.string.debug_app)
                 .addBarViewInfo(
-                        new BarViewInfo(mIcon, 10 /* barNumber */, R.string.debug_app, null))
+                        new BarViewInfo(mIcon, 10, null /* title */,
+                                mContext.getText(R.string.debug_app) /* summary */,
+                                null /* contentDescription */))
                 .build();
 
         mPreference.initializeBarChart(barChartInfo);
@@ -130,7 +134,9 @@
         final BarChartInfo barChartInfo = new BarChartInfo.Builder()
                 .setTitle(R.string.debug_app)
                 .addBarViewInfo(
-                        new BarViewInfo(mIcon, 10 /* barNumber */, R.string.debug_app, null))
+                        new BarViewInfo(mIcon, 10, null /* title */,
+                                mContext.getText(R.string.debug_app) /* summary */,
+                                null /* contentDescription */))
                 .build();
 
         mPreference.initializeBarChart(barChartInfo);
@@ -147,7 +153,9 @@
                 .setDetailsOnClickListener(v -> {
                 })
                 .addBarViewInfo(
-                        new BarViewInfo(mIcon, 10 /* barNumber */, R.string.debug_app, null))
+                        new BarViewInfo(mIcon, 10, null /* title */,
+                                mContext.getText(R.string.debug_app) /* summary */,
+                                null /* contentDescription */))
                 .build();
 
         mPreference.initializeBarChart(barChartInfo);
@@ -160,7 +168,7 @@
     @Test
     public void setBarViewInfos_oneBarViewInfoSet_shouldShowOneBarView() {
         final BarViewInfo[] barViewsInfo = new BarViewInfo[]{
-                new BarViewInfo(mIcon, 10 /* barNumber */, R.string.debug_app, null)
+                new BarViewInfo(mIcon, 10, mTitleStr, mSummaryStr, null /* contentDescription */)
         };
 
         mPreference.initializeBarChart(mBarChartInfo);
@@ -168,7 +176,7 @@
         mPreference.onBindViewHolder(mHolder);
 
         assertThat(mBarView1.getVisibility()).isEqualTo(View.VISIBLE);
-        assertThat(mBarView1.getTitle()).isEqualTo("10");
+        assertThat(mBarView1.getTitle()).isEqualTo(mTitleStr);
 
         assertThat(mBarView2.getVisibility()).isEqualTo(View.GONE);
         assertThat(mBarView3.getVisibility()).isEqualTo(View.GONE);
@@ -178,8 +186,8 @@
     @Test
     public void setBarViewInfos_twoBarViewInfosSet_shouldShowTwoBarViews() {
         final BarViewInfo[] barViewsInfo = new BarViewInfo[]{
-                new BarViewInfo(mIcon, 20 /* barNumber */, R.string.debug_app, null),
-                new BarViewInfo(mIcon, 10 /* barNumber */, R.string.debug_app, null)
+                new BarViewInfo(mIcon, 20, mTitleStr, mSummaryStr, null /* contentDescription */),
+                new BarViewInfo(mIcon, 10, mTitleStr, mSummaryStr, null /* contentDescription */),
         };
 
         mPreference.initializeBarChart(mBarChartInfo);
@@ -187,9 +195,9 @@
         mPreference.onBindViewHolder(mHolder);
 
         assertThat(mBarView1.getVisibility()).isEqualTo(View.VISIBLE);
-        assertThat(mBarView1.getTitle()).isEqualTo("20");
+        assertThat(mBarView1.getTitle()).isEqualTo(mTitleStr);
         assertThat(mBarView2.getVisibility()).isEqualTo(View.VISIBLE);
-        assertThat(mBarView2.getTitle()).isEqualTo("10");
+        assertThat(mBarView2.getTitle()).isEqualTo(mTitleStr);
 
         assertThat(mBarView3.getVisibility()).isEqualTo(View.GONE);
         assertThat(mBarView4.getVisibility()).isEqualTo(View.GONE);
@@ -198,9 +206,9 @@
     @Test
     public void setBarViewInfos_threeBarViewInfosSet_shouldShowThreeBarViews() {
         final BarViewInfo[] barViewsInfo = new BarViewInfo[]{
-                new BarViewInfo(mIcon, 20 /* barNumber */, R.string.debug_app, null),
-                new BarViewInfo(mIcon, 10 /* barNumber */, R.string.debug_app, null),
-                new BarViewInfo(mIcon, 5 /* barNumber */, R.string.debug_app, null)
+                new BarViewInfo(mIcon, 20, mTitleStr, mSummaryStr, null /* contentDescription */),
+                new BarViewInfo(mIcon, 10, mTitleStr, mSummaryStr, null /* contentDescription */),
+                new BarViewInfo(mIcon, 5, mTitleStr, mSummaryStr, null /* contentDescription */)
         };
 
         mPreference.initializeBarChart(mBarChartInfo);
@@ -208,11 +216,11 @@
         mPreference.onBindViewHolder(mHolder);
 
         assertThat(mBarView1.getVisibility()).isEqualTo(View.VISIBLE);
-        assertThat(mBarView1.getTitle()).isEqualTo("20");
+        assertThat(mBarView1.getTitle()).isEqualTo(mTitleStr);
         assertThat(mBarView2.getVisibility()).isEqualTo(View.VISIBLE);
-        assertThat(mBarView2.getTitle()).isEqualTo("10");
+        assertThat(mBarView2.getTitle()).isEqualTo(mTitleStr);
         assertThat(mBarView3.getVisibility()).isEqualTo(View.VISIBLE);
-        assertThat(mBarView3.getTitle()).isEqualTo("5");
+        assertThat(mBarView3.getTitle()).isEqualTo(mTitleStr);
 
         assertThat(mBarView4.getVisibility()).isEqualTo(View.GONE);
     }
@@ -220,10 +228,10 @@
     @Test
     public void setBarViewInfos_fourBarViewInfosSet_shouldShowFourBarViews() {
         final BarViewInfo[] barViewsInfo = new BarViewInfo[]{
-                new BarViewInfo(mIcon, 20 /* barNumber */, R.string.debug_app, null),
-                new BarViewInfo(mIcon, 10 /* barNumber */, R.string.debug_app, null),
-                new BarViewInfo(mIcon, 5 /* barNumber */, R.string.debug_app, null),
-                new BarViewInfo(mIcon, 2 /* barNumber */, R.string.debug_app, null),
+                new BarViewInfo(mIcon, 20, mTitleStr, mSummaryStr, null /* contentDescription */),
+                new BarViewInfo(mIcon, 10, mTitleStr, mSummaryStr, null /* contentDescription */),
+                new BarViewInfo(mIcon, 5, mTitleStr, mSummaryStr, null /* contentDescription */),
+                new BarViewInfo(mIcon, 2, mTitleStr, mSummaryStr, null /* contentDescription */)
         };
 
         mPreference.initializeBarChart(mBarChartInfo);
@@ -231,13 +239,13 @@
         mPreference.onBindViewHolder(mHolder);
 
         assertThat(mBarView1.getVisibility()).isEqualTo(View.VISIBLE);
-        assertThat(mBarView1.getTitle()).isEqualTo("20");
+        assertThat(mBarView1.getTitle()).isEqualTo(mTitleStr);
         assertThat(mBarView2.getVisibility()).isEqualTo(View.VISIBLE);
-        assertThat(mBarView2.getTitle()).isEqualTo("10");
+        assertThat(mBarView2.getTitle()).isEqualTo(mTitleStr);
         assertThat(mBarView3.getVisibility()).isEqualTo(View.VISIBLE);
-        assertThat(mBarView3.getTitle()).isEqualTo("5");
+        assertThat(mBarView3.getTitle()).isEqualTo(mTitleStr);
         assertThat(mBarView4.getVisibility()).isEqualTo(View.VISIBLE);
-        assertThat(mBarView4.getTitle()).isEqualTo("2");
+        assertThat(mBarView4.getTitle()).isEqualTo(mTitleStr);
     }
 
     @Test
@@ -245,11 +253,11 @@
         thrown.expect(IllegalStateException.class);
 
         final BarViewInfo[] barViewsInfo = new BarViewInfo[]{
-                new BarViewInfo(mIcon, 30 /* barNumber */, R.string.debug_app, null),
-                new BarViewInfo(mIcon, 50 /* barNumber */, R.string.debug_app, null),
-                new BarViewInfo(mIcon, 5 /* barNumber */, R.string.debug_app, null),
-                new BarViewInfo(mIcon, 10 /* barNumber */, R.string.debug_app, null),
-                new BarViewInfo(mIcon, 70 /* barNumber */, R.string.debug_app, null),
+                new BarViewInfo(mIcon, 30, mTitleStr, mSummaryStr, null /* contentDescription */),
+                new BarViewInfo(mIcon, 50, mTitleStr, mSummaryStr, null /* contentDescription */),
+                new BarViewInfo(mIcon, 5, mTitleStr, mSummaryStr, null /* contentDescription */),
+                new BarViewInfo(mIcon, 10, mTitleStr, mSummaryStr, null /* contentDescription */),
+                new BarViewInfo(mIcon, 70, mTitleStr, mSummaryStr, null /* contentDescription */),
         };
 
         mPreference.setBarViewInfos(barViewsInfo);
@@ -258,10 +266,10 @@
     @Test
     public void setBarViewInfos_barViewInfosSet_shouldBeSortedInDescending() {
         final BarViewInfo[] barViewsInfo = new BarViewInfo[]{
-                new BarViewInfo(mIcon, 30 /* barNumber */, R.string.debug_app, null),
-                new BarViewInfo(mIcon, 50 /* barNumber */, R.string.debug_app, null),
-                new BarViewInfo(mIcon, 5 /* barNumber */, R.string.debug_app, null),
-                new BarViewInfo(mIcon, 10 /* barNumber */, R.string.debug_app, null),
+                new BarViewInfo(mIcon, 30, "30", mSummaryStr, null /* contentDescription */),
+                new BarViewInfo(mIcon, 50, "50", mSummaryStr, null /* contentDescription */),
+                new BarViewInfo(mIcon, 5, "5", mSummaryStr, null /* contentDescription */),
+                new BarViewInfo(mIcon, 10, "10", mSummaryStr, null /* contentDescription */)
         };
 
         mPreference.initializeBarChart(mBarChartInfo);
@@ -281,7 +289,7 @@
     @Test
     public void setBarViewInfos_validBarViewSummarySet_barViewShouldShowSummary() {
         final BarViewInfo[] barViewsInfo = new BarViewInfo[]{
-                new BarViewInfo(mIcon, 10 /* barNumber */, R.string.debug_app, null),
+                new BarViewInfo(mIcon, 10, mTitleStr, mSummaryStr, null /* contentDescription */)
         };
 
         mPreference.initializeBarChart(mBarChartInfo);
@@ -289,13 +297,27 @@
         mPreference.onBindViewHolder(mHolder);
 
         assertThat(mBarView1.getVisibility()).isEqualTo(View.VISIBLE);
-        assertThat(mBarView1.getSummary()).isEqualTo(mContext.getText(R.string.debug_app));
+        assertThat(mBarView1.getSummary()).isEqualTo(mSummaryStr);
+    }
+
+    @Test
+    public void setBarViewInfos_validBarViewTitleSet_barViewShouldShowTitle() {
+        final BarViewInfo[] barViewsInfo = new BarViewInfo[]{
+                new BarViewInfo(mIcon, 10, mTitleStr, mSummaryStr, null /* contentDescription */)
+        };
+
+        mPreference.initializeBarChart(mBarChartInfo);
+        mPreference.setBarViewInfos(barViewsInfo);
+        mPreference.onBindViewHolder(mHolder);
+
+        assertThat(mBarView1.getVisibility()).isEqualTo(View.VISIBLE);
+        assertThat(mBarView1.getTitle()).isEqualTo(mTitleStr);
     }
 
     @Test
     public void setBarViewInfos_clickListenerForBarViewSet_barViewShouldHaveClickListener() {
-        final BarViewInfo viewInfo = new BarViewInfo(mIcon, 30 /* barNumber */, R.string.debug_app,
-                null);
+        final BarViewInfo viewInfo = new BarViewInfo(mIcon, 30, mTitleStr, mSummaryStr,
+                null /* contentDescription */);
         viewInfo.setClickListener(v -> {
         });
         final BarViewInfo[] barViewsInfo = new BarViewInfo[]{viewInfo};
@@ -310,8 +332,8 @@
 
     @Test
     public void onBindViewHolder_loadingStateIsTrue_shouldHideAllViews() {
-        final BarViewInfo viewInfo = new BarViewInfo(mIcon, 30 /* barNumber */, R.string.debug_app,
-                null);
+        final BarViewInfo viewInfo = new BarViewInfo(mIcon, 30, mTitleStr, mSummaryStr,
+                null /* contentDescription */);
         viewInfo.setClickListener(v -> {
         });
         final BarViewInfo[] barViewsInfo = new BarViewInfo[]{viewInfo};
@@ -327,8 +349,8 @@
 
     @Test
     public void onBindViewHolder_loadingStateIsFalse_shouldInitAnyView() {
-        final BarViewInfo viewInfo = new BarViewInfo(mIcon, 30 /* barNumber */, R.string.debug_app,
-                null);
+        final BarViewInfo viewInfo = new BarViewInfo(mIcon, 30, mTitleStr, mSummaryStr,
+                null /* contentDescription */);
         viewInfo.setClickListener(v -> {
         });
         final BarViewInfo[] barViewsInfo = new BarViewInfo[]{viewInfo};
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 4b342b3..296f7a1 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -16,6 +16,7 @@
 
 package com.android.providers.settings;
 
+import static android.os.Process.INVALID_UID;
 import static android.os.Process.ROOT_UID;
 import static android.os.Process.SHELL_UID;
 import static android.os.Process.SYSTEM_UID;
@@ -2777,7 +2778,7 @@
                         boolean someSettingChanged = false;
                         Setting setting = settingsState.getSettingLocked(name);
                         if (!SettingsState.isSystemPackage(getContext(),
-                                setting.getPackageName())) {
+                                setting.getPackageName(), INVALID_UID, userId)) {
                             if (prefix != null && !setting.getName().startsWith(prefix)) {
                                 continue;
                             }
@@ -2797,7 +2798,7 @@
                         boolean someSettingChanged = false;
                         Setting setting = settingsState.getSettingLocked(name);
                         if (!SettingsState.isSystemPackage(getContext(),
-                                setting.getPackageName())) {
+                                setting.getPackageName(), INVALID_UID, userId)) {
                             if (prefix != null && !setting.getName().startsWith(prefix)) {
                                 continue;
                             }
@@ -4410,7 +4411,7 @@
                 }
                 try {
                     final boolean systemSet = SettingsState.isSystemPackage(getContext(),
-                            setting.getPackageName(), callingUid);
+                            setting.getPackageName(), callingUid, userId);
                     if (systemSet) {
                         settings.insertSettingLocked(name, setting.getValue(),
                                 setting.getTag(), true, setting.getPackageName());
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
index 521163f..c05c4cdf 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -17,6 +17,7 @@
 package com.android.providers.settings;
 
 import static android.os.Process.FIRST_APPLICATION_UID;
+import static android.os.Process.INVALID_UID;
 
 import android.annotation.NonNull;
 import android.content.Context;
@@ -1124,11 +1125,16 @@
         return sb.toString();
     }
 
+    // Check if a specific package belonging to the caller is part of the system package.
     public static boolean isSystemPackage(Context context, String packageName) {
-        return isSystemPackage(context, packageName, Binder.getCallingUid());
+        final int callingUid = Binder.getCallingUid();
+        final int callingUserId = UserHandle.getUserId(callingUid);
+        return isSystemPackage(context, packageName, callingUid, callingUserId);
     }
 
-    public static boolean isSystemPackage(Context context, String packageName, int callingUid) {
+    // Check if a specific package, uid, and user ID are part of the system package.
+    public static boolean isSystemPackage(Context context, String packageName, int uid,
+            int userId) {
         synchronized (sLock) {
             if (SYSTEM_PACKAGE_NAME.equals(packageName)) {
                 return true;
@@ -1140,26 +1146,19 @@
                 return false;
             }
 
-            // Native services running as a special UID get a pass
-            final int callingAppId = UserHandle.getAppId(callingUid);
-            if (callingAppId < FIRST_APPLICATION_UID) {
-                sSystemUids.put(callingAppId, callingAppId);
-                return true;
+            if (uid != INVALID_UID) {
+                // Native services running as a special UID get a pass
+                final int callingAppId = UserHandle.getAppId(uid);
+                if (callingAppId < FIRST_APPLICATION_UID) {
+                    sSystemUids.put(callingAppId, callingAppId);
+                    return true;
+                }
             }
 
-            // While some callers may have permissions to manipulate cross user
-            // settings or some settings are stored in the parent of a managed
-            // profile for the purpose of determining whether the other end is a
-            // system component we need to use the user id of the caller for
-            // pulling information about the caller from the package manager.
-            final int callingUserId = UserHandle.getUserId(callingUid);
-
             final long identity = Binder.clearCallingIdentity();
             try {
-                final int uid;
                 try {
-                    uid = context.getPackageManager().getPackageUidAsUser(packageName, 0,
-                            callingUserId);
+                    uid = context.getPackageManager().getPackageUidAsUser(packageName, 0, userId);
                 } catch (PackageManager.NameNotFoundException e) {
                     return false;
                 }
@@ -1187,7 +1186,7 @@
                 PackageInfo packageInfo;
                 try {
                     packageInfo = context.getPackageManager().getPackageInfoAsUser(
-                            packageName, PackageManager.GET_SIGNATURES, callingUserId);
+                            packageName, PackageManager.GET_SIGNATURES, userId);
                     if ((packageInfo.applicationInfo.flags
                             & ApplicationInfo.FLAG_PERSISTENT) != 0
                             && (packageInfo.applicationInfo.flags
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index d6e61eb..d39646b 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -125,6 +125,8 @@
     <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
     <uses-permission android:name="android.permission.MOUNT_FORMAT_FILESYSTEMS" />
     <uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
+    <!-- Shell only holds android.permission.NETWORK_SCAN in order to to enable CTS testing -->
+    <uses-permission android:name="android.permission.NETWORK_SCAN" />
     <uses-permission android:name="android.permission.REGISTER_CALL_PROVIDER" />
     <uses-permission android:name="android.permission.REGISTER_CONNECTION_MANAGER" />
     <uses-permission android:name="android.permission.REGISTER_SIM_SUBSCRIPTION" />
@@ -178,6 +180,8 @@
 
     <!-- Permission needed to run network tests in CTS -->
     <uses-permission android:name="android.permission.MANAGE_TEST_NETWORKS" />
+    <!-- Permission needed to test tcp keepalive offload. -->
+    <uses-permission android:name="android.permission.PACKET_KEEPALIVE_OFFLOAD" />
 
     <!-- Permission needed to run keyguard manager tests in CTS -->
     <uses-permission android:name="android.permission.CONTROL_KEYGUARD_SECURE_NOTIFICATIONS" />
diff --git a/packages/Shell/tests/Android.mk b/packages/Shell/tests/Android.mk
index b93ddde..44ff338 100644
--- a/packages/Shell/tests/Android.mk
+++ b/packages/Shell/tests/Android.mk
@@ -9,7 +9,7 @@
 LOCAL_JAVA_LIBRARIES := android.test.runner android.test.base android.test.mock
 
 LOCAL_STATIC_JAVA_LIBRARIES := \
-    android-support-test \
+    androidx.test.rules \
     mockito-target-minus-junit4 \
     ub-uiautomator \
     junit \
diff --git a/packages/Shell/tests/AndroidManifest.xml b/packages/Shell/tests/AndroidManifest.xml
index 6d564c6..e845ef9 100644
--- a/packages/Shell/tests/AndroidManifest.xml
+++ b/packages/Shell/tests/AndroidManifest.xml
@@ -36,7 +36,7 @@
         </activity>
     </application>
 
-    <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner"
+    <instrumentation android:name="androidx.test.runner.AndroidJUnitRunner"
         android:targetPackage="com.android.shell"
         android:label="Tests for Shell" />
 
diff --git a/packages/Shell/tests/AndroidTest.xml b/packages/Shell/tests/AndroidTest.xml
index e592d82..e03b68a 100644
--- a/packages/Shell/tests/AndroidTest.xml
+++ b/packages/Shell/tests/AndroidTest.xml
@@ -22,7 +22,7 @@
     <option name="test-tag" value="ShellTests" />
     <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="com.android.shell.tests" />
-        <option name="runner" value="android.support.test.runner.AndroidJUnitRunner" />
+        <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
         <option name="hidden-api-checks" value="false"/>
     </test>
 </configuration>
diff --git a/packages/Shell/tests/src/com/android/shell/BugreportProgressServiceTest.java b/packages/Shell/tests/src/com/android/shell/BugreportProgressServiceTest.java
index cef74ae..433eca2 100644
--- a/packages/Shell/tests/src/com/android/shell/BugreportProgressServiceTest.java
+++ b/packages/Shell/tests/src/com/android/shell/BugreportProgressServiceTest.java
@@ -20,7 +20,6 @@
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertNull;
 
-import static org.mockito.Matchers.anyInt;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Mockito.when;
 
@@ -29,12 +28,12 @@
 import android.content.Context;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.support.test.filters.SmallTest;
-import android.support.test.runner.AndroidJUnit4;
 import android.test.mock.MockContext;
 import android.util.Pair;
 
-import org.junit.Before;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
diff --git a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
index e69b0a8..3a71632 100644
--- a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
+++ b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
@@ -42,6 +42,40 @@
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
+import android.app.ActivityManager;
+import android.app.ActivityManager.RunningServiceInfo;
+import android.app.Instrumentation;
+import android.app.NotificationManager;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.SystemClock;
+import android.os.SystemProperties;
+import android.service.notification.StatusBarNotification;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.UiObject;
+import android.support.test.uiautomator.UiObjectNotFoundException;
+import android.text.TextUtils;
+import android.text.format.DateUtils;
+import android.util.Log;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.shell.ActionSendMultipleConsumerActivity.CustomActionSendMultipleListener;
+
+import libcore.io.Streams;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TestName;
+import org.junit.runner.RunWith;
+
 import java.io.BufferedOutputStream;
 import java.io.BufferedWriter;
 import java.io.ByteArrayOutputStream;
@@ -60,40 +94,6 @@
 import java.util.zip.ZipInputStream;
 import java.util.zip.ZipOutputStream;
 
-import libcore.io.Streams;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Ignore;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.TestName;
-import org.junit.runner.RunWith;
-
-import android.app.ActivityManager;
-import android.app.ActivityManager.RunningServiceInfo;
-import android.app.Instrumentation;
-import android.app.NotificationManager;
-import android.content.Context;
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.SystemClock;
-import android.os.SystemProperties;
-import android.service.notification.StatusBarNotification;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.LargeTest;
-import android.support.test.runner.AndroidJUnit4;
-import android.support.test.uiautomator.UiDevice;
-import android.support.test.uiautomator.UiObject;
-import android.support.test.uiautomator.UiObjectNotFoundException;
-import android.text.TextUtils;
-import android.text.format.DateUtils;
-import android.util.Log;
-
-import com.android.shell.ActionSendMultipleConsumerActivity.CustomActionSendMultipleListener;
-
 /**
  * Integration tests for {@link BugreportReceiver}.
  * <p>
diff --git a/packages/SystemUI/res/anim/ic_signal_workmode_disable_left_animation.xml b/packages/SystemUI/res/anim/ic_signal_workmode_disable_left_animation.xml
deleted file mode 100644
index d6054c4..0000000
--- a/packages/SystemUI/res/anim/ic_signal_workmode_disable_left_animation.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<set
-    xmlns:android="http://schemas.android.com/apk/res/android" >
-    <objectAnimator
-        android:duration="250"
-        android:propertyName="scaleX"
-        android:valueFrom="1.0"
-        android:valueTo="1.8"
-        android:valueType="floatType"
-        android:interpolator="@android:interpolator/linear" />
-</set>
diff --git a/packages/SystemUI/res/anim/ic_signal_workmode_disable_mask_1_animation.xml b/packages/SystemUI/res/anim/ic_signal_workmode_disable_mask_1_animation.xml
deleted file mode 100644
index 282170c..0000000
--- a/packages/SystemUI/res/anim/ic_signal_workmode_disable_mask_1_animation.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<set
-    xmlns:android="http://schemas.android.com/apk/res/android" >
-    <set
-        android:ordering="sequentially" >
-        <objectAnimator
-            android:duration="83"
-            android:propertyName="pathData"
-            android:valueFrom="M 366.5,-269.5 c 0.0,0.0 -578.0,2.0 -578.0,2.0 c 0.0,0.0 65.7498321533,68.2501220703 65.7498321533,68.2501220703 c 0.0,0.0 -20.7500457764,20.7500610352 -20.7500457764,20.7500610352 c 0.0,0.0 -65.749786377,-68.2501983643 -65.749786377,-68.2501983643 c 0.0,0.0 -7.25,539.250015259 -7.25,539.250015259 c 0.0,0.0 606.0,0.0 606.0,0.0 c 0.0,0.0 0.0,-562.0 0.0,-562.0 Z"
-            android:valueTo="M 366.5,-269.5 c 0.0,0.0 -578.0,2.0 -578.0,2.0 c 0.0,0.0 65.7498321533,68.2501220703 65.7498321533,68.2501220703 c 0.0,0.0 -20.7500457764,20.7500610352 -20.7500457764,20.7500610352 c 0.0,0.0 -65.749786377,-68.2501983643 -65.749786377,-68.2501983643 c 0.0,0.0 -7.25,539.250015259 -7.25,539.250015259 c 0.0,0.0 606.0,0.0 606.0,0.0 c 0.0,0.0 0.0,-562.0 0.0,-562.0 Z"
-            android:valueType="pathType"
-            android:interpolator="@android:interpolator/linear" />
-        <objectAnimator
-            android:duration="250"
-            android:propertyName="pathData"
-            android:valueFrom="M 366.5,-269.5 c 0.0,0.0 -578.0,2.0 -578.0,2.0 c 0.0,0.0 65.7498321533,68.2501220703 65.7498321533,68.2501220703 c 0.0,0.0 -20.7500457764,20.7500610352 -20.7500457764,20.7500610352 c 0.0,0.0 -65.749786377,-68.2501983643 -65.749786377,-68.2501983643 c 0.0,0.0 -7.25,539.250015259 -7.25,539.250015259 c 0.0,0.0 606.0,0.0 606.0,0.0 c 0.0,0.0 0.0,-562.0 0.0,-562.0 Z"
-            android:valueTo="M 366.5,-269.5 c 0.0,0.0 -578.0,2.0 -578.0,2.0 c 0.0,0.0 480.0,480.0 480.0,480.0 c 0.0,0.0 -20.7500915527,20.75 -20.7500915527,20.75 c 0.0,0.0 -479.999908447,-480.000015259 -479.999908447,-480.000015259 c 0.0,0.0 -7.25,539.250015259 -7.25,539.250015259 c 0.0,0.0 606.0,0.0 606.0,0.0 c 0.0,0.0 0.0,-562.0 0.0,-562.0 Z"
-            android:valueType="pathType"
-            android:interpolator="@interpolator/ic_signal_workmode_disable_animation_interpolator_2" />
-    </set>
-</set>
diff --git a/packages/SystemUI/res/anim/ic_signal_workmode_disable_rectangle_path_3_animation.xml b/packages/SystemUI/res/anim/ic_signal_workmode_disable_rectangle_path_3_animation.xml
deleted file mode 100644
index b59c664..0000000
--- a/packages/SystemUI/res/anim/ic_signal_workmode_disable_rectangle_path_3_animation.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<set
-    xmlns:android="http://schemas.android.com/apk/res/android" >
-    <set
-        android:ordering="sequentially" >
-        <objectAnimator
-            android:duration="133"
-            android:propertyName="pathData"
-            android:valueFrom="M -143.0,-40.0 l 286.0,0.0 c 17.6731119936,0.0 32.0,14.3268880064 32.0,32.0 l 0.0,16.0 c 0.0,17.6731119936 -14.3268880064,32.0 -32.0,32.0 l -286.0,0.0 c -17.6731119936,0.0 -32.0,-14.3268880064 -32.0,-32.0 l 0.0,-16.0 c 0.0,-17.6731119936 14.3268880064,-32.0 32.0,-32.0 Z"
-            android:valueTo="M -143.0,-40.0 l 286.0,0.0 c 17.6731119936,0.0 32.0,14.3268880064 32.0,32.0 l 0.0,16.0 c 0.0,17.6731119936 -14.3268880064,32.0 -32.0,32.0 l -286.0,0.0 c -17.6731119936,0.0 -32.0,-14.3268880064 -32.0,-32.0 l 0.0,-16.0 c 0.0,-17.6731119936 14.3268880064,-32.0 32.0,-32.0 Z"
-            android:valueType="pathType"
-            android:interpolator="@android:interpolator/linear" />
-        <objectAnimator
-            android:duration="116"
-            android:propertyName="pathData"
-            android:valueFrom="M -143.0,-40.0 l 286.0,0.0 c 17.6731119936,0.0 32.0,14.3268880064 32.0,32.0 l 0.0,16.0 c 0.0,17.6731119936 -14.3268880064,32.0 -32.0,32.0 l -286.0,0.0 c -17.6731119936,0.0 -32.0,-14.3268880064 -32.0,-32.0 l 0.0,-16.0 c 0.0,-17.6731119936 14.3268880064,-32.0 32.0,-32.0 Z"
-            android:valueTo="M -143.0,-65.0 l 286.0,0.0 c 17.6731119936,0.0 32.0,14.3268880064 32.0,32.0 l 0.0,66.0 c 0.0,17.6731119936 -14.3268880064,32.0 -32.0,32.0 l -286.0,0.0 c -17.6731119936,0.0 -32.0,-14.3268880064 -32.0,-32.0 l 0.0,-66.0 c 0.0,-17.6731119936 14.3268880064,-32.0 32.0,-32.0 Z"
-            android:valueType="pathType"
-            android:interpolator="@android:interpolator/linear" />
-    </set>
-</set>
diff --git a/packages/SystemUI/res/anim/ic_signal_workmode_disable_rectangle_path_3_position_animation.xml b/packages/SystemUI/res/anim/ic_signal_workmode_disable_rectangle_path_3_position_animation.xml
deleted file mode 100644
index 60d2396..0000000
--- a/packages/SystemUI/res/anim/ic_signal_workmode_disable_rectangle_path_3_position_animation.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<set
-    xmlns:android="http://schemas.android.com/apk/res/android" >
-    <objectAnimator
-        android:duration="250"
-        android:propertyXName="translateX"
-        android:propertyYName="translateY"
-        android:pathData="M 0.0,0.0 c 0.0,4.16667 0.0,20.83333 0.0,25.0"
-        android:interpolator="@interpolator/ic_signal_workmode_disable_animation_interpolator_1" />
-</set>
diff --git a/packages/SystemUI/res/anim/ic_signal_workmode_disable_rectangle_path_4_animation.xml b/packages/SystemUI/res/anim/ic_signal_workmode_disable_rectangle_path_4_animation.xml
deleted file mode 100644
index ef442e9..0000000
--- a/packages/SystemUI/res/anim/ic_signal_workmode_disable_rectangle_path_4_animation.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<set
-    xmlns:android="http://schemas.android.com/apk/res/android" >
-    <set
-        android:ordering="sequentially" >
-        <objectAnimator
-            android:duration="33"
-            android:propertyName="pathData"
-            android:valueFrom="M -143.0,-40.0 l 286.0,0.0 c 17.6731119936,0.0 32.0,14.3268880064 32.0,32.0 l 0.0,16.0 c 0.0,17.6731119936 -14.3268880064,32.0 -32.0,32.0 l -286.0,0.0 c -17.6731119936,0.0 -32.0,-14.3268880064 -32.0,-32.0 l 0.0,-16.0 c 0.0,-17.6731119936 14.3268880064,-32.0 32.0,-32.0 Z"
-            android:valueTo="M -143.0,-40.0 l 286.0,0.0 c 17.6731119936,0.0 32.0,14.3268880064 32.0,32.0 l 0.0,16.0 c 0.0,17.6731119936 -14.3268880064,32.0 -32.0,32.0 l -286.0,0.0 c -17.6731119936,0.0 -32.0,-14.3268880064 -32.0,-32.0 l 0.0,-16.0 c 0.0,-17.6731119936 14.3268880064,-32.0 32.0,-32.0 Z"
-            android:valueType="pathType"
-            android:interpolator="@android:interpolator/linear" />
-        <objectAnimator
-            android:duration="200"
-            android:propertyName="pathData"
-            android:valueFrom="M -143.0,-40.0 l 286.0,0.0 c 17.6731119936,0.0 32.0,14.3268880064 32.0,32.0 l 0.0,16.0 c 0.0,17.6731119936 -14.3268880064,32.0 -32.0,32.0 l -286.0,0.0 c -17.6731119936,0.0 -32.0,-14.3268880064 -32.0,-32.0 l 0.0,-16.0 c 0.0,-17.6731119936 14.3268880064,-32.0 32.0,-32.0 Z"
-            android:valueTo="M -143.0,-65.0 l 286.0,0.0 c 17.6731119936,0.0 32.0,14.3268880064 32.0,32.0 l 0.0,66.0 c 0.0,17.6731119936 -14.3268880064,32.0 -32.0,32.0 l -286.0,0.0 c -17.6731119936,0.0 -32.0,-14.3268880064 -32.0,-32.0 l 0.0,-66.0 c 0.0,-17.6731119936 14.3268880064,-32.0 32.0,-32.0 Z"
-            android:valueType="pathType"
-            android:interpolator="@android:interpolator/linear" />
-    </set>
-</set>
diff --git a/packages/SystemUI/res/anim/ic_signal_workmode_disable_rectangle_path_4_position_animation.xml b/packages/SystemUI/res/anim/ic_signal_workmode_disable_rectangle_path_4_position_animation.xml
deleted file mode 100644
index 97782be..0000000
--- a/packages/SystemUI/res/anim/ic_signal_workmode_disable_rectangle_path_4_position_animation.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<set
-    xmlns:android="http://schemas.android.com/apk/res/android" >
-    <objectAnimator
-        android:duration="233"
-        android:propertyXName="translateX"
-        android:propertyYName="translateY"
-        android:pathData="M 0.0,0.0 c 0.0,-4.16667 0.0,-20.83333 0.0,-25.0"
-        android:interpolator="@interpolator/ic_signal_workmode_disable_animation_interpolator_0" />
-</set>
diff --git a/packages/SystemUI/res/anim/ic_signal_workmode_disable_right_animation.xml b/packages/SystemUI/res/anim/ic_signal_workmode_disable_right_animation.xml
deleted file mode 100644
index d6054c4..0000000
--- a/packages/SystemUI/res/anim/ic_signal_workmode_disable_right_animation.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<set
-    xmlns:android="http://schemas.android.com/apk/res/android" >
-    <objectAnimator
-        android:duration="250"
-        android:propertyName="scaleX"
-        android:valueFrom="1.0"
-        android:valueTo="1.8"
-        android:valueType="floatType"
-        android:interpolator="@android:interpolator/linear" />
-</set>
diff --git a/packages/SystemUI/res/anim/ic_signal_workmode_disable_stick_animation.xml b/packages/SystemUI/res/anim/ic_signal_workmode_disable_stick_animation.xml
deleted file mode 100644
index 573205ffd..0000000
--- a/packages/SystemUI/res/anim/ic_signal_workmode_disable_stick_animation.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<set
-    xmlns:android="http://schemas.android.com/apk/res/android" >
-    <objectAnimator
-        android:duration="250"
-        android:propertyName="scaleY"
-        android:valueFrom="0.0"
-        android:valueTo="1.0"
-        android:valueType="floatType"
-        android:interpolator="@interpolator/ic_signal_workmode_disable_animation_interpolator_3" />
-</set>
diff --git a/packages/SystemUI/res/anim/ic_signal_workmode_disable_stickito_animation.xml b/packages/SystemUI/res/anim/ic_signal_workmode_disable_stickito_animation.xml
deleted file mode 100644
index 4b038b9..0000000
--- a/packages/SystemUI/res/anim/ic_signal_workmode_disable_stickito_animation.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<set
-    xmlns:android="http://schemas.android.com/apk/res/android" >
-    <objectAnimator
-        android:duration="333"
-        android:propertyName="alpha"
-        android:valueFrom="1.0"
-        android:valueTo="0.54"
-        android:valueType="floatType"
-        android:interpolator="@interpolator/ic_signal_workmode_disable_animation_interpolator_4" />
-</set>
diff --git a/packages/SystemUI/res/anim/ic_signal_workmode_disable_whole_animation.xml b/packages/SystemUI/res/anim/ic_signal_workmode_disable_whole_animation.xml
deleted file mode 100644
index 562985a8..0000000
--- a/packages/SystemUI/res/anim/ic_signal_workmode_disable_whole_animation.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<set
-    xmlns:android="http://schemas.android.com/apk/res/android" >
-    <set
-        android:ordering="sequentially" >
-        <objectAnimator
-            android:duration="83"
-            android:propertyName="scaleX"
-            android:valueFrom="1.0"
-            android:valueTo="1.15667"
-            android:valueType="floatType"
-            android:interpolator="@interpolator/ic_signal_workmode_disable_animation_interpolator_5" />
-        <objectAnimator
-            android:duration="166"
-            android:propertyName="scaleX"
-            android:valueFrom="1.15667"
-            android:valueTo="0.0"
-            android:valueType="floatType"
-            android:interpolator="@interpolator/ic_signal_workmode_disable_animation_interpolator_5" />
-    </set>
-    <set
-        android:ordering="sequentially" >
-        <objectAnimator
-            android:duration="83"
-            android:propertyName="scaleY"
-            android:valueFrom="1.0"
-            android:valueTo="1.15667"
-            android:valueType="floatType"
-            android:interpolator="@interpolator/ic_signal_workmode_disable_animation_interpolator_5" />
-        <objectAnimator
-            android:duration="166"
-            android:propertyName="scaleY"
-            android:valueFrom="1.15667"
-            android:valueTo="0.0"
-            android:valueType="floatType"
-            android:interpolator="@interpolator/ic_signal_workmode_disable_animation_interpolator_5" />
-    </set>
-</set>
diff --git a/packages/SystemUI/res/anim/ic_signal_workmode_enable_animation_cross_1.xml b/packages/SystemUI/res/anim/ic_signal_workmode_enable_animation_cross_1.xml
deleted file mode 100644
index 6c7e751..0000000
--- a/packages/SystemUI/res/anim/ic_signal_workmode_enable_animation_cross_1.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
-    <objectAnimator
-        android:duration="350"
-        android:propertyName="pathData"
-        android:valueFrom="M 7.54049682617,3.9430847168 c 0.0,0.0 31.5749816895,31.4499664307 31.5749816895,31.4499664307 "
-        android:valueTo="M 7.54049682617,3.9430847168 c 0.0,0.0 0.324981689453,0.399978637695 0.324981689453,0.399978637695 "
-        android:valueType="pathType"
-        android:interpolator="@interpolator/ic_signal_workmode_enable_cross_1_pathdata_interpolator" />
-    <set
-        android:ordering="sequentially" >
-        <objectAnimator
-            android:duration="333"
-            android:propertyName="strokeAlpha"
-            android:valueFrom="1"
-            android:valueTo="1"
-            android:interpolator="@android:interpolator/linear" />
-        <objectAnimator
-            android:duration="17"
-            android:propertyName="strokeAlpha"
-            android:valueFrom="1"
-            android:valueTo="0"
-            android:interpolator="@android:interpolator/linear" />
-    </set>
-</set>
diff --git a/packages/SystemUI/res/anim/ic_signal_workmode_enable_animation_ic_signal_briefcase.xml b/packages/SystemUI/res/anim/ic_signal_workmode_enable_animation_ic_signal_briefcase.xml
deleted file mode 100644
index c699fe2..0000000
--- a/packages/SystemUI/res/anim/ic_signal_workmode_enable_animation_ic_signal_briefcase.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
-    <set
-        android:ordering="sequentially" >
-        <objectAnimator
-            android:duration="200"
-            android:propertyName="alpha"
-            android:valueFrom="0.5"
-            android:valueTo="0.5"
-            android:interpolator="@android:interpolator/fast_out_slow_in" />
-        <objectAnimator
-            android:duration="350"
-            android:propertyName="alpha"
-            android:valueFrom="0.5"
-            android:valueTo="1"
-            android:interpolator="@android:interpolator/fast_out_slow_in" />
-    </set>
-</set>
diff --git a/packages/SystemUI/res/anim/ic_signal_workmode_enable_animation_mask.xml b/packages/SystemUI/res/anim/ic_signal_workmode_enable_animation_mask.xml
deleted file mode 100644
index 5595e5c..0000000
--- a/packages/SystemUI/res/anim/ic_signal_workmode_enable_animation_mask.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<set xmlns:android="http://schemas.android.com/apk/res/android" >
-    <objectAnimator
-        android:duration="350"
-        android:propertyName="pathData"
-        android:valueFrom="M 37.8337860107,-40.3974914551 c 0.0,0.0 -35.8077850342,31.5523681641 -35.8077850342,31.5523681641 c 0.0,0.0 40.9884796143,40.9278411865 40.9884796143,40.9278411865 c 0.0,0.0 -2.61700439453,2.0938873291 -2.61700439453,2.0938873291 c 0.0,0.0 -41.1884460449,-40.9392852783 -41.1884460449,-40.9392852783 c 0.0,0.0 -34.6200408936,25.4699249268 -34.6200408936,25.4699249268 c 0.0,0.0 55.9664764404,69.742401123 55.9664764404,69.742401123 c 0.0,0.0 73.2448120117,-59.1047973633 73.2448120117,-59.1047973633 c 0.0,0.0 -55.9664916992,-69.7423400879 -55.9664916992,-69.7423400879 Z"
-        android:valueTo="M 37.8337860107,-40.4599914551 c 0.0,0.0 -35.8077850342,31.5523681641 -35.8077850342,31.5523681641 c 0.0,0.0 9.55097961426,9.55285644531 9.55097961426,9.55285644531 c 0.0,0.0 -2.61698913574,2.09387207031 -2.61698913574,2.09387207031 c 0.0,0.0 -9.75096130371,-9.56428527832 -9.75096130371,-9.56428527832 c 0.0,0.0 -34.6200408936,25.4699249268 -34.6200408936,25.4699249268 c 0.0,0.0 55.9664764404,69.742401123 55.9664764404,69.742401123 c 0.0,0.0 73.2448120117,-59.1047973633 73.2448120117,-59.1047973633 c 0.0,0.0 -55.9664916992,-69.7423400879 -55.9664916992,-69.7423400879 Z"
-        android:valueType="pathType"
-        android:interpolator="@interpolator/ic_signal_workmode_enable_mask_pathdata_interpolator" />
-</set>
diff --git a/packages/SystemUI/res/anim/ic_signal_workmode_enable_left_animation.xml b/packages/SystemUI/res/anim/ic_signal_workmode_enable_left_animation.xml
deleted file mode 100644
index 4614bfc..0000000
--- a/packages/SystemUI/res/anim/ic_signal_workmode_enable_left_animation.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<set
-    xmlns:android="http://schemas.android.com/apk/res/android" >
-    <set
-        android:ordering="sequentially" >
-        <objectAnimator
-            android:duration="83"
-            android:propertyName="scaleX"
-            android:valueFrom="1.8"
-            android:valueTo="1.8"
-            android:valueType="floatType"
-            android:interpolator="@android:interpolator/linear" />
-        <objectAnimator
-            android:duration="250"
-            android:propertyName="scaleX"
-            android:valueFrom="1.8"
-            android:valueTo="1.0"
-            android:valueType="floatType"
-            android:interpolator="@android:interpolator/linear" />
-    </set>
-</set>
diff --git a/packages/SystemUI/res/anim/ic_signal_workmode_enable_mask_1_animation.xml b/packages/SystemUI/res/anim/ic_signal_workmode_enable_mask_1_animation.xml
deleted file mode 100644
index f5cfcf9..0000000
--- a/packages/SystemUI/res/anim/ic_signal_workmode_enable_mask_1_animation.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<set
-    xmlns:android="http://schemas.android.com/apk/res/android" >
-    <objectAnimator
-        android:duration="250"
-        android:propertyName="pathData"
-        android:valueFrom="M 366.5,-269.5 c 0.0,0.0 -578.0,2.0 -578.0,2.0 c 0.0,0.0 480.0,480.0 480.0,480.0 c 0.0,0.0 -20.7500915527,20.75 -20.7500915527,20.75 c 0.0,0.0 -479.999908447,-480.000015259 -479.999908447,-480.000015259 c 0.0,0.0 -7.25,539.250015259 -7.25,539.250015259 c 0.0,0.0 606.0,0.0 606.0,0.0 c 0.0,0.0 0.0,-562.0 0.0,-562.0 Z"
-        android:valueTo="M 366.5,-269.5 c 0.0,0.0 -578.0,2.0 -578.0,2.0 c 0.0,0.0 65.7498321533,68.2501220703 65.7498321533,68.2501220703 c 0.0,0.0 -20.7500457764,20.7500610352 -20.7500457764,20.7500610352 c 0.0,0.0 -65.749786377,-68.2501983643 -65.749786377,-68.2501983643 c 0.0,0.0 -7.25,539.250015259 -7.25,539.250015259 c 0.0,0.0 606.0,0.0 606.0,0.0 c 0.0,0.0 0.0,-562.0 0.0,-562.0 Z"
-        android:valueType="pathType"
-        android:interpolator="@interpolator/ic_signal_workmode_enable_animation_interpolator_1" />
-</set>
diff --git a/packages/SystemUI/res/anim/ic_signal_workmode_enable_rectangle_path_3_animation.xml b/packages/SystemUI/res/anim/ic_signal_workmode_enable_rectangle_path_3_animation.xml
deleted file mode 100644
index 0b74b3a..0000000
--- a/packages/SystemUI/res/anim/ic_signal_workmode_enable_rectangle_path_3_animation.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<set
-    xmlns:android="http://schemas.android.com/apk/res/android" >
-    <set
-        android:ordering="sequentially" >
-        <objectAnimator
-            android:duration="83"
-            android:propertyName="pathData"
-            android:valueFrom="M -143.0,-65.0 l 286.0,0.0 c 17.6731119936,0.0 32.0,14.3268880064 32.0,32.0 l 0.0,66.0 c 0.0,17.6731119936 -14.3268880064,32.0 -32.0,32.0 l -286.0,0.0 c -17.6731119936,0.0 -32.0,-14.3268880064 -32.0,-32.0 l 0.0,-66.0 c 0.0,-17.6731119936 14.3268880064,-32.0 32.0,-32.0 Z"
-            android:valueTo="M -143.0,-65.0 l 286.0,0.0 c 17.6731119936,0.0 32.0,14.3268880064 32.0,32.0 l 0.0,66.0 c 0.0,17.6731119936 -14.3268880064,32.0 -32.0,32.0 l -286.0,0.0 c -17.6731119936,0.0 -32.0,-14.3268880064 -32.0,-32.0 l 0.0,-66.0 c 0.0,-17.6731119936 14.3268880064,-32.0 32.0,-32.0 Z"
-            android:valueType="pathType"
-            android:interpolator="@android:interpolator/linear" />
-        <objectAnimator
-            android:duration="133"
-            android:propertyName="pathData"
-            android:valueFrom="M -143.0,-65.0 l 286.0,0.0 c 17.6731119936,0.0 32.0,14.3268880064 32.0,32.0 l 0.0,66.0 c 0.0,17.6731119936 -14.3268880064,32.0 -32.0,32.0 l -286.0,0.0 c -17.6731119936,0.0 -32.0,-14.3268880064 -32.0,-32.0 l 0.0,-66.0 c 0.0,-17.6731119936 14.3268880064,-32.0 32.0,-32.0 Z"
-            android:valueTo="M -143.0,-40.0 l 286.0,0.0 c 17.6731119936,0.0 32.0,14.3268880064 32.0,32.0 l 0.0,16.0 c 0.0,17.6731119936 -14.3268880064,32.0 -32.0,32.0 l -286.0,0.0 c -17.6731119936,0.0 -32.0,-14.3268880064 -32.0,-32.0 l 0.0,-16.0 c 0.0,-17.6731119936 14.3268880064,-32.0 32.0,-32.0 Z"
-            android:valueType="pathType"
-            android:interpolator="@android:interpolator/linear" />
-    </set>
-</set>
diff --git a/packages/SystemUI/res/anim/ic_signal_workmode_enable_rectangle_path_3_position_animation.xml b/packages/SystemUI/res/anim/ic_signal_workmode_enable_rectangle_path_3_position_animation.xml
deleted file mode 100644
index ba10224..0000000
--- a/packages/SystemUI/res/anim/ic_signal_workmode_enable_rectangle_path_3_position_animation.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<set
-    xmlns:android="http://schemas.android.com/apk/res/android" >
-    <objectAnimator
-        android:duration="216"
-        android:propertyXName="translateX"
-        android:propertyYName="translateY"
-        android:pathData="M 0.0,25.0 c 0.0,-4.16667 0.0,-20.83333 0.0,-25.0"
-        android:interpolator="@interpolator/ic_signal_workmode_enable_animation_interpolator_2" />
-</set>
diff --git a/packages/SystemUI/res/anim/ic_signal_workmode_enable_rectangle_path_4_animation.xml b/packages/SystemUI/res/anim/ic_signal_workmode_enable_rectangle_path_4_animation.xml
deleted file mode 100644
index 395bbf4..0000000
--- a/packages/SystemUI/res/anim/ic_signal_workmode_enable_rectangle_path_4_animation.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<set
-    xmlns:android="http://schemas.android.com/apk/res/android" >
-    <set
-        android:ordering="sequentially" >
-        <objectAnimator
-            android:duration="100"
-            android:propertyName="pathData"
-            android:valueFrom="M -143.0,-65.0 l 286.0,0.0 c 17.6731119936,0.0 32.0,14.3268880064 32.0,32.0 l 0.0,66.0 c 0.0,17.6731119936 -14.3268880064,32.0 -32.0,32.0 l -286.0,0.0 c -17.6731119936,0.0 -32.0,-14.3268880064 -32.0,-32.0 l 0.0,-66.0 c 0.0,-17.6731119936 14.3268880064,-32.0 32.0,-32.0 Z"
-            android:valueTo="M -143.0,-65.0 l 286.0,0.0 c 17.6731119936,0.0 32.0,14.3268880064 32.0,32.0 l 0.0,66.0 c 0.0,17.6731119936 -14.3268880064,32.0 -32.0,32.0 l -286.0,0.0 c -17.6731119936,0.0 -32.0,-14.3268880064 -32.0,-32.0 l 0.0,-66.0 c 0.0,-17.6731119936 14.3268880064,-32.0 32.0,-32.0 Z"
-            android:valueType="pathType"
-            android:interpolator="@android:interpolator/linear" />
-        <objectAnimator
-            android:duration="199"
-            android:propertyName="pathData"
-            android:valueFrom="M -143.0,-65.0 l 286.0,0.0 c 17.6731119936,0.0 32.0,14.3268880064 32.0,32.0 l 0.0,66.0 c 0.0,17.6731119936 -14.3268880064,32.0 -32.0,32.0 l -286.0,0.0 c -17.6731119936,0.0 -32.0,-14.3268880064 -32.0,-32.0 l 0.0,-66.0 c 0.0,-17.6731119936 14.3268880064,-32.0 32.0,-32.0 Z"
-            android:valueTo="M -143.0,-40.0 l 286.0,0.0 c 17.6731119936,0.0 32.0,14.3268880064 32.0,32.0 l 0.0,16.0 c 0.0,17.6731119936 -14.3268880064,32.0 -32.0,32.0 l -286.0,0.0 c -17.6731119936,0.0 -32.0,-14.3268880064 -32.0,-32.0 l 0.0,-16.0 c 0.0,-17.6731119936 14.3268880064,-32.0 32.0,-32.0 Z"
-            android:valueType="pathType"
-            android:interpolator="@android:interpolator/linear" />
-    </set>
-</set>
diff --git a/packages/SystemUI/res/anim/ic_signal_workmode_enable_rectangle_path_4_position_animation.xml b/packages/SystemUI/res/anim/ic_signal_workmode_enable_rectangle_path_4_position_animation.xml
deleted file mode 100644
index 0115759..0000000
--- a/packages/SystemUI/res/anim/ic_signal_workmode_enable_rectangle_path_4_position_animation.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<set
-    xmlns:android="http://schemas.android.com/apk/res/android" >
-    <objectAnimator
-        android:duration="300"
-        android:propertyXName="translateX"
-        android:propertyYName="translateY"
-        android:pathData="M 0.0,-25.0 c 0.0,4.16667 0.0,20.83333 0.0,25.0"
-        android:interpolator="@interpolator/ic_signal_workmode_enable_animation_interpolator_4" />
-</set>
diff --git a/packages/SystemUI/res/anim/ic_signal_workmode_enable_right_animation.xml b/packages/SystemUI/res/anim/ic_signal_workmode_enable_right_animation.xml
deleted file mode 100644
index 4614bfc..0000000
--- a/packages/SystemUI/res/anim/ic_signal_workmode_enable_right_animation.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<set
-    xmlns:android="http://schemas.android.com/apk/res/android" >
-    <set
-        android:ordering="sequentially" >
-        <objectAnimator
-            android:duration="83"
-            android:propertyName="scaleX"
-            android:valueFrom="1.8"
-            android:valueTo="1.8"
-            android:valueType="floatType"
-            android:interpolator="@android:interpolator/linear" />
-        <objectAnimator
-            android:duration="250"
-            android:propertyName="scaleX"
-            android:valueFrom="1.8"
-            android:valueTo="1.0"
-            android:valueType="floatType"
-            android:interpolator="@android:interpolator/linear" />
-    </set>
-</set>
diff --git a/packages/SystemUI/res/anim/ic_signal_workmode_enable_stick_animation.xml b/packages/SystemUI/res/anim/ic_signal_workmode_enable_stick_animation.xml
deleted file mode 100644
index 6b182be..0000000
--- a/packages/SystemUI/res/anim/ic_signal_workmode_enable_stick_animation.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<set
-    xmlns:android="http://schemas.android.com/apk/res/android" >
-    <set
-        android:ordering="sequentially" >
-        <objectAnimator
-            android:duration="83"
-            android:propertyName="scaleY"
-            android:valueFrom="1.0"
-            android:valueTo="1.0"
-            android:valueType="floatType"
-            android:interpolator="@android:interpolator/linear" />
-        <objectAnimator
-            android:duration="250"
-            android:propertyName="scaleY"
-            android:valueFrom="1.0"
-            android:valueTo="0.0"
-            android:valueType="floatType"
-            android:interpolator="@android:interpolator/fast_out_slow_in" />
-    </set>
-</set>
diff --git a/packages/SystemUI/res/anim/ic_signal_workmode_enable_stickito_animation.xml b/packages/SystemUI/res/anim/ic_signal_workmode_enable_stickito_animation.xml
deleted file mode 100644
index 828f7a2..0000000
--- a/packages/SystemUI/res/anim/ic_signal_workmode_enable_stickito_animation.xml
+++ /dev/null
@@ -1,11 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<set
-    xmlns:android="http://schemas.android.com/apk/res/android" >
-    <objectAnimator
-        android:duration="333"
-        android:propertyName="alpha"
-        android:valueFrom="0.54"
-        android:valueTo="1.0"
-        android:valueType="floatType"
-        android:interpolator="@interpolator/ic_signal_workmode_enable_animation_interpolator_3" />
-</set>
diff --git a/packages/SystemUI/res/anim/ic_signal_workmode_enable_whole_animation.xml b/packages/SystemUI/res/anim/ic_signal_workmode_enable_whole_animation.xml
deleted file mode 100644
index 89ab580..0000000
--- a/packages/SystemUI/res/anim/ic_signal_workmode_enable_whole_animation.xml
+++ /dev/null
@@ -1,52 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<set
-    xmlns:android="http://schemas.android.com/apk/res/android" >
-    <set
-        android:ordering="sequentially" >
-        <objectAnimator
-            android:duration="66"
-            android:propertyName="scaleX"
-            android:valueFrom="0.0"
-            android:valueTo="0.0"
-            android:valueType="floatType"
-            android:interpolator="@android:interpolator/linear" />
-        <objectAnimator
-            android:duration="166"
-            android:propertyName="scaleX"
-            android:valueFrom="0.0"
-            android:valueTo="1.15667"
-            android:valueType="floatType"
-            android:interpolator="@interpolator/ic_signal_workmode_enable_animation_interpolator_5" />
-        <objectAnimator
-            android:duration="83"
-            android:propertyName="scaleX"
-            android:valueFrom="1.15667"
-            android:valueTo="1.0"
-            android:valueType="floatType"
-            android:interpolator="@interpolator/ic_signal_workmode_enable_animation_interpolator_0" />
-    </set>
-    <set
-        android:ordering="sequentially" >
-        <objectAnimator
-            android:duration="66"
-            android:propertyName="scaleY"
-            android:valueFrom="0.0"
-            android:valueTo="0.0"
-            android:valueType="floatType"
-            android:interpolator="@android:interpolator/linear" />
-        <objectAnimator
-            android:duration="166"
-            android:propertyName="scaleY"
-            android:valueFrom="0.0"
-            android:valueTo="1.15667"
-            android:valueType="floatType"
-            android:interpolator="@interpolator/ic_signal_workmode_enable_animation_interpolator_5" />
-        <objectAnimator
-            android:duration="83"
-            android:propertyName="scaleY"
-            android:valueFrom="1.15667"
-            android:valueTo="1.0"
-            android:valueType="floatType"
-            android:interpolator="@interpolator/ic_signal_workmode_enable_animation_interpolator_0" />
-    </set>
-</set>
diff --git a/packages/SystemUI/res/drawable/ic_alarm.xml b/packages/SystemUI/res/drawable/ic_alarm.xml
new file mode 100644
index 0000000..1c1adcd
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_alarm.xml
@@ -0,0 +1,25 @@
+<!--
+     Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="17dp"
+    android:width="17dp"
+    android:viewportHeight="24"
+    android:viewportWidth="24">
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M13,8h-2v5.41l3.79,3.8 1.42,-1.42 -3.21,-3.2zM12,4c-4.97,0 -9,4.03 -9,9s4.03,9 9,9 9,-4.03 9,-9 -4.03,-9 -9,-9zM12,20c-3.86,0 -7,-3.14 -7,-7s3.14,-7 7,-7 7,3.14 7,7 -3.14,7 -7,7zM16.056,3.346l1.282,-1.535 4.607,3.85 -1.28,1.54zM2.056,5.654L6.663,1.81l1.28,1.536L3.338,7.19z"/>
+
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_alarm_dim.xml b/packages/SystemUI/res/drawable/ic_alarm_dim.xml
new file mode 100644
index 0000000..37ab873
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_alarm_dim.xml
@@ -0,0 +1,26 @@
+<!--
+     Copyright (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:height="17dp"
+    android:width="17dp"
+    android:viewportHeight="24"
+    android:viewportWidth="24">
+    <path
+        android:fillColor="#FFFFFF"
+        android:fillAlpha="0.3"
+        android:pathData="M13,8h-2v5.41l3.79,3.8 1.42,-1.42 -3.21,-3.2zM12,4c-4.97,0 -9,4.03 -9,9s4.03,9 9,9 9,-4.03 9,-9 -4.03,-9 -9,-9zM12,20c-3.86,0 -7,-3.14 -7,-7s3.14,-7 7,-7 7,3.14 7,7 -3.14,7 -7,7zM16.056,3.346l1.282,-1.535 4.607,3.85 -1.28,1.54zM2.056,5.654L6.663,1.81l1.28,1.536L3.338,7.19z"/>
+
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_bluetooth_connected.xml b/packages/SystemUI/res/drawable/ic_bluetooth_connected.xml
new file mode 100644
index 0000000..125082c
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_bluetooth_connected.xml
@@ -0,0 +1,30 @@
+<!--
+Copyright (C) 2017 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="17dp"
+    android:height="17dp"
+    android:viewportWidth="24.0"
+    android:viewportHeight="24.0">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M17.71,7.71L12,2h-1v7.59L6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 11,14.41L11,22h1l5.71,-5.71 -4.3,-4.29 4.3,-4.29zM13,5.83l1.88,1.88L13,9.59L13,5.83zM14.88,16.29L13,18.17v-3.76l1.88,1.88z"/>
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M5,12m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0"/>
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M19,12m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0"/>
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_cast.xml b/packages/SystemUI/res/drawable/ic_cast.xml
new file mode 100644
index 0000000..a2c2eb2
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_cast.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2017 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24.0"
+    android:viewportHeight="24.0">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M21,3L3,3c-1.1,0 -2,0.9 -2,2v3h2L3,5h18v14h-7v2h7c1.1,0 2,-0.9 2,-2L23,5c0,-1.1 -0.9,-2 -2,-2zM1,18v3h3c0,-1.66 -1.34,-3 -3,-3zM1,14v2c2.76,0 5,2.24 5,5h2c0,-3.87 -3.13,-7 -7,-7zM1,10v2c4.97,0 9,4.03 9,9h2c0,-6.08 -4.93,-11 -11,-11z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_cast_connected.xml b/packages/SystemUI/res/drawable/ic_cast_connected.xml
new file mode 100644
index 0000000..995fd49
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_cast_connected.xml
@@ -0,0 +1,26 @@
+<!--
+Copyright (C) 2017 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="17dp"
+        android:height="17dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M1,18v3h3C4,19.34 2.66,18 1,18zM1,14v2c2.76,0 5,2.24 5,5h2C8,17.13 4.87,14 1,14zM19,7H5v1.63c3.96,1.28 7.09,4.41 8.37,8.37H19V7zM1,10v2c4.97,0 9,4.03 9,9h2C12,14.92 7.07,10 1,10zM21,3H3C1.9,3 1,3.9 1,5v3h2V5h18v14h-7v2h7c1.1,0 2,-0.9 2,-2V5C23,3.9 22.1,3 21,3"/>
+
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_data_saver.xml b/packages/SystemUI/res/drawable/ic_data_saver.xml
index 0f027ee..cc3f539 100644
--- a/packages/SystemUI/res/drawable/ic_data_saver.xml
+++ b/packages/SystemUI/res/drawable/ic_data_saver.xml
@@ -14,15 +14,11 @@
     limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
+    android:width="18dp"
+    android:height="18dp"
     android:viewportWidth="24.0"
-    android:viewportHeight="24.0"
-    android:tint="?android:attr/colorControlNormal">
+    android:viewportHeight="24.0">
     <path
-        android:pathData="M16,12c0,0.55 -0.45,1 -1,1h-2v2c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1v-2L9,13c-0.55,0 -1,-0.45 -1,-1s0.45,-1 1,-1h2L11,9c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v2h2c0.55,0 1,0.45 1,1zM17.69,16.87a7.437,7.437 0,0 1,-5.93 2.63c-3.82,-0.12 -7.03,-3.25 -7.25,-7.07 -0.21,-3.84 2.48,-7.1 6.07,-7.79 0.24,-0.04 0.42,-0.24 0.42,-0.48L11,2.62c0,-0.3 -0.27,-0.55 -0.57,-0.5A10.02,10.02 0,0 0,2.09 13.4c0.59,4.4 4.16,7.94 8.56,8.52a9.99,9.99 0,0 0,9.14 -3.65,0.5 0.5,0 0,0 -0.15,-0.74l-1.32,-0.76a0.469,0.469 0,0 0,-0.63 0.1z"
+        android:pathData="M11,8v3L8,11v2h3v3h2v-3h3v-2h-3L13,8zM13,2.05v3.03c3.39,0.49 6,3.39 6,6.92 0,0.9 -0.18,1.75 -0.48,2.54l2.6,1.53c0.56,-1.24 0.88,-2.62 0.88,-4.07 0,-5.18 -3.95,-9.45 -9,-9.95zM12,19c-3.87,0 -7,-3.13 -7,-7 0,-3.53 2.61,-6.43 6,-6.92L11,2.05c-5.06,0.5 -9,4.76 -9,9.95 0,5.52 4.47,10 9.99,10 3.31,0 6.24,-1.61 8.06,-4.09l-2.6,-1.53C16.17,17.98 14.21,19 12,19z"
         android:fillColor="#FFFFFFFF"/>
-    <path
-        android:pathData="M13.41,4.64a0.493,0.493 0,0 1,-0.41 -0.48L13,2.62c0,-0.3 0.27,-0.55 0.57,-0.5C18.35,2.88 22,7.01 22,12c0,1.23 -0.23,2.41 -0.64,3.5 -0.11,0.28 -0.45,0.4 -0.72,0.24l-1.33,-0.77a0.484,0.484 0,0 1,-0.21 -0.59c0.25,-0.75 0.39,-1.55 0.39,-2.38 0.01,-3.65 -2.62,-6.69 -6.08,-7.36z"
-        android:fillColor="#54FFFFFF" />
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_data_saver_off.xml b/packages/SystemUI/res/drawable/ic_data_saver_off.xml
index 29e6c91..d8e9bc4 100644
--- a/packages/SystemUI/res/drawable/ic_data_saver_off.xml
+++ b/packages/SystemUI/res/drawable/ic_data_saver_off.xml
@@ -17,9 +17,8 @@
         android:width="24.0dp"
         android:height="24.0dp"
         android:viewportWidth="24.0"
-        android:viewportHeight="24.0"
-        android:tint="?android:attr/colorControlNormal">
+        android:viewportHeight="24.0">
     <path
         android:fillColor="#FFFFFFFF"
-        android:pathData="M18.32,16.75l1.32,0.76c0.26,0.15 0.34,0.51 0.15,0.74 -2.09,2.6 -5.44,4.14 -9.14,3.65 -4.4,-0.58 -7.96,-4.12 -8.56,-8.52C1.34,7.8 5.21,2.95 10.43,2.12c0.3,-0.05 0.57,0.2 0.57,0.5v1.53c0,0.24 -0.18,0.44 -0.41,0.49 -3.6,0.69 -6.29,3.95 -6.07,7.79 0.21,3.82 3.43,6.95 7.25,7.07 2.37,0.08 4.51,-0.96 5.93,-2.63a0.48,0.48 0,0 1,0.62 -0.12zM19.5,12c0,0.83 -0.14,1.63 -0.39,2.38 -0.08,0.23 0.01,0.47 0.21,0.59l1.33,0.77c0.26,0.15 0.61,0.04 0.72,-0.24 0.4,-1.09 0.63,-2.27 0.63,-3.5 0,-4.99 -3.65,-9.12 -8.43,-9.88 -0.3,-0.04 -0.57,0.2 -0.57,0.5v1.53c0,0.24 0.18,0.44 0.41,0.48 3.46,0.68 6.09,3.72 6.09,7.37z" />
+        android:pathData="M13,2.05v3.03c3.39,0.49 6,3.39 6,6.92 0,0.9 -0.18,1.75 -0.48,2.54l2.6,1.53c0.56,-1.24 0.88,-2.62 0.88,-4.07 0,-5.18 -3.95,-9.45 -9,-9.95zM12,19c-3.87,0 -7,-3.13 -7,-7 0,-3.53 2.61,-6.43 6,-6.92V2.05c-5.06,0.5 -9,4.76 -9,9.95 0,5.52 4.47,10 9.99,10 3.31,0 6.24,-1.61 8.06,-4.09l-2.6,-1.53C16.17,17.98 14.21,19 12,19z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_dnd.xml b/packages/SystemUI/res/drawable/ic_dnd.xml
deleted file mode 100644
index 09a6aab..0000000
--- a/packages/SystemUI/res/drawable/ic_dnd.xml
+++ /dev/null
@@ -1,30 +0,0 @@
-<!--
-     Copyright (C) 2017 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:height="24dp"
-    android:viewportHeight="24.0"
-    android:viewportWidth="24.0"
-    android:width="24dp"
-    android:tint="?android:attr/colorControlNormal">
-
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M12,2C6.48,2 2,6.48 2,12c0,5.52 4.48,10 10,10c5.52,0 10,-4.48 10,-10C22,6.48 17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8c0,-4.41 3.59,-8 8,-8c4.41,0 8,3.59 8,8C20,16.41 16.41,20 12,20z"/>
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M7,11h10v2h-10z"/>
-
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_headset.xml b/packages/SystemUI/res/drawable/ic_headset.xml
index 27efe80..797a80a 100644
--- a/packages/SystemUI/res/drawable/ic_headset.xml
+++ b/packages/SystemUI/res/drawable/ic_headset.xml
@@ -13,19 +13,12 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<inset xmlns:android="http://schemas.android.com/apk/res/android"
-    android:insetLeft="2.5dp"
-    android:insetRight="2.5dp">
-    <vector
-        android:width="17.0dp"
-        android:height="17.0dp"
-        android:viewportWidth="24"
-        android:viewportHeight="24">
-        <group
-            android:translateY="-1">
-            <path
-                android:fillColor="#FFFFFFFF"
-                android:pathData="M19,15v3c0,0.55 -0.45,1 -1,1h-1v-4H19M7,15v4H6c-0.55,0 -1,-0.45 -1,-1v-3H7M12,2c-4.97,0 -9,4.03 -9,9v7c0,1.66 1.34,3 3,3h3v-8H5v-2c0,-3.87 3.13,-7 7,-7s7,3.13 7,7v2h-4v8h3c1.66,0 3,-1.34 3,-3v-7C21,6.03 16.97,2 12,2L12,2z"/>
-        </group>
-    </vector>
-</inset>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="17.0dp"
+    android:height="17.0dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M19,15v3c0,0.55 -0.45,1 -1,1h-1v-4h2M7,15v4H6c-0.55,0 -1,-0.45 -1,-1v-3h2m5,-13c-4.97,0 -9,4.03 -9,9v7c0,1.66 1.34,3 3,3h3v-8H5v-2c0,-3.87 3.13,-7 7,-7s7,3.13 7,7v2h-4v8h3c1.66,0 3,-1.34 3,-3v-7c0,-4.97 -4.03,-9 -9,-9z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_headset_mic.xml b/packages/SystemUI/res/drawable/ic_headset_mic.xml
index 1260e0f..b3f006d 100644
--- a/packages/SystemUI/res/drawable/ic_headset_mic.xml
+++ b/packages/SystemUI/res/drawable/ic_headset_mic.xml
@@ -13,16 +13,12 @@
     See the License for the specific language governing permissions and
     limitations under the License.
 -->
-<inset xmlns:android="http://schemas.android.com/apk/res/android"
-    android:insetLeft="2.5dp"
-    android:insetRight="2.5dp">
-    <vector
-        android:width="17.0dp"
-        android:height="17.0dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
-        <path
-            android:fillColor="#FFFFFFFF"
-            android:pathData="M12,1c-4.97,0 -9,4.03 -9,9v7c0,1.66 1.34,3 3,3h3v-8H5v-1.71C5,6.45 7.96,3.11 11.79,3C15.76,2.89 19,6.06 19,10v2h-4v8h4v1h-6v2h6c1.1,0 2,-0.9 2,-2V10C21,5.03 16.97,1 12,1zM7,14v4H6c-0.55,0 -1,-0.45 -1,-1v-3H7zM19,18h-2v-4h2V18z"/>
-    </vector>
-</inset>
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="17.0dp"
+    android:height="17.0dp"
+    android:viewportWidth="24.0"
+    android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M12,1c-4.97,0 -9,4.03 -9,9v7c0,1.66 1.34,3 3,3h3v-8H5v-1.71C5,6.45 7.96,3.11 11.79,3C15.76,2.89 19,6.06 19,10v2h-4v8h4v1h-6v2h6c1.1,0 2,-0.9 2,-2V10C21,5.03 16.97,1 12,1zM7,14v4H6c-0.55,0 -1,-0.45 -1,-1v-3H7zM19,18h-2v-4h2V18z" />
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_hotspot.xml b/packages/SystemUI/res/drawable/ic_hotspot.xml
index 8450bf6..b6fa798 100644
--- a/packages/SystemUI/res/drawable/ic_hotspot.xml
+++ b/packages/SystemUI/res/drawable/ic_hotspot.xml
@@ -15,14 +15,12 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="48dp"
-    android:height="48dp"
+    android:width="18dp"
+    android:height="18dp"
     android:viewportWidth="24.0"
     android:viewportHeight="24.0">
-    <group
-        android:translateY="-0.32">
-        <path
-            android:pathData="M12,11c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM18,13a6,6 0,0 0,-6.75 -5.95c-2.62,0.32 -4.78,2.41 -5.18,5.02 -0.32,2.14 0.49,4.11 1.92,5.39 0.48,0.43 1.24,0.33 1.56,-0.23 0.24,-0.42 0.14,-0.94 -0.22,-1.26a3.99,3.99 0,0 1,-1.22 -3.94,3.954 3.954,0 0,1 2.9,-2.91A4.007,4.007 0,0 1,16 13c0,1.18 -0.51,2.23 -1.33,2.96 -0.36,0.33 -0.47,0.85 -0.23,1.27 0.31,0.54 1.04,0.69 1.5,0.28A5.97,5.97 0,0 0,18 13zM10.83,3.07c-4.62,0.52 -8.35,4.33 -8.78,8.96a9.966,9.966 0,0 0,4.02 9.01c0.48,0.35 1.16,0.2 1.46,-0.31 0.25,-0.43 0.14,-0.99 -0.26,-1.29 -2.28,-1.69 -3.65,-4.55 -3.16,-7.7 0.54,-3.5 3.46,-6.29 6.98,-6.68C15.91,4.51 20,8.28 20,13c0,2.65 -1.29,4.98 -3.27,6.44 -0.4,0.3 -0.51,0.85 -0.26,1.29 0.3,0.52 0.98,0.66 1.46,0.31A9.96,9.96 0,0 0,22 13c0,-5.91 -5.13,-10.62 -11.17,-9.93z"
-            android:fillColor="#FFFFFFFF"/>
-    </group>
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M12,7c-3.31,0 -6,2.69 -6,6 0,1.66 0.68,3.15 1.76,4.24l1.42,-1.42C8.45,15.1 8,14.11 8,13c0,-2.21 1.79,-4 4,-4s4,1.79 4,4c0,1.11 -0.45,2.1 -1.18,2.82l1.42,1.42C17.32,16.15 18,14.66 18,13c0,-3.31 -2.69,-6 -6,-6zM12,3C6.48,3 2,7.48 2,13c0,2.76 1.12,5.26 2.93,7.07l1.41,-1.41C4.9,17.21 4,15.21 4,13c0,-4.42 3.58,-8 8,-8s8,3.58 8,8c0,2.21 -0.9,4.2 -2.35,5.65l1.41,1.41C20.88,18.26 22,15.76 22,13c0,-5.52 -4.48,-10 -10,-10zM12,11c-1.1,0 -2,0.9 -2,2 0,0.55 0.23,1.05 0.59,1.41 0.36,0.36 0.86,0.59 1.41,0.59s1.05,-0.23 1.41,-0.59c0.36,-0.36 0.59,-0.86 0.59,-1.41 0,-1.1 -0.9,-2 -2,-2z" />
+
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_hotspot_unavailable.xml b/packages/SystemUI/res/drawable/ic_hotspot_unavailable.xml
deleted file mode 100644
index 7641998..0000000
--- a/packages/SystemUI/res/drawable/ic_hotspot_unavailable.xml
+++ /dev/null
@@ -1,61 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:name="root"
-    android:height="48dp"
-    android:width="48dp"
-    android:viewportHeight="48"
-    android:viewportWidth="48" >
-    <group
-        android:name="ic_hotspot"
-        android:translateX="23.97354"
-        android:translateY="24.26306" >
-        <group
-            android:name="ic_hotspot_pivot"
-            android:translateX="-23.21545"
-            android:translateY="-18.86649" >
-            <clip-path
-                android:name="mask"
-                android:pathData="M 38.8337860107,-40.3974914551 c 0.0,0.0 -38.4077911377,30.8523712158 -38.4077911377,30.8523712158 c 0.0,0.0 43.1884765625,43.515335083 43.1884765625,43.515335083 c 0.0,0.0 -2.4169921875,2.57838439941 -2.4169921875,2.57838439941 c 0.0,0.0 -42.9885101318,-43.0112609863 -42.9885101318,-43.0112609863 c 0.0,0.0 -32.6199798584,25.1699066162 -32.6199798584,25.1699066162 c 0.0,0.0 55.9664764404,69.742401123 55.9664764404,69.742401123 c 0.0,0.0 27.6589050293,-22.6579437256 27.6589050293,-22.6579437256 c 0.0,0.0 -30.8645172119,-34.00390625 -30.8645172119,-34.00390625 c 0.0,0.0 2.70756530762,-1.99278259277 2.70756530762,-1.99278259277 c 0.0,0.0 1.53030395508,-0.876571655273 1.53030395508,-0.876571655274 c 0.0,0.0 2.85780334473,-3.12069702148 2.85780334473,-3.12069702148 c 0.0,0.0 13.0984039307,13.025604248 13.0984039307,13.025604248 c 0.0,0.0 -3.13299560547,2.82977294922 -3.13299560547,2.82977294922 c 0.0,0.0 16.571762085,22.0471801758 16.571762085,22.0471801758 c 0.0,0.0 42.8175811768,-34.3554534912 42.8175811768,-34.3554534912 c 0.0,0.0 -55.9664916992,-69.7423400879 -55.9664916992,-69.7423400879 Z" />
-            <group
-                android:name="cross" >
-                <path
-                    android:name="cross_1"
-                    android:pathData="M 4.44044494629,2.24310302734 c 0.0,0.0 35.4000396729,35.3999633789 35.4000396729,35.3999633789 "
-                    android:strokeColor="#FFFFFFFF"
-                    android:strokeAlpha="1"
-                    android:strokeWidth="3.5"
-                    android:fillColor="#00000000" />
-            </group>
-            <group
-                android:name="hotspot"
-                android:translateX="23.481"
-                android:translateY="18.71151" >
-                <group
-                    android:name="circles"
-                    android:translateX="-0.23909"
-                    android:translateY="-0.10807" >
-                    <path
-                        android:name="circle_3"
-                        android:pathData="M 0.0843505859375,-2.93901062012 c -2.30102539062,0.0 -4.16702270508,1.86602783203 -4.16702270508,4.16702270508 c 0.0,2.29898071289 1.86599731445,4.16598510742 4.16702270508,4.16598510742 c 2.29998779297,0.0 4.16598510742,-1.86700439453 4.16598510742,-4.16598510742 c 0.0,-2.30099487305 -1.86599731445,-4.16702270508 -4.16598510742,-4.16702270508 Z M 11.1185302734,5.83390808105 c 0.0,0.0 0.0009765625,0.00100708007812 0.0009765625,0.00100708007812 c 0.14501953125,-0.356994628906 0.27099609375,-0.725006103516 0.382995605469,-1.09799194336 c 0.0570068359375,-0.195007324219 0.101013183594,-0.394989013672 0.149017333984,-0.595001220703 c 0.0690002441406,-0.281005859375 0.126983642578,-0.563995361328 0.175994873047,-0.851989746094 c 0.0270080566406,-0.169006347656 0.0559997558594,-0.337005615234 0.0759887695313,-0.509002685547 c 0.0580139160156,-0.468017578125 0.0970153808594,-0.942993164062 0.0970153808593,-1.4280090332 c 0.0,0.0 0.0,-0.00100708007812 0.0,-0.00100708007812 c 0.0,-5.03900146484 -3.11099243164,-9.3450012207 -7.5119934082,-11.1229858398 c -0.00601196289062,-0.00299072265625 -0.0130004882812,-0.0050048828125 -0.0190124511719,-0.00701904296875 c -0.686004638672,-0.275970458984 -1.39999389648,-0.492980957031 -2.14099121094,-0.638977050781 c -0.072998046875,-0.0150146484375 -0.149017333984,-0.02099609375 -0.222991943359,-0.0339965820313 c -0.302001953125,-0.0540161132812 -0.605010986328,-0.106018066406 -0.916015625,-0.136016845703 c -0.389984130859,-0.0390014648438 -0.786987304688,-0.0599975585938 -1.18899536133,-0.0599975585937 c -0.402008056641,0.0 -0.799011230469,0.02099609375 -1.19000244141,0.0599975585937 c -0.304992675781,0.0299987792969 -0.602996826172,0.0809936523438 -0.901000976563,0.132995605469 c -0.0790100097656,0.0150146484375 -0.160003662109,0.02099609375 -0.238006591797,0.0370178222656 c -0.368988037109,0.0719909667969 -0.730987548828,0.164001464844 -1.08700561523,0.269989013672 c -0.00299072265625,0.00100708007812 -0.0059814453125,0.00201416015625 -0.00900268554687,0.0020141601562 c -0.351989746094,0.10498046875 -0.694000244141,0.226989746094 -1.0309753418,0.361999511719 c -0.0110168457031,0.00399780273438 -0.0220031738281,0.00698852539062 -0.0320129394531,0.0119934082031 c -4.40200805664,1.77798461914 -7.51098632812,6.083984375 -7.5119934082,11.1229858398 c 0.0,0.00799560546875 0.00198364257812,0.0160217285156 0.0019836425781,0.0240173339844 c 0.00100708007812,0.475006103516 0.0380249023438,0.940002441406 0.0950012207032,1.39898681641 c 0.02001953125,0.175994873047 0.0490112304688,0.348999023438 0.0780029296875,0.523010253906 c 0.0469970703125,0.281982421875 0.105010986328,0.557983398438 0.171997070312,0.833984375 c 0.0480041503906,0.204010009766 0.093017578125,0.410003662109 0.152008056641,0.610015869141 c 0.110992431641,0.372009277344 0.238006591797,0.736999511719 0.382019042969,1.09298706055 c 0.0,0.0 0.0009765625,0.0 0.0009765625,0.0 c 1.00701904297,2.48400878906 2.81301879883,4.56100463867 5.11001586914,5.89501953125 c 0.0,0.0 2.01599121094,-3.48300170898 2.01599121094,-3.48300170898 c -2.03900146484,-1.18402099609 -3.5119934082,-3.22500610352 -3.89898681641,-5.63900756836 c 0.0,0.0 0.0009765625,-0.00100708007812 0.0009765625,-0.00100708007812 c -0.0220031738281,-0.130981445312 -0.0369873046875,-0.265991210938 -0.052978515625,-0.399993896484 c -0.0290222167969,-0.274993896484 -0.0570068359375,-0.552001953125 -0.0570068359375,-0.834991455078 c 0.0,0.0 0.0,-0.0190124511719 0.0,-0.0190124511719 c 0.0,-3.98999023438 2.92498779297,-7.28900146484 6.74398803711,-7.89199829102 c 0.0,0.0 0.0180053710938,0.0169982910156 0.0180053710938,0.0169982910156 c 0.404998779297,-0.0639953613281 0.81298828125,-0.125 1.23599243164,-0.125 c 0.0,0.0 0.00201416015625,0.0 0.00201416015624,0.0 c 0.0,0.0 0.00299072265625,0.0 0.00299072265626,0.0 c 0.423004150391,0.0 0.830017089844,0.0610046386719 1.23501586914,0.125 c 0.0,0.0 0.0169982910156,-0.0180053710938 0.0169982910156,-0.0180053710938 c 3.81997680664,0.60400390625 6.74499511719,3.90301513672 6.74499511719,7.89199829102 c 0.0,0.292999267578 -0.0280151367188,0.578002929688 -0.0589904785156,0.861999511719 c -0.0150146484375,0.132019042969 -0.0290222167969,0.264007568359 -0.051025390625,0.393005371094 c -0.385986328125,2.41500854492 -1.85897827148,4.45599365234 -3.89797973633,5.64001464844 c 0.0,0.0 2.01599121094,3.48300170898 2.01599121094,3.48300170898 c 2.29699707031,-1.33401489258 4.10299682617,-3.41101074219 5.11001586914,-5.89602661133 Z M 19.9300231934,2.95698547363 c 0.0059814453125,-0.0659790039062 0.0159912109375,-0.130981445312 0.02099609375,-0.196990966797 c 0.031982421875,-0.462005615234 0.0479736328125,-0.928009033203 0.0489807128906,-1.39700317383 c 0,0.0 0,-0.00997924804688 0,-0.00997924804687 c 0,0.0 0,-0.00100708007812 0,-0.00100708007813 c 0,-7.22500610352 -3.84399414062,-13.5360107422 -9.58599853516,-17.0500183105 c -1.06500244141,-0.652984619141 -2.19299316406,-1.20599365234 -3.37799072266,-1.65197753906 c -0.157989501953,-0.0599975585938 -0.317016601562,-0.118011474609 -0.476989746094,-0.174011230469 c -0.317016601562,-0.110992431641 -0.634002685547,-0.218994140625 -0.9580078125,-0.31298828125 c -0.470001220703,-0.139007568359 -0.944000244141,-0.264007568359 -1.4280090332,-0.368011474609 c -0.186004638672,-0.0390014648438 -0.376983642578,-0.0669860839844 -0.565002441406,-0.101013183594 c -0.414001464844,-0.0759887695312 -0.832000732422,-0.140991210938 -1.25500488281,-0.190979003906 c -0.184997558594,-0.0220031738281 -0.369995117188,-0.0429992675781 -0.556976318359,-0.0599975585937 c -0.592010498047,-0.0530090332031 -1.18801879883,-0.0899963378906 -1.79602050781,-0.0899963378907 c -0.605987548828,0.0 -1.20300292969,0.0369873046875 -1.79598999023,0.0899963378907 c -0.186004638672,0.0169982910156 -0.371002197266,0.0379943847656 -0.555999755859,0.0599975585937 c -0.423004150391,0.0499877929688 -0.842010498047,0.114990234375 -1.25601196289,0.190979003906 c -0.18798828125,0.0350036621094 -0.377990722656,0.06201171875 -0.563995361328,0.101013183594 c -0.483001708984,0.10400390625 -0.959991455078,0.22900390625 -1.42999267578,0.368011474609 c -0.321990966797,0.093994140625 -0.638000488281,0.201995849609 -0.953002929688,0.311981201172 c -0.162994384766,0.0570068359375 -0.324005126953,0.115997314453 -0.484985351562,0.177001953125 c -1.18099975586,0.445007324219 -2.30599975586,0.997009277344 -3.36801147461,1.64700317383 c -0.00201416015625,0.00100708007812 -0.00399780273438,0.00201416015625 -0.0060119628907,0.0029907226562 c -5.74099731445,3.51400756836 -9.58499145508,9.82501220703 -9.58599853516,17.0500183105 c 0,0.0 0,0.00100708007812 0,0.00100708007813 c 0,0.0059814453125 0.00100708007812,0.0130004882812 0.0010070800781,0.0199890136719 c 0.0,0.466003417969 0.0169982910156,0.928009033203 0.0490112304688,1.38598632812 c 0.0050048828125,0.0690002441406 0.0159912109375,0.136016845703 0.02099609375,0.206024169922 c 0.031982421875,0.401000976562 0.0719909667969,0.799987792969 0.127990722656,1.19400024414 c 0.00201416015625,0.0189819335938 0.00701904296875,0.0369873046875 0.010009765625,0.0569763183594 c 0.888000488281,6.17202758789 4.59799194336,11.4250183105 9.7799987793,14.4309997559 c 0.0,0.0 2.00198364258,-3.458984375 2.00198364258,-3.458984375 c -2.58599853516,-1.5 -4.708984375,-3.70401000977 -6.11697387695,-6.34399414063 c 0.0,0.0 0.0169982910156,-0.0180053710938 0.0169982910156,-0.0180053710938 c -0.890014648438,-1.67098999023 -1.50601196289,-3.5110168457 -1.76000976562,-5.46499633789 c -0.00698852539062,-0.0500183105469 -0.010009765625,-0.102020263672 -0.0159912109375,-0.152008056641 c -0.0330200195312,-0.273010253906 -0.0610046386719,-0.545989990234 -0.0800170898437,-0.821990966797 c -0.0220031738281,-0.343017578125 -0.0350036621094,-0.68701171875 -0.0350036621094,-1.03500366211 c 0,-6.53701782227 3.92599487305,-12.1480102539 9.54299926758,-14.6310119629 c 0.157012939453,-0.0700073242188 0.313995361328,-0.135986328125 0.472015380859,-0.199981689453 c 0.373992919922,-0.151000976562 0.751983642578,-0.294006347656 1.13900756836,-0.417022705078 c 0.108978271484,-0.0350036621094 0.221984863281,-0.0619812011719 0.332000732422,-0.0950012207031 c 0.349975585938,-0.102996826172 0.705993652344,-0.194976806641 1.06597900391,-0.273986816406 c 0.114013671875,-0.0249938964844 0.227996826172,-0.052001953125 0.342010498047,-0.0750122070313 c 0.440002441406,-0.0869750976562 0.885986328125,-0.154998779297 1.33700561523,-0.203979492188 c 0.10400390625,-0.0120239257812 0.209991455078,-0.02001953125 0.315002441406,-0.0299987792969 c 0.47998046875,-0.0429992675781 0.963989257812,-0.072998046875 1.45397949219,-0.072998046875 c 0.492004394531,0.0 0.975006103516,0.0299987792969 1.45401000977,0.072998046875 c 0.105987548828,0.00997924804688 0.212005615234,0.0179748535156 0.316986083984,0.0299987792969 c 0.450012207031,0.0489807128906 0.89501953125,0.117004394531 1.33502197266,0.203002929688 c 0.115997314453,0.0239868164062 0.22998046875,0.0509948730469 0.345001220703,0.0769958496094 c 0.358001708984,0.0780029296875 0.710998535156,0.169982910156 1.06097412109,0.272003173828 c 0.111022949219,0.0329895019531 0.226013183594,0.0609741210938 0.336029052734,0.0969848632813 c 0.385986328125,0.123016357422 0.761993408203,0.265014648438 1.13497924805,0.415008544922 c 0.160003662109,0.0650024414062 0.319000244141,0.131988525391 0.477020263672,0.201995849609 c 5.61599731445,2.48400878906 9.53997802734,8.09399414062 9.53997802734,14.6310119629 c 0,0.346984863281 -0.0130004882812,0.690979003906 -0.0350036621094,1.03399658203 c -0.0179748535156,0.274993896484 -0.0469970703125,0.548004150391 -0.0789794921875,0.819000244141 c -0.00601196289062,0.052001953125 -0.010009765625,0.10498046875 -0.0160217285156,0.154998779297 c -0.252990722656,1.95498657227 -0.871002197266,3.79400634766 -1.75997924805,5.46499633789 c 0.0,0.0 0.0169982910156,0.0180053710938 0.0169982910156,0.0180053710938 c -1.40802001953,2.63998413086 -3.53100585938,4.84399414062 -6.11700439453,6.34399414063 c 0.0,0.0 2.00198364258,3.458984375 2.00198364258,3.458984375 c 5.18402099609,-3.00698852539 8.89501953125,-8.26300048828 9.78100585938,-14.4379882813 c 0.00201416015625,-0.0169982910156 0.00601196289062,-0.0320129394531 0.0079956054688,-0.0490112304688 c 0.0570068359375,-0.39697265625 0.0970153808594,-0.798980712891 0.129028320312,-1.20300292969 Z"
-                        android:fillColor="#FFFFFFFF"
-                        android:fillAlpha="1" />
-                </group>
-            </group>
-        </group>
-    </group>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_location.xml b/packages/SystemUI/res/drawable/ic_location.xml
new file mode 100644
index 0000000..50ba523
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_location.xml
@@ -0,0 +1,27 @@
+<!--
+  ~ Copyright (C) 2014 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="17dp"
+    android:height="17dp"
+    android:viewportWidth="24.0"
+    android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M12,2C8.13,2 5,5.13 5,9c0,5.25 7,13 7,13s7,-7.75 7,-13C19,5.13 15.87,2 12,2zM7,9c0,-2.76 2.24,-5 5,-5s5,2.24 5,5c0,2.88 -2.88,7.19 -5,9.88C9.92,16.21 7,11.85 7,9z"/>
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M12,9m-2.5,0a2.5,2.5 0,1 1,5 0a2.5,2.5 0,1 1,-5 0"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_bluetooth_connected.xml b/packages/SystemUI/res/drawable/ic_qs_bluetooth_connected.xml
deleted file mode 100644
index dd124b7..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_bluetooth_connected.xml
+++ /dev/null
@@ -1,32 +0,0 @@
-<!--
-Copyright (C) 2017 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24dp"
-        android:height="24dp"
-        android:viewportWidth="24"
-        android:viewportHeight="24"
-        android:tint="?android:attr/colorControlNormal">
-
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M17.71,7.71L12,2h-1v7.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L11,14.41V22h1l5.71-5.71L13.41,12L17.71,7.71z M13,5.83 l1.88,1.88L13,9.59V5.83z M14.88,16.29L13,18.17v-3.76L14.88,16.29z" />
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M 5 10.5 C 5.82842712475 10.5 6.5 11.1715728753 6.5 12 C 6.5 12.8284271247 5.82842712475 13.5 5 13.5 C 4.17157287525 13.5 3.5 12.8284271247 3.5 12 C 3.5 11.1715728753 4.17157287525 10.5 5 10.5 Z" />
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M 19 10.5 C 19.8284271247 10.5 20.5 11.1715728753 20.5 12 C 20.5 12.8284271247 19.8284271247 13.5 19 13.5 C 18.1715728753 13.5 17.5 12.8284271247 17.5 12 C 17.5 11.1715728753 18.1715728753 10.5 19 10.5 Z" />
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_bluetooth_on.xml b/packages/SystemUI/res/drawable/ic_qs_bluetooth_on.xml
index 220c63c..1c86706 100644
--- a/packages/SystemUI/res/drawable/ic_qs_bluetooth_on.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_bluetooth_on.xml
@@ -14,13 +14,11 @@
     limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24dp"
-        android:height="24dp"
-        android:viewportWidth="24"
-        android:viewportHeight="24"
-        android:tint="?android:attr/colorControlNormal">
-
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24.0"
+    android:viewportHeight="24.0">
     <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M17.71,7.71L12,2h-1v7.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L11,14.41V22h1l5.71-5.71L13.41,12L17.71,7.71z M13,5.83 l1.88,1.88L13,9.59V5.83z M14.88,16.29L13,18.17v-3.76L14.88,16.29z" />
-</vector>
+        android:fillColor="@android:color/white"
+        android:pathData="M17.71,7.71L12,2h-1v7.59L6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 11,14.41L11,22h1l5.71,-5.71 -4.3,-4.29 4.3,-4.29zM13,5.83l1.88,1.88L13,9.59L13,5.83zM14.88,16.29L13,18.17v-3.76l1.88,1.88z"/>
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_qs_cast_off.xml b/packages/SystemUI/res/drawable/ic_qs_cast_off.xml
deleted file mode 100644
index 9e57577..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_cast_off.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<!--
-Copyright (C) 2017 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="64dp"
-    android:height="64dp"
-    android:viewportWidth="24.0"
-    android:viewportHeight="24.0">
-    <path
-        android:pathData="M1,18v2c0,0.55 0.45,1 1,1h2c0,-1.66 -1.34,-3 -3,-3zM0.97,15.06c-0.01,0.51 0.35,0.93 0.85,1.02 2.08,0.36 3.74,2 4.1,4.08 0.09,0.48 0.5,0.84 0.99,0.84 0.61,0 1.09,-0.54 1,-1.14a6.996,6.996 0,0 0,-5.8 -5.78c-0.59,-0.09 -1.12,0.38 -1.14,0.98zM0.97,11.03c-0.01,0.52 0.37,0.96 0.88,1.01 4.26,0.43 7.68,3.82 8.1,8.08 0.05,0.5 0.48,0.88 0.99,0.88 0.59,0 1.06,-0.51 1,-1.1 -0.52,-5.21 -4.66,-9.34 -9.87,-9.85 -0.57,-0.05 -1.08,0.4 -1.1,0.98zM21,3L3,3c-1.1,0 -2,0.9 -2,2v3h2L3,5h18v14h-7v2h7c1.1,0 2,-0.9 2,-2L23,5c0,-1.1 -0.9,-2 -2,-2z"
-        android:fillColor="#FFFFFFFF" />
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_cast_on.xml b/packages/SystemUI/res/drawable/ic_qs_cast_on.xml
deleted file mode 100644
index 3dda87c..0000000
--- a/packages/SystemUI/res/drawable/ic_qs_cast_on.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<!--
-Copyright (C) 2017 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="64dp"
-        android:height="64dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
-
-    <path
-        android:fillColor="#FFFFFFFF"
-        android:pathData="M1,18v2c0,0.55 0.45,1 1,1h2c0,-1.66 -1.34,-3 -3,-3zM0.97,15.06c-0.01,0.51 0.35,0.93 0.85,1.02 2.08,0.36 3.74,2 4.1,4.08 0.09,0.48 0.5,0.84 0.99,0.84 0.61,0 1.09,-0.54 1,-1.14a6.996,6.996 0,0 0,-5.8 -5.78c-0.59,-0.09 -1.12,0.38 -1.14,0.98zM19,7L5,7v1.63c3.96,1.28 7.09,4.41 8.37,8.37L19,17L19,7zM0.97,11.03c-0.01,0.52 0.37,0.96 0.88,1.01 4.26,0.43 7.68,3.82 8.1,8.08 0.05,0.5 0.48,0.88 0.99,0.88 0.59,0 1.06,-0.51 1,-1.1 -0.52,-5.21 -4.66,-9.34 -9.87,-9.85 -0.57,-0.05 -1.08,0.4 -1.1,0.98zM21,3L3,3c-1.1,0 -2,0.9 -2,2v3h2L3,5h18v14h-7v2h7c1.1,0 2,-0.9 2,-2L23,5c0,-1.1 -0.9,-2 -2,-2z" />
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_signal_workmode_disable.xml b/packages/SystemUI/res/drawable/ic_signal_workmode_disable.xml
deleted file mode 100644
index 96d8484..0000000
--- a/packages/SystemUI/res/drawable/ic_signal_workmode_disable.xml
+++ /dev/null
@@ -1,122 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<vector
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:name="ic_signal_workmode_disable"
-    android:width="42dp"
-    android:viewportWidth="42"
-    android:height="42dp"
-    android:viewportHeight="42" >
-    <group
-        android:name="suitcase"
-        android:translateX="21"
-        android:translateY="36.9375"
-        android:scaleX="0.1"
-        android:scaleY="0.1" >
-        <group
-            android:name="suitcase_pivot"
-            android:translateY="-158" >
-            <clip-path
-                android:name="mask_1"
-                android:pathData="M 366.5,-269.5 c 0.0,0.0 -578.0,2.0 -578.0,2.0 c 0.0,0.0 65.7498321533,68.2501220703 65.7498321533,68.2501220703 c 0.0,0.0 -20.7500457764,20.7500610352 -20.7500457764,20.7500610352 c 0.0,0.0 -65.749786377,-68.2501983643 -65.749786377,-68.2501983643 c 0.0,0.0 -7.25,539.250015259 -7.25,539.250015259 c 0.0,0.0 606.0,0.0 606.0,0.0 c 0.0,0.0 0.0,-562.0 0.0,-562.0 Z" />
-            <group
-                android:name="whole"
-                android:translateX="-1.11523"
-                android:translateY="32.0918" >
-                <path
-                    android:name="rectangle_path_1"
-                    android:strokeColor="#FFFFFFFF"
-                    android:strokeWidth="65"
-                    android:pathData="M 0.0,-66.5 l 0.0,0.0 c 36.7269358617,0.0 66.5,29.7730641383 66.5,66.5 l 0.0,0.0 c 0.0,36.7269358617 -29.7730641383,66.5 -66.5,66.5 l 0.0,0.0 c -36.7269358617,0.0 -66.5,-29.7730641383 -66.5,-66.5 l 0.0,0.0 c 0.0,-36.7269358617 29.7730641383,-66.5 66.5,-66.5 Z" />
-            </group>
-            <group
-                android:name="handle"
-                android:translateY="-100" >
-                <path
-                    android:name="rectangle_path_2"
-                    android:strokeColor="#FFFFFFFF"
-                    android:strokeWidth="35"
-                    android:pathData="M -34.0,-50.0 l 68.0,0.0 c 8.8365559968,0.0 16.0,7.1634440032 16.0,16.0 l 0.0,68.0 c 0.0,8.8365559968 -7.1634440032,16.0 -16.0,16.0 l -68.0,0.0 c -8.8365559968,0.0 -16.0,-7.1634440032 -16.0,-16.0 l 0.0,-68.0 c 0.0,-8.8365559968 7.1634440032,-16.0 16.0,-16.0 Z" />
-            </group>
-            <group
-                android:name="case"
-                android:translateY="32.68518" >
-                <group
-                    android:name="case_pivot"
-                    android:translateY="-32.68518" >
-                    <group
-                        android:name="bottom"
-                        android:translateY="-97.62964" >
-                        <group
-                            android:name="bottom_pivot"
-                            android:translateY="40" >
-                            <group
-                                android:name="rectangle_path_3_position" >
-                                <path
-                                    android:name="rectangle_path_3"
-                                    android:fillColor="#FFFFFFFF"
-                                    android:pathData="M -143.0,-40.0 l 286.0,0.0 c 17.6731119936,0.0 32.0,14.3268880064 32.0,32.0 l 0.0,16.0 c 0.0,17.6731119936 -14.3268880064,32.0 -32.0,32.0 l -286.0,0.0 c -17.6731119936,0.0 -32.0,-14.3268880064 -32.0,-32.0 l 0.0,-16.0 c 0.0,-17.6731119936 14.3268880064,-32.0 32.0,-32.0 Z" />
-                            </group>
-                        </group>
-                    </group>
-                    <group
-                        android:name="top"
-                        android:translateY="163" >
-                        <group
-                            android:name="top_pivot"
-                            android:translateY="-40" >
-                            <group
-                                android:name="rectangle_path_4_position" >
-                                <path
-                                    android:name="rectangle_path_4"
-                                    android:fillColor="#FFFFFFFF"
-                                    android:pathData="M -143.0,-40.0 l 286.0,0.0 c 17.6731119936,0.0 32.0,14.3268880064 32.0,32.0 l 0.0,16.0 c 0.0,17.6731119936 -14.3268880064,32.0 -32.0,32.0 l -286.0,0.0 c -17.6731119936,0.0 -32.0,-14.3268880064 -32.0,-32.0 l 0.0,-16.0 c 0.0,-17.6731119936 14.3268880064,-32.0 32.0,-32.0 Z" />
-                            </group>
-                        </group>
-                    </group>
-                    <group
-                        android:name="left"
-                        android:translateX="-175.00635"
-                        android:translateY="30" >
-                        <group
-                            android:name="left_pivot"
-                            android:translateX="50.00635" >
-                            <path
-                                android:name="rectangle_path_5"
-                                android:fillColor="#FFFFFFFF"
-                                android:pathData="M -50.0,-88.0 l 100.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,176.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l -100.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-176.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z" />
-                        </group>
-                    </group>
-                    <group
-                        android:name="right"
-                        android:translateX="174.97778"
-                        android:translateY="30" >
-                        <group
-                            android:name="right_pivot"
-                            android:translateX="-49.97778" >
-                            <path
-                                android:name="rectangle_path_6"
-                                android:fillColor="#FFFFFFFF"
-                                android:pathData="M -50.0,-88.0 l 100.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,176.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l -100.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-176.0 c 0.0,0.0 0.0,0.0 0.0,0.0 Z" />
-                        </group>
-                    </group>
-                </group>
-            </group>
-            <group
-                android:name="stick"
-                android:translateX="-166.59082"
-                android:translateY="-156.51367"
-                android:scaleY="0"
-                android:rotation="-45" >
-                <group
-                    android:name="stick_pivot"
-                    android:translateX="0.18161"
-                    android:translateY="243.8158" >
-                    <path
-                        android:name="stickito"
-                        android:fillColor="#FFFFFFFF"
-                        android:pathData="M -16.5,-243.999885 l 33.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,487.99977 c 0.0,0.0 0.0,0.0 0.0,0.0 l -33.0,0.0 c 0.0,0.0 0.0,0.0 0.0,0.0 l 0.0,-487.99977 c 0.0,0.0 0.0,0.0 0.0,0.0 Z" />
-                </group>
-            </group>
-        </group>
-    </group>
-</vector>
diff --git a/packages/SystemUI/res/drawable/ic_volume_alarm.xml b/packages/SystemUI/res/drawable/ic_volume_alarm.xml
index 996e488..771b466 100644
--- a/packages/SystemUI/res/drawable/ic_volume_alarm.xml
+++ b/packages/SystemUI/res/drawable/ic_volume_alarm.xml
@@ -14,14 +14,12 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:height="24.0dp"
-    android:viewportHeight="24.0"
-    android:viewportWidth="24.0"
-    android:width="24.0dp"
-    android:tint="?android:attr/colorControlNormal">
-
+    android:height="24dp"
+    android:width="24dp"
+    android:viewportHeight="24"
+    android:viewportWidth="24">
     <path
         android:fillColor="#FFFFFF"
-        android:pathData="M2.7,6.5c-0.4,-0.4 -0.3,-1 0.1,-1.4l3,-2.6c0.4,-0.4 1,-0.3 1.4,0.1C7.6,3 7.5,3.7 7.1,4l-3,2.6C3.6,7 3,6.9 2.7,6.5zM21.3,5.1l-3.1,-2.6c-0.4,-0.4 -0.99,-0.31 -1.4,0.1c-0.4,0.4 -0.3,1 0.1,1.4L20,6.6c0.41,0.37 1,0.3 1.4,-0.1C21.73,6.12 21.7,5.4 21.3,5.1zM21,13c0,5 -4,9 -9,9s-9,-4 -9,-9s4,-9 9,-9S21,8 21,13zM19.1,13c0,-3.9 -3.2,-7.1 -7.1,-7.1S4.9,9.1 4.9,13s3.2,7.1 7.1,7.1S19.1,16.9 19.1,13zM11.75,8C11.34,8 11,8.34 11,8.75V14l4.14,2.48c0.34,0.21 0.77,0.1 0.98,-0.24s0.09,-0.79 -0.25,-0.99l-3.37,-2v-4.5C12.5,8.34 12.16,8 11.75,8z"/>
+        android:pathData="M13,8h-2v5.41l3.79,3.8 1.42,-1.42 -3.21,-3.2zM12,4c-4.97,0 -9,4.03 -9,9s4.03,9 9,9 9,-4.03 9,-9 -4.03,-9 -9,-9zM12,20c-3.86,0 -7,-3.14 -7,-7s3.14,-7 7,-7 7,3.14 7,7 -3.14,7 -7,7zM16.056,3.346l1.282,-1.535 4.607,3.85 -1.28,1.54zM2.056,5.654L6.663,1.81l1.28,1.536L3.338,7.19z"/>
 
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_volume_alarm_mute.xml b/packages/SystemUI/res/drawable/ic_volume_alarm_mute.xml
index 02fb1e7..18e2736 100644
--- a/packages/SystemUI/res/drawable/ic_volume_alarm_mute.xml
+++ b/packages/SystemUI/res/drawable/ic_volume_alarm_mute.xml
@@ -22,6 +22,6 @@
 
     <path
         android:fillColor="#FFFFFF"
-        android:pathData="M21.35,6.49c-0.35,0.42 -0.98,0.47 -1.4,0.12l-3.07,-2.57a1,1 0,1 1,1.29 -1.53l3.07,2.57c0.42,0.35 0.47,0.98 0.11,1.41zM20.72,20.09a0.9,0.9 0,0 1,0 1.27,0.9 0.9,0 0,1 -1.27,0l-1.57,-1.57A8.875,8.875 0,0 1,12 22c-4.98,0 -9,-4.03 -9,-9 0,-2.25 0.83,-4.31 2.2,-5.89l-0.8,-0.8 -0.41,0.35a1,1 0,0 1,-1.35 -0.06,1 1,0 0,1 0.07,-1.47l0.27,-0.23 -0.7,-0.7a0.9,0.9 0,0 1,0 -1.27c0.35,-0.35 0.93,-0.35 1.28,0l17.16,17.16zM16.54,18.45L6.55,8.46A7.041,7.041 0,0 0,4.9 13c0,3.91 3.19,7.1 7.1,7.1 1.73,0 3.31,-0.62 4.54,-1.65zM7.17,3.98A0.997,0.997 0,1 0,5.9 2.44l-0.16,0.13 1.42,1.42 0.01,-0.01zM12,4c-1.41,0 -2.73,0.33 -3.92,0.91l1.45,1.45c0.77,-0.29 1.6,-0.46 2.47,-0.46 3.91,0 7.1,3.18 7.1,7.1 0,0.87 -0.17,1.7 -0.45,2.47l1.44,1.44c0.58,-1.18 0.91,-2.5 0.91,-3.91a9,9 0,0 0,-9 -9z"/>
+        android:pathData="M16.056,3.346l1.282,-1.535 4.607,3.85 -1.28,1.54zM9.35,6.52C10.17,6.19 11.06,6 12,6c3.86,0 7,3.14 7,7 0,0.94 -0.19,1.83 -0.52,2.65l1.5,1.5C20.63,15.91 21,14.5 21,13c0,-4.97 -4.03,-9 -9,-9 -1.5,0 -2.91,0.37 -4.15,1.02l1.5,1.5zM17.42,17.42L7.58,7.58 6.16,6.16l-0.72,-0.72 -1.42,-1.42 -1.21,-1.21 -1.42,1.41L2.48,5.3l-0.42,0.35 1.28,1.54 0.56,-0.47 0.9,0.9C3.67,9.12 3,10.98 3,13c0,4.97 4.03,9 9,9 2.02,0 3.88,-0.67 5.38,-1.79l2.4,2.4 1.41,-1.41 -2.35,-2.35 -1.42,-1.43zM12,20c-3.86,0 -7,-3.14 -7,-7 0,-1.46 0.46,-2.82 1.23,-3.94l9.71,9.71C14.82,19.54 13.46,20 12,20zM7.94,3.35L6.66,1.81l-1.1,0.92 1.42,1.42z"/>
 
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_volume_ringer_vibrate.xml b/packages/SystemUI/res/drawable/ic_volume_ringer_vibrate.xml
index aa13f1e..314e06c 100644
--- a/packages/SystemUI/res/drawable/ic_volume_ringer_vibrate.xml
+++ b/packages/SystemUI/res/drawable/ic_volume_ringer_vibrate.xml
@@ -14,11 +14,10 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:height="24dp"
+    android:height="19dp"
+    android:width="19dp"
     android:viewportHeight="24.0"
-    android:viewportWidth="24.0"
-    android:width="24dp"
-    android:tint="?android:attr/colorControlNormal" >
+    android:viewportWidth="24.0">
 
     <path
         android:fillColor="#FFFFFFFF"
diff --git a/packages/SystemUI/res/drawable/stat_sys_airplane_mode.xml b/packages/SystemUI/res/drawable/stat_sys_airplane_mode.xml
index 2655bcd..0f8c571 100644
--- a/packages/SystemUI/res/drawable/stat_sys_airplane_mode.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_airplane_mode.xml
@@ -16,16 +16,5 @@
 ** limitations under the License.
 */
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="17.25dp"
-    android:height="18dp"
-    android:viewportWidth="19.65"
-    android:viewportHeight="20.5">
-    <group
-        android:translateX="1.3"
-        android:translateY="1.7">
-        <path
-            android:pathData="M16.01,9.87l-6.24,-3.9v-4.7C9.77,0.57 9.21,0 8.5,0S7.23,0.57 7.23,1.28v4.7L0.99,9.88c-0.37,0.23 -0.6,0.64 -0.6,1.08v0.41c0,0.29 0.29,0.5 0.55,0.41l6.27,-1.97v4.7l-1.37,1.02c-0.21,0.16 -0.34,0.41 -0.34,0.68v0.57c0,0.15 0.12,0.23 0.27,0.2 1.67,-0.47 1.12,-0.31 2.73,-0.78 1.03,0.3 1.7,0.49 2.72,0.78 0.15,0.03 0.27,-0.06 0.27,-0.2v-0.57c0,-0.27 -0.13,-0.52 -0.34,-0.68l-1.37,-1.02v-4.7l6.27,1.97c0.28,0.09 0.55,-0.12 0.55,-0.41v-0.41c0.01,-0.45 -0.23,-0.87 -0.59,-1.09z"
-            android:fillColor="#FFF"/>
-    </group>
-</vector>
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+    android:drawable="@*android:drawable/ic_qs_airplane" />
diff --git a/packages/SystemUI/res/drawable/stat_sys_alarm.xml b/packages/SystemUI/res/drawable/stat_sys_alarm.xml
index 0e9319c..b9bebec 100644
--- a/packages/SystemUI/res/drawable/stat_sys_alarm.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_alarm.xml
@@ -1,35 +1,21 @@
-<?xml version="1.0" encoding="utf-8"?>
 <!--
-**
-** Copyright 2017, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT 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 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
 */
 -->
 <inset xmlns:android="http://schemas.android.com/apk/res/android"
     android:insetLeft="2.5dp"
-    android:insetRight="2.5dp">
-    <vector
-        android:width="17dp"
-        android:height="17dp"
-        android:viewportWidth="19.3"
-        android:viewportHeight="19.3">
-        <group
-            android:translateX="1.2"
-            android:translateY="1.2">
-            <path
-                android:pathData="M0.97,3.97c-0.32,-0.33 -0.24,-0.81 0.08,-1.13L3.47,0.74C3.79,0.42 4.28,0.5 4.6,0.82s0.24,0.89 -0.08,1.13L2.1,4.05c-0.4,0.32 -0.89,0.24 -1.13,-0.08zM15.97,2.84l-2.5,-2.1c-0.32,-0.32 -0.8,-0.25 -1.13,0.08 -0.32,0.32 -0.24,0.81 0.08,1.13l2.5,2.1c0.33,0.3 0.81,0.24 1.13,-0.08 0.27,-0.31 0.25,-0.89 -0.08,-1.13zM15.73,9.21c0,4.03 -3.23,7.26 -7.26,7.26s-7.26,-3.23 -7.26,-7.26 3.23,-7.26 7.26,-7.26 7.26,3.23 7.26,7.26zM14.2,9.21c0,-3.15 -2.58,-5.73 -5.73,-5.73S2.74,6.06 2.74,9.21s2.58,5.73 5.73,5.73 5.73,-2.59 5.73,-5.73zM8.27,5.18c-0.33,0 -0.6,0.27 -0.6,0.6v4.23l3.34,2c0.27,0.17 0.62,0.08 0.79,-0.19s0.07,-0.64 -0.2,-0.8L8.87,9.41L8.87,5.78c0,-0.33 -0.27,-0.6 -0.6,-0.6z"
-                android:fillColor="#FFF"/>
-        </group>
-    </vector>
-</inset>
+    android:insetRight="2.5dp"
+    android:drawable="@drawable/ic_alarm" />
diff --git a/packages/SystemUI/res/drawable/stat_sys_alarm_dim.xml b/packages/SystemUI/res/drawable/stat_sys_alarm_dim.xml
index c8e2ac1..cf1119d 100644
--- a/packages/SystemUI/res/drawable/stat_sys_alarm_dim.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_alarm_dim.xml
@@ -15,18 +15,5 @@
 -->
 <inset xmlns:android="http://schemas.android.com/apk/res/android"
     android:insetLeft="2.5dp"
-    android:insetRight="2.5dp">
-
-    <vector
-        android:width="17dp"
-        android:height="17dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
-
-        <path
-            android:fillColor="#4dffffff"
-            android:pathData="M22.0,5.7l-4.6,-3.9l-1.3,1.5l4.6,3.9L22.0,5.7zM7.9,3.4L6.6,1.9L2.0,5.7l1.3,1.5L7.9,3.4zM12.5,8.0L11.0,8.0l0.0,6.0l4.7,2.9l0.8,-1.2l-4.0,-2.4L12.5,8.0zM12.0,4.0c-5.0,0.0 -9.0,4.0 -9.0,9.0c0.0,5.0 4.0,9.0 9.0,9.0s9.0,-4.0 9.0,-9.0C21.0,8.0 17.0,4.0 12.0,4.0zM12.0,20.0c-3.9,0.0 -7.0,-3.1 -7.0,-7.0c0.0,-3.9 3.1,-7.0 7.0,-7.0c3.9,0.0 7.0,3.1 7.0,7.0C19.0,16.9 15.9,20.0 12.0,20.0z"/>
-
-    </vector>
-
-</inset>
\ No newline at end of file
+    android:insetRight="2.5dp"
+    android:drawable="@drawable/ic_alarm_dim" />
diff --git a/packages/SystemUI/res/drawable/stat_sys_cast.xml b/packages/SystemUI/res/drawable/stat_sys_cast.xml
index 5228085..de7ec9d 100644
--- a/packages/SystemUI/res/drawable/stat_sys_cast.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_cast.xml
@@ -15,14 +15,5 @@
 -->
 <inset xmlns:android="http://schemas.android.com/apk/res/android"
     android:insetLeft="2.5dp"
-    android:insetRight="2.5dp">
-    <vector android:width="17dp"
-            android:height="17dp"
-            android:viewportWidth="17.0"
-            android:viewportHeight="17.0">
-
-        <path
-            android:fillColor="#FFFFFFFF"
-            android:pathData="M0.71,12.75v1.42c0,0.39 0.32,0.71 0.71,0.71h1.42C2.83,13.7 1.88,12.75 0.71,12.75zM0.69,10.67c-0.01,0.36 0.25,0.66 0.6,0.72c1.47,0.26 2.65,1.42 2.9,2.89c0.06,0.34 0.35,0.6 0.7,0.6c0.43,0 0.77,-0.38 0.71,-0.81c-0.34,-2.11 -2,-3.76 -4.11,-4.09C1.08,9.91 0.7,10.24 0.69,10.67zM13.46,4.96H3.54v1.15c2.81,0.91 5.02,3.12 5.93,5.93h3.99V4.96zM0.69,7.81C0.68,8.18 0.95,8.49 1.31,8.53c3.02,0.3 5.44,2.71 5.74,5.72c0.04,0.35 0.34,0.62 0.7,0.62c0.42,0 0.75,-0.36 0.71,-0.78c-0.37,-3.69 -3.3,-6.62 -6.99,-6.98C1.06,7.08 0.7,7.4 0.69,7.81zM14.88,2.12H2.12c-0.78,0 -1.42,0.64 -1.42,1.42v2.12h1.42V3.54h12.75v9.92H9.92v1.42h4.96c0.78,0 1.42,-0.64 1.42,-1.42V3.54C16.29,2.76 15.65,2.12 14.88,2.12z" />
-    </vector>
-</inset>
+    android:insetRight="2.5dp"
+    android:drawable="@drawable/ic_cast_connected" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/stat_sys_data_bluetooth.xml b/packages/SystemUI/res/drawable/stat_sys_data_bluetooth.xml
deleted file mode 100644
index 4dc0e4b..0000000
--- a/packages/SystemUI/res/drawable/stat_sys_data_bluetooth.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-**
-** Copyright 2017, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
-** limitations under the License.
-*/
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="17dp"
-        android:height="17dp"
-        android:viewportWidth="17.0"
-        android:viewportHeight="17.0">
-    <group
-        android:translateY="0.5"
-        android:translateX="0.5" >
-        <path
-            android:pathData="M8.84,8l2.62,-2.62c0.29,-0.29 0.29,-0.75 0,-1.04L8.33,1.22L8.31,1.2c-0.3,-0.28 -0.76,-0.26 -1.03,0.04c-0.13,0.13 -0.2,0.31 -0.2,0.5v4.51L4.24,3.4c-0.29,-0.29 -0.74,-0.29 -1.03,0s-0.29,0.74 0,1.03L6.78,8l-3.56,3.56c-0.29,0.29 -0.29,0.74 0,1.03s0.74,0.29 1.03,0l2.83,-2.83v4.51c0,0.4 0.33,0.73 0.73,0.73c0.18,0 0.36,-0.07 0.5,-0.2l0.03,-0.03l3.12,-3.12c0.29,-0.29 0.29,-0.75 0,-1.04L8.84,8zM8.47,6.37V3.36l1.5,1.5L8.47,6.37zM8.47,12.63V9.62l1.5,1.5L8.47,12.63z"
-            android:fillColor="#FFFFFF"/>
-    </group>
-</vector>
diff --git a/packages/SystemUI/res/drawable/stat_sys_data_bluetooth_connected.xml b/packages/SystemUI/res/drawable/stat_sys_data_bluetooth_connected.xml
index c8a4440..8d9e561 100644
--- a/packages/SystemUI/res/drawable/stat_sys_data_bluetooth_connected.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_data_bluetooth_connected.xml
@@ -1,31 +1,17 @@
-<?xml version="1.0" encoding="utf-8"?>
 <!--
-**
-** Copyright 2017, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT 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 (C) 2017 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
 -->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="17dp"
-        android:height="17dp"
-        android:viewportWidth="18.0"
-        android:viewportHeight="18.0">
-    <group
-        android:translateY="0.5"
-        android:translateX="0.5" >
-        <path
-            android:pathData="M9.57,8.5l2.79,-2.78c0.3,-0.3 0.3,-0.8 0,-1.1L9.04,1.29L9.02,1.27C8.7,0.98 8.21,1 7.91,1.31C7.78,1.45 7.71,1.64 7.71,1.84v4.79L4.69,3.61c-0.3,-0.3 -0.79,-0.3 -1.09,0s-0.3,0.79 0,1.09L7.39,8.5L3.6,12.29c-0.3,0.3 -0.3,0.79 0,1.09s0.79,0.3 1.09,0l3.01,-3.01v4.8c0,0.42 0.35,0.77 0.77,0.77c0.19,0 0.39,-0.07 0.53,-0.21l0.04,-0.04l3.32,-3.32c0.3,-0.3 0.3,-0.8 0,-1.1L9.57,8.5zM9.19,6.77v-3.2l1.6,1.6L9.19,6.77zM9.19,13.42v-3.2l1.6,1.6L9.19,13.42zM4.03,9.29c-0.44,0.44 -1.15,0.44 -1.58,0C2.02,8.86 2.02,8.16 2.45,7.72l0.01,-0.01C2.89,7.27 3.59,7.27 4.02,7.7l0.01,0.01C4.47,8.15 4.47,8.85 4.03,9.29zM14.44,7.71c0.44,0.44 0.44,1.15 0,1.58c-0.44,0.44 -1.15,0.44 -1.58,0c-0.44,-0.43 -0.44,-1.13 -0.01,-1.57l0.01,-0.01C13.3,7.28 14,7.27 14.43,7.7C14.44,7.7 14.44,7.71 14.44,7.71z"
-            android:fillColor="#FFFFFF"/>
-    </group>
-</vector>
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+    android:drawable="@drawable/ic_bluetooth_connected" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/stat_sys_data_saver.xml b/packages/SystemUI/res/drawable/stat_sys_data_saver.xml
index fed7cae..0223501 100644
--- a/packages/SystemUI/res/drawable/stat_sys_data_saver.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_data_saver.xml
@@ -18,26 +18,5 @@
 -->
 <inset xmlns:android="http://schemas.android.com/apk/res/android"
     android:insetLeft="2.5dp"
-    android:insetRight="2.5dp" >
-    <vector
-        android:width="18dp"
-        android:height="18dp"
-        android:viewportWidth="19.0"
-        android:viewportHeight="19.0">
-        <group
-            android:translateX="1.0"
-            android:translateY="1.0">
-            <path
-                android:pathData="M11.5,8.5c0,0.41 -0.34,0.74 -0.74,0.74L9.24,9.24v1.5c0,0.41 -0.34,0.74 -0.74,0.74s-0.74,-0.34 -0.74,-0.74v-1.5h-1.5c-0.41,0 -0.74,-0.34 -0.74,-0.74s0.34,-0.74 0.74,-0.74h1.5v-1.5c0,-0.41 0.34,-0.74 0.74,-0.74s0.74,0.34 0.74,0.74v1.5h1.5c0.42,-0.01 0.76,0.33 0.76,0.74z"
-                android:fillColor="#FFF"/>
-            <path
-                android:pathData="M13.23,12.05l0.99,0.57c0.19,0.12 0.25,0.38 0.12,0.55A7.452,7.452 0,0 1,7.5 15.9c-3.29,-0.44 -5.96,-3.08 -6.41,-6.38 -0.57,-4.17 2.33,-7.8 6.23,-8.42 0.23,-0.04 0.44,0.15 0.44,0.37v1.15c0,0.18 -0.14,0.33 -0.31,0.37 -2.7,0.52 -4.71,2.96 -4.55,5.83 0.16,2.86 2.57,5.21 5.43,5.29 1.77,0.06 3.38,-0.72 4.44,-1.97 0.11,-0.14 0.31,-0.18 0.46,-0.09z"
-                android:fillColor="#FFF" />
-            <path
-                android:pathData="M14.11,8.5c0,0.62 -0.11,1.22 -0.29,1.78 -0.06,0.17 0.01,0.35 0.16,0.45l1,0.57c0.19,0.12 0.46,0.03 0.54,-0.18 0.3,-0.82 0.47,-1.7 0.47,-2.62 0,-3.73 -2.73,-6.82 -6.31,-7.39a0.377,0.377 0,0 0,-0.44 0.37v1.15c0,0.18 0.14,0.33 0.31,0.36 2.59,0.51 4.56,2.78 4.56,5.51z"
-                android:fillAlpha="0.3"
-                android:fillColor="#FFF" />
-
-        </group>
-    </vector>
-</inset>
+    android:insetRight="2.5dp"
+    android:drawable="@drawable/ic_data_saver" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/stat_sys_dnd.xml b/packages/SystemUI/res/drawable/stat_sys_dnd.xml
index 68a06d0..aa352b4 100644
--- a/packages/SystemUI/res/drawable/stat_sys_dnd.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_dnd.xml
@@ -18,17 +18,5 @@
 -->
 <inset xmlns:android="http://schemas.android.com/apk/res/android"
     android:insetLeft="2.5dp"
-    android:insetRight="2.5dp" >
-    <vector
-        android:width="17dp"
-        android:height="17dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
-        <path
-            android:fillColor="#FFFFFFFF"
-            android:pathData="M12,2C6.48,2 2,6.48 2,12c0,5.52 4.48,10 10,10c5.52,0 10,-4.48 10,-10C22,6.48 17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8c0,-4.41 3.59,-8 8,-8c4.41,0 8,3.59 8,8C20,16.41 16.41,20 12,20z"/>
-        <path
-            android:fillColor="#FFFFFFFF"
-            android:pathData="M7,11h10v2h-10z"/>
-    </vector>
-</inset>
+    android:insetRight="2.5dp"
+    android:drawable="@*android:drawable/ic_qs_dnd" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/stat_sys_headset.xml b/packages/SystemUI/res/drawable/stat_sys_headset.xml
new file mode 100644
index 0000000..361c665
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_headset.xml
@@ -0,0 +1,19 @@
+<!--
+    Copyright (C) 2016 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+    android:insetLeft="2.5dp"
+    android:insetRight="2.5dp"
+    android:drawable="@drawable/ic_headset" />
diff --git a/packages/SystemUI/res/drawable/stat_sys_headset_mic.xml b/packages/SystemUI/res/drawable/stat_sys_headset_mic.xml
new file mode 100644
index 0000000..b424caa
--- /dev/null
+++ b/packages/SystemUI/res/drawable/stat_sys_headset_mic.xml
@@ -0,0 +1,19 @@
+<!--
+    Copyright (C) 2016 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+    android:insetLeft="2.5dp"
+    android:insetRight="2.5dp"
+    android:drawable="@drawable/ic_headset_mic" />
diff --git a/packages/SystemUI/res/drawable/stat_sys_hotspot.xml b/packages/SystemUI/res/drawable/stat_sys_hotspot.xml
index 4f52777..361b00a 100644
--- a/packages/SystemUI/res/drawable/stat_sys_hotspot.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_hotspot.xml
@@ -15,18 +15,5 @@
 -->
 <inset xmlns:android="http://schemas.android.com/apk/res/android"
     android:insetLeft="2.5dp"
-    android:insetRight="2.5dp">
-    <vector
-        android:width="18.0dp"
-        android:height="18.0dp"
-        android:viewportWidth="18.0"
-        android:viewportHeight="18.0">
-      <group
-          android:translateX="0.5"
-          android:translateY="0.5" >
-          <path
-              android:pathData="M8.5,7.79c-0.78,0 -1.42,0.64 -1.42,1.42c0,0.78 0.64,1.42 1.42,1.42s1.42,-0.64 1.42,-1.42C9.92,8.43 9.28,7.79 8.5,7.79zM12.75,9.21c0,-2.35 -1.9,-4.25 -4.25,-4.25c-0.18,0 -0.35,0.01 -0.53,0.03C6.11,5.22 4.58,6.7 4.3,8.55c-0.23,1.52 0.35,2.91 1.36,3.82C6,12.67 6.54,12.6 6.76,12.2c0.17,-0.3 0.1,-0.67 -0.16,-0.89c-0.78,-0.7 -1.12,-1.77 -0.86,-2.79C5.99,7.5 6.78,6.71 7.8,6.46C9.32,6.08 10.86,7 11.25,8.52c0.06,0.23 0.09,0.46 0.09,0.69c0,0.84 -0.36,1.58 -0.94,2.1c-0.25,0.23 -0.33,0.6 -0.16,0.9c0.22,0.38 0.74,0.49 1.06,0.2C12.22,11.6 12.75,10.43 12.75,9.21zM7.63,1.85C4.19,2.24 1.42,5.07 1.1,8.52c-0.26,2.61 0.88,5.15 2.99,6.7c0.36,0.26 0.86,0.15 1.09,-0.23c0.19,-0.32 0.1,-0.74 -0.19,-0.96c-1.7,-1.26 -2.71,-3.38 -2.35,-5.73c0.4,-2.6 2.57,-4.68 5.19,-4.97c3.59,-0.41 6.63,2.4 6.63,5.91c0,1.97 -0.96,3.7 -2.43,4.79c-0.3,0.22 -0.38,0.63 -0.19,0.96c0.22,0.39 0.73,0.49 1.09,0.23c1.9,-1.4 3.03,-3.62 3.03,-5.98C15.94,4.84 12.12,1.34 7.63,1.85z"
-              android:fillColor="#FFFFFFFF"/>
-      </group>
-    </vector>
-</inset>
+    android:insetRight="2.5dp"
+    android:drawable="@drawable/ic_hotspot" />
diff --git a/packages/SystemUI/res/drawable/stat_sys_location.xml b/packages/SystemUI/res/drawable/stat_sys_location.xml
index bdb0b0c..7a5aeb9 100644
--- a/packages/SystemUI/res/drawable/stat_sys_location.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_location.xml
@@ -14,18 +14,6 @@
   ~ limitations under the License
   -->
 <inset xmlns:android="http://schemas.android.com/apk/res/android"
-    android:insetLeft="1.5dp"
-    android:insetRight="1.5dp">
-        <vector
-            android:width="17dp"
-            android:height="17dp"
-            android:viewportWidth="24.0"
-            android:viewportHeight="24.0">
-                <path
-                    android:fillColor="#FFFFFFFF"
-                    android:pathData="M12,2C8.13,2 5,5.13 5,9c0,5.25 7,13 7,13s7,-7.75 7,-13C19,5.13 15.87,2 12,2zM7,9c0,-2.76 2.24,-5 5,-5s5,2.24 5,5c0,2.88 -2.88,7.19 -5,9.88C9.92,16.21 7,11.85 7,9z"/>
-                <path
-                    android:fillColor="#FFFFFFFF"
-                    android:pathData="M12,9m-2.5,0a2.5,2.5 0,1 1,5 0a2.5,2.5 0,1 1,-5 0"/>
-        </vector>
-</inset>
\ No newline at end of file
+    android:insetLeft="2.5dp"
+    android:insetRight="2.5dp"
+    android:drawable="@drawable/ic_location" />
diff --git a/packages/SystemUI/res/drawable/stat_sys_ringer_vibrate.xml b/packages/SystemUI/res/drawable/stat_sys_ringer_vibrate.xml
index 0b72f75..21a4c17 100644
--- a/packages/SystemUI/res/drawable/stat_sys_ringer_vibrate.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_ringer_vibrate.xml
@@ -1,36 +1,19 @@
-<?xml version="1.0" encoding="utf-8"?>
 <!--
-**
-** Copyright 2017, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
-**
-**     http://www.apache.org/licenses/LICENSE-2.0
-**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT 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 (C) 2017 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
 -->
 <inset xmlns:android="http://schemas.android.com/apk/res/android"
     android:insetLeft="2.5dp"
-    android:insetRight="2.5dp">
-    <vector
-        android:width="19dp"
-        android:height="19dp"
-        android:viewportWidth="23.0"
-        android:viewportHeight="23.0">
-        <group
-            android:translateX="-0.5"
-            android:translateY="-0.5">
-            <path
-                android:fillColor="#F00"
-                android:pathData="M1,9h2v6H1V9zM4,17h2V7H4V17zM21,9v6h2V9H21zM18,17h2V7h-2V17zM17,5.5v13c0,0.83 -0.67,1.5 -1.5,1.5h-7C7.67,20 7,19.33 7,18.5v-13C7,4.67 7.67,4 8.5,4h7C16.33,4 17,4.67 17,5.5zM15,6H9v12h6V6z"/>
-
-        </group>
-    </vector>
-</inset>
+    android:insetRight="2.5dp"
+    android:drawable="@drawable/ic_volume_ringer_vibrate" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/stat_sys_zen_important.xml b/packages/SystemUI/res/drawable/stat_sys_zen_important.xml
deleted file mode 100644
index 1262617..0000000
--- a/packages/SystemUI/res/drawable/stat_sys_zen_important.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<inset xmlns:android="http://schemas.android.com/apk/res/android"
-    android:insetLeft="2.5dp"
-    android:insetRight="2.5dp">
-    <vector android:width="18dp"
-            android:height="18dp"
-            android:viewportWidth="24.0"
-            android:viewportHeight="24.0">
-
-        <path
-            android:fillColor="#FFFFFFFF"
-            android:pathData="M12.0,17.273l6.1800003,3.7269993 -1.6350002,-7.0290003 5.455,-4.7269993 -7.191,-0.6170006 -2.809,-6.627 -2.809,6.627 -7.191,0.6170006 5.455,4.7269993 -1.6349998,7.0290003z"/>
-    </vector>
-</inset>
diff --git a/packages/SystemUI/res/drawable/stat_sys_zen_none.xml b/packages/SystemUI/res/drawable/stat_sys_zen_none.xml
deleted file mode 100644
index 92914a8..0000000
--- a/packages/SystemUI/res/drawable/stat_sys_zen_none.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<!--
-Copyright (C) 2014 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2.0 (the "License");
-    you may not use this file except in compliance with the License.
-    You may obtain a copy of the License at
-
-         http://www.apache.org/licenses/LICENSE-2.0
-
-    Unless required by applicable law or agreed to in writing, software
-    distributed under the License is distributed on an "AS IS" BASIS,
-    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-    See the License for the specific language governing permissions and
-    limitations under the License.
--->
-<inset xmlns:android="http://schemas.android.com/apk/res/android"
-    android:insetLeft="2.5dp"
-    android:insetRight="2.5dp">
-    <vector android:width="17dp"
-            android:height="17dp"
-            android:viewportWidth="48.0"
-            android:viewportHeight="48.0">
-
-        <path
-            android:fillColor="#FFFFFFFF"
-            android:pathData="M24.0,4.0C13.0,4.0 4.0,13.0 4.0,24.0c0.0,11.0 9.0,20.0 20.0,20.0c11.0,0.0 20.0,-9.0 20.0,-20.0C44.0,13.0 35.0,4.0 24.0,4.0zM24.0,40.0c-8.8,0.0 -16.0,-7.2 -16.0,-16.0c0.0,-3.7 1.3,-7.1 3.4,-9.8l22.4,22.4C31.1,38.7 27.7,40.0 24.0,40.0zM36.6,33.8L14.2,11.4C16.9,9.3 20.3,8.0 24.0,8.0c8.8,0.0 16.0,7.2 16.0,16.0C40.0,27.7 38.7,31.1 36.6,33.8z"/>
-    </vector>
-</inset>
diff --git a/packages/SystemUI/res/interpolator/ic_signal_workmode_disable_animation_interpolator_0.xml b/packages/SystemUI/res/interpolator/ic_signal_workmode_disable_animation_interpolator_0.xml
deleted file mode 100644
index 5009c6b..0000000
--- a/packages/SystemUI/res/interpolator/ic_signal_workmode_disable_animation_interpolator_0.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<pathInterpolator
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:pathData="M 0.0,0.0 l 0.144628099174,0.0 l 0.855371900826,1.0 L 1.0,1.0" />
diff --git a/packages/SystemUI/res/interpolator/ic_signal_workmode_disable_animation_interpolator_1.xml b/packages/SystemUI/res/interpolator/ic_signal_workmode_disable_animation_interpolator_1.xml
deleted file mode 100644
index 678b90b..0000000
--- a/packages/SystemUI/res/interpolator/ic_signal_workmode_disable_animation_interpolator_1.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<pathInterpolator
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:pathData="M 0.0,0.0 l 0.534759358289,0.0 l 0.465240641711,1.0" />
diff --git a/packages/SystemUI/res/interpolator/ic_signal_workmode_disable_animation_interpolator_2.xml b/packages/SystemUI/res/interpolator/ic_signal_workmode_disable_animation_interpolator_2.xml
deleted file mode 100644
index 6c6df60..0000000
--- a/packages/SystemUI/res/interpolator/ic_signal_workmode_disable_animation_interpolator_2.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<pathInterpolator
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:pathData="M 0.0,0.0 c 0.313385868073,0.330828523695 0.125984191895,0.661170632677 1.0,1.0" />
diff --git a/packages/SystemUI/res/interpolator/ic_signal_workmode_disable_animation_interpolator_3.xml b/packages/SystemUI/res/interpolator/ic_signal_workmode_disable_animation_interpolator_3.xml
deleted file mode 100644
index b1eec483..0000000
--- a/packages/SystemUI/res/interpolator/ic_signal_workmode_disable_animation_interpolator_3.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<pathInterpolator
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:pathData="M 0.0,0.0 c 0.4,0.0 0.2,0.2 1.0,1.0" />
diff --git a/packages/SystemUI/res/interpolator/ic_signal_workmode_disable_animation_interpolator_4.xml b/packages/SystemUI/res/interpolator/ic_signal_workmode_disable_animation_interpolator_4.xml
deleted file mode 100644
index 17ff65a..0000000
--- a/packages/SystemUI/res/interpolator/ic_signal_workmode_disable_animation_interpolator_4.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<pathInterpolator
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:pathData="M 0.0,0.0 c 0.4,0.4 0.2,0.2 1.0,1.0" />
diff --git a/packages/SystemUI/res/interpolator/ic_signal_workmode_disable_animation_interpolator_5.xml b/packages/SystemUI/res/interpolator/ic_signal_workmode_disable_animation_interpolator_5.xml
deleted file mode 100644
index aee48dc..0000000
--- a/packages/SystemUI/res/interpolator/ic_signal_workmode_disable_animation_interpolator_5.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<pathInterpolator
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:pathData="M 0.0,0.0 c 0.33333333,0.0 0.66666667,1.0 1.0,1.0" />
diff --git a/packages/SystemUI/res/interpolator/ic_signal_workmode_disable_cross_1_pathdata_interpolator.xml b/packages/SystemUI/res/interpolator/ic_signal_workmode_disable_cross_1_pathdata_interpolator.xml
deleted file mode 100644
index 66cfaff..0000000
--- a/packages/SystemUI/res/interpolator/ic_signal_workmode_disable_cross_1_pathdata_interpolator.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
-    android:pathData="M 0,0 c 0.166666667,0 0.2,1 1,1" />
diff --git a/packages/SystemUI/res/interpolator/ic_signal_workmode_enable_animation_interpolator_0.xml b/packages/SystemUI/res/interpolator/ic_signal_workmode_enable_animation_interpolator_0.xml
deleted file mode 100644
index 4a5fde9..0000000
--- a/packages/SystemUI/res/interpolator/ic_signal_workmode_enable_animation_interpolator_0.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<pathInterpolator
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:pathData="M 0.0,0.0 c 0.33333333,0.0 0.83333333333,1.0 1.0,1.0" />
diff --git a/packages/SystemUI/res/interpolator/ic_signal_workmode_enable_animation_interpolator_1.xml b/packages/SystemUI/res/interpolator/ic_signal_workmode_enable_animation_interpolator_1.xml
deleted file mode 100644
index 0f35e5d..0000000
--- a/packages/SystemUI/res/interpolator/ic_signal_workmode_enable_animation_interpolator_1.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<pathInterpolator
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:pathData="M 0.0,0.0 c 0.714960628748,0.0 0.678740215302,1.0 1.0,1.0" />
diff --git a/packages/SystemUI/res/interpolator/ic_signal_workmode_enable_animation_interpolator_2.xml b/packages/SystemUI/res/interpolator/ic_signal_workmode_enable_animation_interpolator_2.xml
deleted file mode 100644
index 626f9ef..0000000
--- a/packages/SystemUI/res/interpolator/ic_signal_workmode_enable_animation_interpolator_2.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<pathInterpolator
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:pathData="M 0.0,0.0 l 0.392038600724,0.0 l 0.607961399276,1.0" />
diff --git a/packages/SystemUI/res/interpolator/ic_signal_workmode_enable_animation_interpolator_3.xml b/packages/SystemUI/res/interpolator/ic_signal_workmode_enable_animation_interpolator_3.xml
deleted file mode 100644
index 17ff65a..0000000
--- a/packages/SystemUI/res/interpolator/ic_signal_workmode_enable_animation_interpolator_3.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<pathInterpolator
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:pathData="M 0.0,0.0 c 0.4,0.4 0.2,0.2 1.0,1.0" />
diff --git a/packages/SystemUI/res/interpolator/ic_signal_workmode_enable_animation_interpolator_4.xml b/packages/SystemUI/res/interpolator/ic_signal_workmode_enable_animation_interpolator_4.xml
deleted file mode 100644
index 96bdb48..0000000
--- a/packages/SystemUI/res/interpolator/ic_signal_workmode_enable_animation_interpolator_4.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<pathInterpolator
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:pathData="M 0.0,0.0 l 0.337078651685,0.0 l 0.662921348315,1.0 L 1.0,1.0" />
diff --git a/packages/SystemUI/res/interpolator/ic_signal_workmode_enable_animation_interpolator_5.xml b/packages/SystemUI/res/interpolator/ic_signal_workmode_enable_animation_interpolator_5.xml
deleted file mode 100644
index a91610d..0000000
--- a/packages/SystemUI/res/interpolator/ic_signal_workmode_enable_animation_interpolator_5.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<pathInterpolator
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:pathData="M 0.0,0.0 c 0.16666666667,0.0 0.66666667,1.0 1.0,1.0" />
diff --git a/packages/SystemUI/res/interpolator/ic_signal_workmode_enable_cross_1_pathdata_interpolator.xml b/packages/SystemUI/res/interpolator/ic_signal_workmode_enable_cross_1_pathdata_interpolator.xml
deleted file mode 100644
index a0118d70..0000000
--- a/packages/SystemUI/res/interpolator/ic_signal_workmode_enable_cross_1_pathdata_interpolator.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
-    android:pathData="M 0,0 c 0.8,0 0.833333333,1 1,1" />
diff --git a/packages/SystemUI/res/interpolator/ic_signal_workmode_enable_mask_pathdata_interpolator.xml b/packages/SystemUI/res/interpolator/ic_signal_workmode_enable_mask_pathdata_interpolator.xml
deleted file mode 100644
index 1820bab..0000000
--- a/packages/SystemUI/res/interpolator/ic_signal_workmode_enable_mask_pathdata_interpolator.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2015 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
-    android:pathData="M 0,0 c 0.8,0 0.6,1 1,1" />
diff --git a/packages/SystemUI/res/layout/biometric_dialog.xml b/packages/SystemUI/res/layout/biometric_dialog.xml
index 8f7a45f..c452855 100644
--- a/packages/SystemUI/res/layout/biometric_dialog.xml
+++ b/packages/SystemUI/res/layout/biometric_dialog.xml
@@ -76,10 +76,6 @@
                             android:layout_marginTop="24dp"
                             android:gravity="@integer/biometric_dialog_text_gravity"
                             android:textSize="20sp"
-                            android:maxLines="1"
-                            android:singleLine="true"
-                            android:ellipsize="marquee"
-                            android:marqueeRepeatLimit="marquee_forever"
                             android:textColor="?android:attr/textColorPrimary"/>
 
                         <TextView
@@ -91,10 +87,6 @@
                             android:layout_marginEnd="24dp"
                             android:gravity="@integer/biometric_dialog_text_gravity"
                             android:textSize="16sp"
-                            android:maxLines="1"
-                            android:singleLine="true"
-                            android:ellipsize="marquee"
-                            android:marqueeRepeatLimit="marquee_forever"
                             android:textColor="?android:attr/textColorPrimary"/>
 
                         <TextView
@@ -106,7 +98,6 @@
                             android:gravity="@integer/biometric_dialog_text_gravity"
                             android:paddingTop="8dp"
                             android:textSize="16sp"
-                            android:maxLines="4"
                             android:textColor="?android:attr/textColorPrimary"/>
 
                         <ImageView
diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
index adc0b41..636b929 100644
--- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -77,15 +77,20 @@
         android:contentDescription="@string/accessibility_phone_button"
         android:tint="?attr/wallpaperTextColor" />
 
-    <com.android.systemui.statusbar.phone.LockIcon
-        android:id="@+id/lock_icon"
+    <FrameLayout
+        android:id="@+id/lock_icon_container"
         android:layout_width="@dimen/keyguard_lock_width"
         android:layout_height="@dimen/keyguard_lock_height"
         android:layout_gravity="bottom|center_horizontal"
-        android:layout_marginBottom="@dimen/keyguard_lock_padding"
-        android:src="@*android:drawable/ic_lock"
-        android:contentDescription="@string/accessibility_unlock_button"
-        android:scaleType="center" />
+        android:layout_marginBottom="@dimen/keyguard_lock_padding">
+        <com.android.systemui.statusbar.phone.LockIcon
+            android:id="@+id/lock_icon"
+            android:layout_width="@dimen/keyguard_lock_width"
+            android:layout_height="@dimen/keyguard_lock_height"
+            android:src="@*android:drawable/ic_lock"
+            android:contentDescription="@string/accessibility_unlock_button"
+            android:scaleType="center" />
+    </FrameLayout>
 
     <FrameLayout
         android:id="@+id/overlay_container"
diff --git a/packages/SystemUI/res/layout/volume_dnd_icon.xml b/packages/SystemUI/res/layout/volume_dnd_icon.xml
index 037d143..10c1472 100644
--- a/packages/SystemUI/res/layout/volume_dnd_icon.xml
+++ b/packages/SystemUI/res/layout/volume_dnd_icon.xml
@@ -24,6 +24,6 @@
         android:layout_width="14dp"
         android:layout_height="14dp"
         android:layout_gravity="right|top"
-        android:src="@drawable/ic_dnd"
+        android:src="@*android:drawable/ic_qs_dnd"
         android:tint="?android:attr/textColorTertiary"/>
 </FrameLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index baa2055..039eca6 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -37,7 +37,13 @@
     <dimen name="navigation_handle_radius">1dp</dimen>
     <dimen name="navigation_handle_bottom">6dp</dimen>
     <dimen name="navigation_handle_horizontal_margin">30dp</dimen>
-    <dimen name="navigation_home_handle_width">280dp</dimen>
+    <dimen name="navigation_handle_sample_horizontal_margin">10dp</dimen>
+    <dimen name="navigation_home_handle_width">72dp</dimen>
+
+    <!-- Luminance threshold to determine black/white contrast for the navigation affordances -->
+    <item name="navigation_luminance_threshold" type="dimen" format="float">0.5</item>
+    <!-- Luminance change threshold that allows applying new value if difference was exceeded -->
+    <item name="navigation_luminance_change_threshold" type="dimen" format="float">0.05</item>
 
     <!-- Height of notification icons in the status bar -->
     <dimen name="status_bar_icon_size">@*android:dimen/status_bar_icon_size</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 3aba6a0..03b6a52 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -79,6 +79,9 @@
     <!-- Battery saver confirmation dialog title [CHAR LIMIT=NONE]-->
     <string name="battery_saver_confirmation_title">Turn on Battery Saver?</string>
 
+    <!-- The more generic version of the battery saver confirmation dialog title [CHAR LIMIT=NONE] -->
+    <string name="battery_saver_confirmation_title_generic">About Battery Saver</string>
+
     <!-- Battery saver confirmation dialog ok text [CHAR LIMIT=40]-->
     <string name="battery_saver_confirmation_ok">Turn on</string>
 
diff --git a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
index ace086f..3fc6689 100644
--- a/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/appops/AppOpsControllerImpl.java
@@ -204,24 +204,59 @@
     }
 
     /**
-     * Does the app-op item refer to a user sensitive permission. Only user sensitive permission
-     * should be shown to the user by default.
+     * Does the app-op code refer to a user sensitive permission for the specified user id
+     * and package. Only user sensitive permission should be shown to the user by default.
      *
-     * @param item The item
+     * @param appOpCode The code of the app-op.
+     * @param uid The uid of the user.
+     * @param packageName The name of the package.
      *
      * @return {@code true} iff the app-op item is user sensitive
      */
-    private boolean isUserSensitive(AppOpItem item) {
-        String permission = AppOpsManager.opToPermission(item.getCode());
+    private boolean isUserSensitive(int appOpCode, int uid, String packageName) {
+        String permission = AppOpsManager.opToPermission(appOpCode);
         if (permission == null) {
             return false;
         }
         int permFlags = mContext.getPackageManager().getPermissionFlags(permission,
-                item.getPackageName(), UserHandle.getUserHandleForUid(item.getUid()));
+                packageName, UserHandle.getUserHandleForUid(uid));
         return (permFlags & PackageManager.FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED) != 0;
     }
 
     /**
+     * Does the app-op item refer to an operation that should be shown to the user.
+     * Only specficic ops (like SYSTEM_ALERT_WINDOW) or ops that refer to user sensitive
+     * permission should be shown to the user by default.
+     *
+     * @param item The item
+     *
+     * @return {@code true} iff the app-op item should be shown to the user
+     */
+    private boolean isUserVisible(AppOpItem item) {
+        return isUserVisible(item.getCode(), item.getUid(), item.getPackageName());
+    }
+
+
+    /**
+     * Does the app-op, uid and package name, refer to an operation that should be shown to the
+     * user. Only specficic ops (like {@link AppOpsManager.OP_SYSTEM_ALERT_WINDOW}) or
+     * ops that refer to user sensitive permission should be shown to the user by default.
+     *
+     * @param item The item
+     *
+     * @return {@code true} iff the app-op for should be shown to the user
+     */
+    private boolean isUserVisible(int appOpCode, int uid, String packageName) {
+        // currently OP_SYSTEM_ALERT_WINDOW does not correspond to a platform permission
+        // which may be user senstive, so for now always show it to the user.
+        if (appOpCode == AppOpsManager.OP_SYSTEM_ALERT_WINDOW) {
+            return true;
+        }
+
+        return isUserSensitive(appOpCode, uid, packageName);
+    }
+
+    /**
      * Returns a copy of the list containing all the active AppOps that the controller tracks.
      *
      * @return List of active AppOps information
@@ -245,7 +280,7 @@
             for (int i = 0; i < numActiveItems; i++) {
                 AppOpItem item = mActiveItems.get(i);
                 if ((userId == UserHandle.USER_ALL || UserHandle.getUserId(item.getUid()) == userId)
-                        && isUserSensitive(item)) {
+                        && isUserVisible(item)) {
                     list.add(item);
                 }
             }
@@ -255,7 +290,7 @@
             for (int i = 0; i < numNotedItems; i++) {
                 AppOpItem item = mNotedItems.get(i);
                 if ((userId == UserHandle.USER_ALL || UserHandle.getUserId(item.getUid()) == userId)
-                        && isUserSensitive(item)) {
+                        && isUserVisible(item)) {
                     list.add(item);
                 }
             }
@@ -281,7 +316,8 @@
     }
 
     private void notifySuscribers(int code, int uid, String packageName, boolean active) {
-        if (mCallbacksByCode.containsKey(code)) {
+        if (mCallbacksByCode.containsKey(code)
+                && isUserVisible(code, uid, packageName)) {
             for (Callback cb: mCallbacksByCode.get(code)) {
                 cb.onActiveStateChanged(code, uid, packageName, active);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index 22c019f..e84c648 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -384,9 +384,11 @@
             }
             if (shouldAutoBubbleForFlags(mContext, entry) || shouldBubble(entry)) {
                 // TODO: handle group summaries
-                // It's a new notif, it shows in the shade and as a bubble
                 entry.setIsBubble(true);
-                entry.setShowInShadeWhenBubble(true);
+                boolean suppressNotification = entry.getBubbleMetadata() != null
+                        && entry.getBubbleMetadata().getSuppressInitialNotification()
+                        && isForegroundApp(entry.notification.getPackageName());
+                entry.setShowInShadeWhenBubble(!suppressNotification);
             }
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
index ec6ea55..559c9f6 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java
@@ -413,7 +413,7 @@
             ((TextView) mPermissionView.findViewById(R.id.pkgname)).setText(mAppName);
             ((TextView) mPermissionView.findViewById(R.id.prompt)).setText(
                     getResources().getString(R.string.bubbles_prompt, mAppName));
-            logBubbleClickEvent(mEntry.notification,
+            logBubbleClickEvent(mEntry,
                     StatsLog.BUBBLE_UICHANGED__ACTION__PERMISSION_DIALOG_SHOWN);
         }
     }
@@ -509,7 +509,7 @@
             mStackView.collapseStack(() -> {
                 try {
                     n.contentIntent.send();
-                    logBubbleClickEvent(mEntry.notification,
+                    logBubbleClickEvent(mEntry,
                             StatsLog.BUBBLE_UICHANGED__ACTION__HEADER_GO_TO_APP);
                 } catch (PendingIntent.CanceledException e) {
                     Log.w(TAG, "Failed to send intent for bubble with key: "
@@ -521,7 +521,7 @@
                     mEntry.notification.getUid());
             mStackView.collapseStack(() -> {
                 mContext.startActivity(intent);
-                logBubbleClickEvent(mEntry.notification,
+                logBubbleClickEvent(mEntry,
                         StatsLog.BUBBLE_UICHANGED__ACTION__HEADER_GO_TO_SETTINGS);
             });
         } else if (id == R.id.no_bubbles_button) {
@@ -544,7 +544,7 @@
                 mOnBubbleBlockedListener.onBubbleBlocked(mEntry);
             }
             mStackView.onExpandedHeightChanged();
-            logBubbleClickEvent(mEntry.notification,
+            logBubbleClickEvent(mEntry,
                     allowed ? StatsLog.BUBBLE_UICHANGED__ACTION__PERMISSION_OPT_IN :
                             StatsLog.BUBBLE_UICHANGED__ACTION__PERMISSION_OPT_OUT);
         } catch (RemoteException e) {
@@ -707,10 +707,11 @@
     /**
      * Logs bubble UI click event.
      *
-     * @param notification the bubble notification that user is interacting with.
+     * @param entry the bubble notification entry that user is interacting with.
      * @param action the user interaction enum.
      */
-    private void logBubbleClickEvent(StatusBarNotification notification, int action) {
+    private void logBubbleClickEvent(NotificationEntry entry, int action) {
+        StatusBarNotification notification = entry.notification;
         StatsLog.write(StatsLog.BUBBLE_UI_CHANGED,
                 notification.getPackageName(),
                 notification.getNotification().getChannelId(),
@@ -719,7 +720,8 @@
                 mStackView.getBubbleCount(),
                 action,
                 mStackView.getNormalizedXPosition(),
-                mStackView.getNormalizedYPosition());
+                mStackView.getNormalizedYPosition(),
+                entry.showInShadeWhenBubble());
     }
 
     private int getDimenForPackageUser(int resId, String pkg, int userId) {
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
index 3129900..617090a 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java
@@ -962,7 +962,8 @@
                     getBubbleCount(),
                     action,
                     getNormalizedXPosition(),
-                    getNormalizedYPosition());
+                    getNormalizedYPosition(),
+                    false /* unread notification */);
         } else {
             StatusBarNotification notification = bubble.entry.notification;
             StatsLog.write(StatsLog.BUBBLE_UI_CHANGED,
@@ -973,7 +974,8 @@
                     getBubbleCount(),
                     action,
                     getNormalizedXPosition(),
-                    getNormalizedYPosition());
+                    getNormalizedYPosition(),
+                    bubble.entry.showInShadeWhenBubble());
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayout.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayout.java
index 8731b6b..0f659c3 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/PhysicsAnimationLayout.java
@@ -799,4 +799,9 @@
             }
         }
     }
+
+    @Override
+    protected boolean canReceivePointerEvents() {
+        return false;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java b/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java
index a4592d5..3c6dc73 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeDockHandler.java
@@ -87,7 +87,8 @@
     }
 
     private void requestPulseOutNow(State dozeState) {
-        if (dozeState == State.DOZE_REQUEST_PULSE || dozeState == State.DOZE_PULSING) {
+        if (dozeState == State.DOZE_REQUEST_PULSE || dozeState == State.DOZE_PULSING
+                || dozeState == State.DOZE_PULSING_BRIGHT) {
             final int pulseReason = mMachine.getPulseReason();
             if (pulseReason == DozeLog.PULSE_REASON_DOCKING) {
                 mDozeHost.stopPulsing();
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
index 36e28dc..0607654 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
@@ -71,7 +71,7 @@
                 new DozeScreenState(wrappedService, handler, params, wakeLock),
                 createDozeScreenBrightness(context, wrappedService, sensorManager, host, params,
                         handler),
-                new DozeWallpaperState(context, machine),
+                new DozeWallpaperState(context),
                 new DozeDockHandler(context, machine, host, config, handler, dockManager)
         });
 
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
index bd7a421..3c9d4a9 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
@@ -33,7 +33,11 @@
     boolean isProvisioned();
     boolean isBlockingDoze();
 
-    void extendPulse();
+    /**
+     * Makes a current pulse last for twice as long.
+     * @param reason why we're extending it.
+     */
+    void extendPulse(int reason);
 
     void setAnimateWakeup(boolean animateWakeup);
     void setAnimateScreenOff(boolean animateScreenOff);
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
index c243899..8bf2256 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
@@ -59,6 +59,8 @@
         DOZE_REQUEST_PULSE,
         /** Pulse is showing. Device is awake and showing UI. */
         DOZE_PULSING,
+        /** Pulse is showing with bright wallpaper. Device is awake and showing UI. */
+        DOZE_PULSING_BRIGHT,
         /** Pulse is done showing. Followed by transition to DOZE or DOZE_AOD. */
         DOZE_PULSE_DONE,
         /** Doze is done. DozeService is finished. */
@@ -84,6 +86,7 @@
             switch (this) {
                 case DOZE_REQUEST_PULSE:
                 case DOZE_PULSING:
+                case DOZE_PULSING_BRIGHT:
                     return true;
                 default:
                     return false;
@@ -101,6 +104,7 @@
                 case DOZE:
                     return Display.STATE_OFF;
                 case DOZE_PULSING:
+                case DOZE_PULSING_BRIGHT:
                     return Display.STATE_ON;
                 case DOZE_AOD:
                 case DOZE_AOD_PAUSING:
@@ -188,7 +192,10 @@
     @MainThread
     public State getState() {
         Assert.isMainThread();
-        Preconditions.checkState(!isExecutingTransition());
+        if (isExecutingTransition()) {
+            throw new IllegalStateException("Cannot get state because there were pending "
+                    + "transitions: " + mQueuedRequests.toString());
+        }
         return mState;
     }
 
@@ -202,6 +209,7 @@
         Assert.isMainThread();
         Preconditions.checkState(mState == State.DOZE_REQUEST_PULSE
                 || mState == State.DOZE_PULSING
+                || mState == State.DOZE_PULSING_BRIGHT
                 || mState == State.DOZE_PULSE_DONE, "must be in pulsing state, but is " + mState);
         return mPulseReason;
     }
@@ -283,7 +291,8 @@
                     break;
                 case DOZE_PULSE_DONE:
                     Preconditions.checkState(
-                            mState == State.DOZE_REQUEST_PULSE || mState == State.DOZE_PULSING);
+                            mState == State.DOZE_REQUEST_PULSE || mState == State.DOZE_PULSING
+                                    || mState == State.DOZE_PULSING_BRIGHT);
                     break;
                 default:
                     break;
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index 7189a48..0fe6611 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.doze;
 
+import android.annotation.Nullable;
 import android.app.AlarmManager;
 import android.app.UiModeManager;
 import android.content.BroadcastReceiver;
@@ -147,7 +148,7 @@
         boolean wakeEvent = rawValues != null && rawValues.length > 0 && rawValues[0] != 0;
 
         if (isWakeDisplay) {
-            onWakeScreen(wakeEvent, mMachine.getState());
+            onWakeScreen(wakeEvent, mMachine.isExecutingTransition() ? null : mMachine.getState());
         } else if (isLongPress) {
             requestPulse(pulseReason, sensorPerformedProxCheck);
         } else if (isWakeLockScreen) {
@@ -168,7 +169,7 @@
                 } else if (isPickup) {
                     gentleWakeUp(pulseReason);
                 } else {
-                    mDozeHost.extendPulse();
+                    mDozeHost.extendPulse(pulseReason);
                 }
             }, sensorPerformedProxCheck
                     || (mDockManager != null && mDockManager.isDocked()), pulseReason);
@@ -212,7 +213,8 @@
         final boolean pausing = (state == DozeMachine.State.DOZE_AOD_PAUSING);
         final boolean aod = (state == DozeMachine.State.DOZE_AOD);
 
-        if (state == DozeMachine.State.DOZE_PULSING) {
+        if (state == DozeMachine.State.DOZE_PULSING
+                || state == DozeMachine.State.DOZE_PULSING_BRIGHT) {
             boolean ignoreTouch = near;
             if (DEBUG) Log.i(TAG, "Prox changed, ignore touch = " + ignoreTouch);
             mDozeHost.onIgnoreTouchWhilePulsing(ignoreTouch);
@@ -227,10 +229,14 @@
         }
     }
 
-    private void onWakeScreen(boolean wake, DozeMachine.State state) {
+    /**
+     * When a wake screen event is received from a sensor
+     * @param wake {@code true} when it's time to wake up, {@code false} when we should sleep.
+     * @param state The current state, or null if the state could not be determined due to enqueued
+     *              transitions.
+     */
+    private void onWakeScreen(boolean wake, @Nullable DozeMachine.State state) {
         DozeLog.traceWakeDisplay(wake);
-        boolean paused = (state == DozeMachine.State.DOZE_AOD_PAUSED);
-        boolean pausing = (state == DozeMachine.State.DOZE_AOD_PAUSING);
         sWakeDisplaySensorState = wake;
 
         if (wake) {
@@ -244,6 +250,8 @@
                 }
             }, false /* alreadyPerformedProxCheck */, DozeLog.REASON_SENSOR_WAKE_UP);
         } else {
+            boolean paused = (state == DozeMachine.State.DOZE_AOD_PAUSED);
+            boolean pausing = (state == DozeMachine.State.DOZE_AOD_PAUSING);
             if (!pausing && !paused) {
                 mMachine.requestState(DozeMachine.State.DOZE);
             }
@@ -276,6 +284,7 @@
                 mDozeSensors.setListening(false);
                 break;
             case DOZE_PULSING:
+            case DOZE_PULSING_BRIGHT:
                 mDozeSensors.setTouchscreenSensorsListening(false);
                 mDozeSensors.setProxListening(true);
                 break;
@@ -306,7 +315,16 @@
 
     private void requestPulse(final int reason, boolean performedProxCheck) {
         Assert.isMainThread();
-        mDozeHost.extendPulse();
+        mDozeHost.extendPulse(reason);
+
+        // When already pulsing we're allowed to show the wallpaper directly without
+        // requesting a new pulse.
+        if (mMachine.getState() == DozeMachine.State.DOZE_PULSING
+                && reason == DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN) {
+            mMachine.requestState(DozeMachine.State.DOZE_PULSING_BRIGHT);
+            return;
+        }
+
         if (mPulsePending || !mAllowPulseTriggers || !canPulse()) {
             if (mAllowPulseTriggers) {
                 DozeLog.tracePulseDropped(mContext, mPulsePending, mMachine.getState(),
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
index 847182d..51e96d2 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeUi.java
@@ -94,7 +94,10 @@
                     @Override
                     public void onPulseStarted() {
                         try {
-                            mMachine.requestState(DozeMachine.State.DOZE_PULSING);
+                            mMachine.requestState(
+                                    reason == DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN
+                                            ? DozeMachine.State.DOZE_PULSING_BRIGHT
+                                            : DozeMachine.State.DOZE_PULSING);
                         } catch (IllegalStateException e) {
                             // It's possible that the pulse was asynchronously cancelled while
                             // we were waiting for it to start (under stress conditions.)
@@ -148,6 +151,7 @@
         switch (state) {
             case DOZE_REQUEST_PULSE:
             case DOZE_PULSING:
+            case DOZE_PULSING_BRIGHT:
             case DOZE_PULSE_DONE:
                 mHost.setAnimateWakeup(true);
                 break;
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeWallpaperState.java b/packages/SystemUI/src/com/android/systemui/doze/DozeWallpaperState.java
index ca9f24f..1b3cd88 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeWallpaperState.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeWallpaperState.java
@@ -38,19 +38,17 @@
 
     private final IWallpaperManager mWallpaperManagerService;
     private final DozeParameters mDozeParameters;
-    private final DozeMachine mMachine;
     private boolean mIsAmbientMode;
 
-    public DozeWallpaperState(Context context, DozeMachine machine) {
-        this(machine, IWallpaperManager.Stub.asInterface(
+    public DozeWallpaperState(Context context) {
+        this(IWallpaperManager.Stub.asInterface(
                 ServiceManager.getService(Context.WALLPAPER_SERVICE)),
                 DozeParameters.getInstance(context));
     }
 
     @VisibleForTesting
-    DozeWallpaperState(DozeMachine machine, IWallpaperManager wallpaperManagerService,
+    DozeWallpaperState(IWallpaperManager wallpaperManagerService,
             DozeParameters parameters) {
-        mMachine = machine;
         mWallpaperManagerService = wallpaperManagerService;
         mDozeParameters = parameters;
     }
@@ -65,16 +63,13 @@
             case DOZE_AOD_PAUSED:
             case DOZE_REQUEST_PULSE:
             case DOZE_PULSE_DONE:
+            case DOZE_PULSING:
                 isAmbientMode = true;
                 break;
-            case DOZE_PULSING:
-                isAmbientMode =
-                        mMachine.getPulseReason() != DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN;
-                break;
+            case DOZE_PULSING_BRIGHT:
             default:
                 isAmbientMode = false;
         }
-
         final boolean animated;
         if (isAmbientMode) {
             animated = mDozeParameters.shouldControlScreenOff();
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
index b03b872..6f50baa 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardSliceProvider.java
@@ -286,8 +286,9 @@
         RowBuilder dndBuilder = new RowBuilder(mDndUri)
                 .setContentDescription(getContext().getResources()
                         .getString(R.string.accessibility_quick_settings_dnd))
-                .addEndItem(IconCompat.createWithResource(getContext(), R.drawable.stat_sys_dnd),
-                        ListBuilder.ICON_IMAGE);
+                .addEndItem(
+                    IconCompat.createWithResource(getContext(), R.drawable.stat_sys_dnd),
+                    ListBuilder.ICON_IMAGE);
         builder.addRow(dndBuilder);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/power/BatteryStateSnapshot.kt b/packages/SystemUI/src/com/android/systemui/power/BatteryStateSnapshot.kt
index d7a2d9a..02ad0f1 100644
--- a/packages/SystemUI/src/com/android/systemui/power/BatteryStateSnapshot.kt
+++ b/packages/SystemUI/src/com/android/systemui/power/BatteryStateSnapshot.kt
@@ -17,7 +17,8 @@
     val timeRemainingMillis: Long,
     val severeThresholdMillis: Long,
     val lowThresholdMillis: Long,
-    val isBasedOnUsage: Boolean
+    val isBasedOnUsage: Boolean,
+    val isLowWarningEnabled: Boolean
 ) {
     /**
      * Returns whether hybrid warning logic/copy should be used for this snapshot
@@ -48,7 +49,8 @@
         NO_ESTIMATE_AVAILABLE.toLong(),
         NO_ESTIMATE_AVAILABLE.toLong(),
         NO_ESTIMATE_AVAILABLE.toLong(),
-        false
+        false,
+        true
     ) {
         this.isHybrid = false
     }
diff --git a/packages/SystemUI/src/com/android/systemui/power/EnhancedEstimates.java b/packages/SystemUI/src/com/android/systemui/power/EnhancedEstimates.java
index bd130f4..a879227 100644
--- a/packages/SystemUI/src/com/android/systemui/power/EnhancedEstimates.java
+++ b/packages/SystemUI/src/com/android/systemui/power/EnhancedEstimates.java
@@ -23,4 +23,9 @@
      * show a severe warning to the user.
      */
     long getSevereWarningThreshold();
+
+    /**
+     * Returns a boolean indicating if the low warning should be shown at all or not.
+     */
+    boolean getLowWarningEnabled();
 }
diff --git a/packages/SystemUI/src/com/android/systemui/power/EnhancedEstimatesImpl.java b/packages/SystemUI/src/com/android/systemui/power/EnhancedEstimatesImpl.java
index 3f24176..bfb809e 100644
--- a/packages/SystemUI/src/com/android/systemui/power/EnhancedEstimatesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/power/EnhancedEstimatesImpl.java
@@ -21,4 +21,9 @@
     public long getSevereWarningThreshold() {
         return 0;
     }
+
+    @Override
+    public boolean getLowWarningEnabled() {
+        return true;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
index 41bcab5..10f727b 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -31,6 +31,7 @@
 import android.os.Looper;
 import android.os.PowerManager;
 import android.os.UserHandle;
+import android.provider.Settings.Secure;
 import android.text.Annotation;
 import android.text.Layout;
 import android.text.SpannableString;
@@ -70,6 +71,7 @@
  */
 @Singleton
 public class PowerNotificationWarnings implements PowerUI.WarningsUI {
+
     private static final String TAG = PowerUI.TAG + ".Notification";
     private static final boolean DEBUG = PowerUI.DEBUG;
 
@@ -119,6 +121,7 @@
             .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
             .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
             .build();
+    public static final String EXTRA_CONFIRM_ONLY = "extra_confirm_only";
 
     private final Context mContext;
     private final NotificationManager mNoMan;
@@ -544,10 +547,9 @@
         updateNotification();
     }
 
-    private void showStartSaverConfirmation() {
+    private void showStartSaverConfirmation(boolean confirmOnly) {
         if (mSaverConfirmation != null) return;
         final SystemUIDialog d = new SystemUIDialog(mContext);
-        d.setTitle(R.string.battery_saver_confirmation_title);
         d.setMessage(getBatterySaverDescription());
 
         // Sad hack for http://b/78261259 and http://b/78298335. Otherwise "Battery" may be split
@@ -558,9 +560,19 @@
         // We need to set LinkMovementMethod to make the link clickable.
         d.setMessageMovementMethod(LinkMovementMethod.getInstance());
 
-        d.setNegativeButton(android.R.string.cancel, null);
-        d.setPositiveButton(R.string.battery_saver_confirmation_ok,
+        if (confirmOnly) {
+            d.setTitle(R.string.battery_saver_confirmation_title_generic);
+            d.setPositiveButton(com.android.internal.R.string.confirm_battery_saver,
+                    (dialog, which) -> Secure.putInt(
+                            mContext.getContentResolver(),
+                            Secure.LOW_POWER_WARNING_ACKNOWLEDGED,
+                            1));
+        } else {
+            d.setTitle(R.string.battery_saver_confirmation_title);
+            d.setPositiveButton(R.string.battery_saver_confirmation_ok,
                 (dialog, which) -> setSaverMode(true, false));
+            d.setNegativeButton(android.R.string.cancel, null);
+        }
         d.setShowForAllUsers(true);
         d.setOnDismissListener((dialog) -> mSaverConfirmation = null);
         d.show();
@@ -719,7 +731,7 @@
                 dismissLowBatteryNotification();
             } else if (action.equals(ACTION_SHOW_START_SAVER_CONFIRMATION)) {
                 dismissLowBatteryNotification();
-                showStartSaverConfirmation();
+                showStartSaverConfirmation(intent.getBooleanExtra(EXTRA_CONFIRM_ONLY, false));
             } else if (action.equals(ACTION_DISMISSED_WARNING)) {
                 dismissLowBatteryWarning();
             } else if (ACTION_CLICKED_TEMP_WARNING.equals(action)) {
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index 1863860..4e41108 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -284,7 +284,8 @@
                     plugged, bucket, mBatteryStatus, mLowBatteryReminderLevels[1],
                     mLowBatteryReminderLevels[0], estimate.getEstimateMillis(),
                     mEnhancedEstimates.getSevereWarningThreshold(),
-                    mEnhancedEstimates.getLowWarningThreshold(), estimate.isBasedOnUsage());
+                    mEnhancedEstimates.getLowWarningThreshold(), estimate.isBasedOnUsage(),
+                    mEnhancedEstimates.getLowWarningEnabled());
         } else {
             if (DEBUG) {
                 Slog.d(TAG, "using standard");
@@ -351,7 +352,6 @@
                 Slog.d(TAG, "Low warning marked as shown this cycle");
                 mLowWarningShownThisChargeCycle = true;
             }
-
         } else if (shouldDismissHybridWarning(currentSnapshot)) {
             if (DEBUG) {
                 Slog.d(TAG, "Dismissing warning");
@@ -375,8 +375,9 @@
             return false;
         }
 
-        // Only show the low warning once per charge cycle & no battery saver
-        final boolean canShowWarning = !mLowWarningShownThisChargeCycle && !snapshot.isPowerSaver()
+        // Only show the low warning if enabled once per charge cycle & no battery saver
+        final boolean canShowWarning = snapshot.isLowWarningEnabled()
+                && !mLowWarningShownThisChargeCycle && !snapshot.isPowerSaver()
                 && (snapshot.getTimeRemainingMillis() < snapshot.getLowThresholdMillis()
                 || snapshot.getBatteryLevel() <= snapshot.getLowLevelThreshold());
 
@@ -386,6 +387,7 @@
                 || snapshot.getBatteryLevel() <= snapshot.getSevereLevelThreshold());
 
         final boolean canShow = canShowWarning || canShowSevereWarning;
+
         if (DEBUG) {
             Slog.d(TAG, "Enhanced trigger is: " + canShow + "\nwith battery snapshot:"
                     + " mLowWarningShownThisChargeCycle: " + mLowWarningShownThisChargeCycle
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index 608f646..8ed5424 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -113,6 +113,7 @@
 
     public void saveSpecs(QSTileHost host) {
         List<String> newSpecs = new ArrayList<>();
+        clearAccessibilityState();
         for (int i = 1; i < mTiles.size() && mTiles.get(i) != null; i++) {
             newSpecs.add(mTiles.get(i).spec);
         }
@@ -120,6 +121,17 @@
         mCurrentSpecs = newSpecs;
     }
 
+    private void clearAccessibilityState() {
+        if (mAccessibilityAction == ACTION_ADD) {
+            // Remove blank tile from last spot
+            mTiles.remove(--mEditIndex);
+            // Update the tile divider position
+            mTileDividerIndex--;
+            notifyDataSetChanged();
+        }
+        mAccessibilityAction = ACTION_NONE;
+    }
+
     public void resetTileSpecs(QSTileHost host, List<String> specs) {
         // Notify the host so the tiles get removed callbacks.
         host.changeTiles(mCurrentSpecs, specs);
@@ -333,8 +345,6 @@
             // Remove the placeholder.
             mTiles.remove(mEditIndex--);
             notifyItemRemoved(mEditIndex);
-            // Don't remove items when the last position is selected.
-            if (position == mEditIndex - 1) position--;
         }
         mAccessibilityAction = ACTION_NONE;
         move(mAccessibilityFromIndex, position, v);
@@ -372,6 +382,8 @@
         mAccessibilityAction = ACTION_ADD;
         // Add placeholder for last slot.
         mTiles.add(mEditIndex++, null);
+        // Update the tile divider position
+        mTileDividerIndex++;
         mNeedsFocus = true;
         notifyDataSetChanged();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
index 387de71..19e20a9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
@@ -43,8 +43,7 @@
 
 /** Quick settings tile: Airplane mode **/
 public class AirplaneModeTile extends QSTileImpl<BooleanState> {
-    private final Icon mIcon =
-            ResourceIcon.get(R.drawable.ic_signal_airplane);
+    private final Icon mIcon = ResourceIcon.get(com.android.internal.R.drawable.ic_qs_airplane);
     private final GlobalSetting mSetting;
     private final ActivityStarter mActivityStarter;
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
index 5b85498..ca04076 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BluetoothTile.java
@@ -147,14 +147,15 @@
                 state.icon = ResourceIcon.get(R.drawable.ic_bluetooth_transient_animation);
                 state.contentDescription = state.secondaryLabel;
             } else {
-                state.icon = ResourceIcon.get(R.drawable.ic_qs_bluetooth_on);
+                state.icon =
+                        ResourceIcon.get(com.android.internal.R.drawable.ic_qs_bluetooth);
                 state.contentDescription = mContext.getString(
                         R.string.accessibility_quick_settings_bluetooth) + ","
                         + mContext.getString(R.string.accessibility_not_connected);
             }
             state.state = Tile.STATE_ACTIVE;
         } else {
-            state.icon = ResourceIcon.get(R.drawable.ic_qs_bluetooth_on);
+            state.icon = ResourceIcon.get(com.android.internal.R.drawable.ic_qs_bluetooth);
             state.contentDescription = mContext.getString(
                     R.string.accessibility_quick_settings_bluetooth);
             state.state = Tile.STATE_INACTIVE;
@@ -288,7 +289,7 @@
             // This method returns Pair<Drawable, String> while first value is the drawable
             return BluetoothDeviceLayerDrawable.createLayerDrawable(
                     context,
-                    R.drawable.ic_qs_bluetooth_connected,
+                    R.drawable.ic_bluetooth_connected,
                     mBatteryLevel,
                     mIconScale);
         }
@@ -309,7 +310,7 @@
         @Override
         public Drawable getDrawable(Context context) {
             // This method returns Pair<Drawable, String> - the first value is the drawable.
-            return context.getDrawable(R.drawable.ic_qs_bluetooth_connected);
+            return context.getDrawable(R.drawable.ic_bluetooth_connected);
         }
     }
 
@@ -383,12 +384,12 @@
                 for (CachedBluetoothDevice device : devices) {
                     if (mController.getBondState(device) == BluetoothDevice.BOND_NONE) continue;
                     final Item item = new Item();
-                    item.iconResId = R.drawable.ic_qs_bluetooth_on;
+                    item.iconResId = com.android.internal.R.drawable.ic_qs_bluetooth;
                     item.line1 = device.getName();
                     item.tag = device;
                     int state = device.getMaxConnectionState();
                     if (state == BluetoothProfile.STATE_CONNECTED) {
-                        item.iconResId = R.drawable.ic_qs_bluetooth_connected;
+                        item.iconResId = R.drawable.ic_bluetooth_connected;
                         int batteryLevel = device.getBatteryLevel();
                         if (batteryLevel != BluetoothDevice.BATTERY_LEVEL_UNKNOWN) {
                             item.icon = new BluetoothBatteryTileIcon(batteryLevel,1 /* iconScale */);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
index bdebf79..415870c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -202,8 +202,8 @@
         if (connecting && !state.value) {
             state.secondaryLabel = mContext.getString(R.string.quick_settings_connecting);
         }
-        state.icon = ResourceIcon.get(state.value ? R.drawable.ic_qs_cast_on
-                : R.drawable.ic_qs_cast_off);
+        state.icon = ResourceIcon.get(state.value ? R.drawable.ic_cast_connected
+                : R.drawable.ic_cast);
         if (mWifiConnected || state.value) {
             state.state = state.value ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE;
             if (!state.value) {
@@ -334,7 +334,7 @@
                 for (CastDevice device : devices) {
                     if (device.state == CastDevice.STATE_CONNECTED) {
                         final Item item = new Item();
-                        item.iconResId = R.drawable.ic_qs_cast_on;
+                        item.iconResId = R.drawable.ic_cast_connected;
                         item.line1 = getDeviceName(device);
                         item.line2 = mContext.getString(R.string.quick_settings_connected);
                         item.tag = device;
@@ -354,7 +354,7 @@
                         final CastDevice device = mVisibleOrder.get(id);
                         if (!devices.contains(device)) continue;
                         final Item item = new Item();
-                        item.iconResId = R.drawable.ic_qs_cast_off;
+                        item.iconResId = R.drawable.ic_cast;
                         item.line1 = getDeviceName(device);
                         if (device.state == CastDevice.STATE_CONNECTING) {
                             item.line2 = mContext.getString(R.string.quick_settings_connecting);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index db79e4d7..38962eb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -45,7 +45,6 @@
 import com.android.systemui.qs.QSHost;
 import com.android.systemui.qs.tileimpl.QSTileImpl;
 import com.android.systemui.statusbar.phone.SystemUIDialog;
-import com.android.systemui.statusbar.policy.KeyguardMonitor;
 import com.android.systemui.statusbar.policy.NetworkController;
 import com.android.systemui.statusbar.policy.NetworkController.IconState;
 import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
@@ -62,15 +61,13 @@
 
     private final CellSignalCallback mSignalCallback = new CellSignalCallback();
     private final ActivityStarter mActivityStarter;
-    private final KeyguardMonitor mKeyguardMonitor;
 
     @Inject
     public CellularTile(QSHost host, NetworkController networkController,
-            ActivityStarter activityStarter, KeyguardMonitor keyguardMonitor) {
+            ActivityStarter activityStarter) {
         super(host);
         mController = networkController;
         mActivityStarter = activityStarter;
-        mKeyguardMonitor = keyguardMonitor;
         mDataController = mController.getMobileDataController();
         mDetailAdapter = new CellularDetailAdapter();
         mController.observe(getLifecycle(), mSignalCallback);
@@ -106,11 +103,7 @@
             return;
         }
         if (mDataController.isMobileDataEnabled()) {
-            if (mKeyguardMonitor.isSecure() && !mKeyguardMonitor.canSkipBouncer()) {
-                mActivityStarter.postQSRunnableDismissingKeyguard(this::maybeShowDisableDialog);
-            } else {
-                mUiHandler.post(this::maybeShowDisableDialog);
-            }
+            maybeShowDisableDialog();
         } else {
             mDataController.setMobileDataEnabled(true);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
index 7fcd59f..869fa6b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -235,7 +235,7 @@
         state.label = getTileLabel();
         state.secondaryLabel = TextUtils.emptyIfNull(ZenModeConfig.getDescription(mContext,
                 zen != Global.ZEN_MODE_OFF, mController.getConfig(), false));
-        state.icon = ResourceIcon.get(R.drawable.ic_dnd);
+        state.icon = ResourceIcon.get(com.android.internal.R.drawable.ic_qs_dnd);
         checkIfRestrictionEnforcedByAdminOnly(state, UserManager.DISALLOW_ADJUST_VOLUME);
         switch (zen) {
             case Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS:
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
index dfa3fb9..2755e98 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
@@ -35,7 +35,7 @@
 public class FlashlightTile extends QSTileImpl<BooleanState> implements
         FlashlightController.FlashlightListener {
 
-    private final Icon mIcon = ResourceIcon.get(R.drawable.ic_signal_flashlight);
+    private final Icon mIcon = ResourceIcon.get(com.android.internal.R.drawable.ic_qs_flashlight);
     private final FlashlightController mFlashlightController;
 
     @Inject
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
index a0f4e24..837ea9f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
@@ -37,7 +37,7 @@
 /** Quick settings tile: Location **/
 public class LocationTile extends QSTileImpl<BooleanState> {
 
-    private final Icon mIcon = ResourceIcon.get(com.android.internal.R.drawable.ic_signal_location);
+    private final Icon mIcon = ResourceIcon.get(R.drawable.ic_location);
 
     private final LocationController mController;
     private final KeyguardMonitor mKeyguard;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
index 21f3d6e..7ca1e44 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
@@ -36,7 +36,7 @@
 /** Quick settings tile: Rotation **/
 public class RotationLockTile extends QSTileImpl<BooleanState> {
 
-    private final Icon mIcon = ResourceIcon.get(R.drawable.ic_qs_auto_rotate);
+    private final Icon mIcon = ResourceIcon.get(com.android.internal.R.drawable.ic_qs_auto_rotate);
     private final RotationLockController mController;
 
     @Inject
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
index f921eb9..7853dc3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
@@ -33,7 +33,7 @@
 /** Quick settings tile: Work profile on/off */
 public class WorkModeTile extends QSTileImpl<BooleanState> implements
         ManagedProfileController.Callback {
-    private final Icon mIcon = ResourceIcon.get(R.drawable.ic_signal_workmode_disable);
+    private final Icon mIcon = ResourceIcon.get(R.drawable.stat_sys_managed_profile_status);
 
     private final ManagedProfileController mProfileController;
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 494e6cd..ead39c69 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -439,6 +439,9 @@
         mSupportsRoundedCornersOnWindows = ScreenDecorationsUtils
                 .supportsRoundedCornersOnWindows(mContext.getResources());
 
+        // Assumes device always starts with back button until launcher tells it that it does not
+        mBackButtonAlpha = 1.0f;
+
         // Listen for the package update changes.
         if (mDeviceProvisionedController.getCurrentUser() == UserHandle.USER_SYSTEM) {
             updateEnabledState();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 8faeb15..a87e50c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -308,11 +308,23 @@
             // Walk down a precedence-ordered list of what indication
             // should be shown based on user or device state
             if (mDozing) {
+                // When dozing we ignore any text color and use white instead, because
+                // colors can be hard to read in low brightness.
+                mTextView.setTextColor(Color.WHITE);
                 if (!TextUtils.isEmpty(mTransientIndication)) {
-                    mTextView.setTextColor(Color.WHITE);
                     mTextView.switchIndication(mTransientIndication);
+                } else if (mPowerPluggedIn) {
+                    String indication = computePowerIndication();
+                    if (animate) {
+                        animateText(mTextView, indication);
+                    } else {
+                        mTextView.switchIndication(indication);
+                    }
+                } else {
+                    String percentage = NumberFormat.getPercentInstance()
+                            .format(mBatteryLevel / 100f);
+                    mTextView.switchIndication(percentage);
                 }
-                updateAlphas();
                 return;
             }
 
@@ -353,14 +365,6 @@
         }
     }
 
-    private void updateAlphas() {
-        if (!TextUtils.isEmpty(mTransientIndication)) {
-            mTextView.setAlpha(1f);
-        } else {
-            mTextView.setAlpha(1f - mDarkAmount);
-        }
-    }
-
     // animates textView - textView moves up and bounces down
     private void animateText(KeyguardIndicationTextView textView, String indication) {
         int yTranslation = mContext.getResources().getInteger(
@@ -523,14 +527,6 @@
         pw.println("  computePowerIndication(): " + computePowerIndication());
     }
 
-    public void setDarkAmount(float darkAmount) {
-        if (mDarkAmount == darkAmount) {
-            return;
-        }
-        mDarkAmount = darkAmount;
-        updateAlphas();
-    }
-
     @Override
     public void onStateChanged(int newState) {
         // don't care
@@ -675,6 +671,7 @@
         public void onBiometricAuthenticated(int userId, BiometricSourceType biometricSourceType) {
             super.onBiometricAuthenticated(userId, biometricSourceType);
             mLastSuccessiveErrorMessage = -1;
+            mHandler.sendEmptyMessage(MSG_HIDE_TRANSIENT);
         }
 
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
index cb9060b..cf6e64c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ScrimView.java
@@ -289,4 +289,9 @@
             }
         }
     }
+
+    @Override
+    protected boolean canReceivePointerEvents() {
+        return false;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
index 9630727c..d287b92 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRow.java
@@ -552,6 +552,9 @@
             mEntry.mIsSystemNotification = isSystemNotification(mContext, mStatusBarNotification);
         }
 
+        isNonblockable |= mEntry.channel.isImportanceLockedByOEM();
+        isNonblockable |= mEntry.channel.isImportanceLockedByCriticalDeviceFunction();
+
         if (!isNonblockable && mEntry != null && mEntry.mIsSystemNotification != null) {
             if (mEntry.mIsSystemNotification) {
                 if (mEntry.channel != null
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 520df97..ce20681 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -399,7 +399,7 @@
     private final ViewOutlineProvider mOutlineProvider = new ViewOutlineProvider() {
         @Override
         public void getOutline(View view, Outline outline) {
-            if (mAmbientState.isDarkAtAll() && !mAmbientState.isFullyDark()) {
+            if (mAmbientState.isDarkAtAll() && !mAmbientState.isFullyDark() || !mShowDarkShelf) {
                 outline.setRoundRect(mBackgroundAnimationRect, mCornerRadius);
             } else {
                 ViewOutlineProvider.BACKGROUND.getOutline(view, outline);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
index 236c72c..0731a56 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DemoStatusIcons.java
@@ -108,16 +108,13 @@
             }
             String zen = args.getString("zen");
             if (zen != null) {
-                int iconId = zen.equals("important") ? R.drawable.stat_sys_zen_important
-                        : zen.equals("none") ? R.drawable.stat_sys_zen_none
-                        : 0;
+                int iconId = zen.equals("dnd") ? R.drawable.stat_sys_dnd : 0;
                 updateSlot("zen", null, iconId);
             }
             String bt = args.getString("bluetooth");
             if (bt != null) {
-                int iconId = bt.equals("disconnected") ? R.drawable.stat_sys_data_bluetooth
-                        : bt.equals("connected") ? R.drawable.stat_sys_data_bluetooth_connected
-                        : 0;
+                int iconId = bt.equals("connected")
+                        ? R.drawable.stat_sys_data_bluetooth_connected : 0;
                 updateSlot("bluetooth", null, iconId);
             }
             String location = args.getString("location");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index 800ae58..a924680 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -19,6 +19,7 @@
 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
 import static android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
 
+import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset;
 import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_LEFT_BUTTON;
 import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_LEFT_UNLOCK;
 import static com.android.systemui.tuner.LockscreenFragment.LOCKSCREEN_RIGHT_BUTTON;
@@ -122,6 +123,7 @@
     private KeyguardAffordanceView mRightAffordanceView;
     private KeyguardAffordanceView mLeftAffordanceView;
     private LockIcon mLockIcon;
+    private ViewGroup mLockIconContainer;
     private ViewGroup mIndicationArea;
     private TextView mEnterpriseDisclosure;
     private TextView mIndicationText;
@@ -171,6 +173,8 @@
     private boolean mDozing;
     private int mIndicationBottomMargin;
     private float mDarkAmount;
+    private int mBurnInXOffset;
+    private int mBurnInYOffset;
     private ActivityIntentHelper mActivityIntentHelper;
 
     public KeyguardBottomAreaView(Context context) {
@@ -244,12 +248,15 @@
         mRightAffordanceView = findViewById(R.id.camera_button);
         mLeftAffordanceView = findViewById(R.id.left_button);
         mLockIcon = findViewById(R.id.lock_icon);
+        mLockIconContainer = findViewById(R.id.lock_icon_container);
         mIndicationArea = findViewById(R.id.keyguard_indication_area);
         mEnterpriseDisclosure = findViewById(
                 R.id.keyguard_indication_enterprise_disclosure);
         mIndicationText = findViewById(R.id.keyguard_indication_text);
         mIndicationBottomMargin = getResources().getDimensionPixelSize(
                 R.dimen.keyguard_indication_margin_bottom);
+        mBurnInYOffset = getResources().getDimensionPixelSize(
+                R.dimen.default_burn_in_prevention_offset);
         updateCameraVisibility();
         mUnlockMethodCache = UnlockMethodCache.getInstance(getContext());
         mUnlockMethodCache.addListener(this);
@@ -319,6 +326,8 @@
         super.onConfigurationChanged(newConfig);
         mIndicationBottomMargin = getResources().getDimensionPixelSize(
                 R.dimen.keyguard_indication_margin_bottom);
+        mBurnInYOffset = getResources().getDimensionPixelSize(
+                R.dimen.default_burn_in_prevention_offset);
         MarginLayoutParams mlp = (MarginLayoutParams) mIndicationArea.getLayoutParams();
         if (mlp.bottomMargin != mIndicationBottomMargin) {
             mlp.bottomMargin = mIndicationBottomMargin;
@@ -562,8 +571,8 @@
             return;
         }
         mDarkAmount = darkAmount;
-        mIndicationController.setDarkAmount(darkAmount);
         mLockIcon.setDarkAmount(darkAmount);
+        dozeTimeTick();
     }
 
     /**
@@ -657,6 +666,10 @@
         return mLockIcon;
     }
 
+    public ViewGroup getLockIconContainer() {
+        return mLockIconContainer;
+    }
+
     public View getIndicationArea() {
         return mIndicationArea;
     }
@@ -835,6 +848,20 @@
         }
     }
 
+    public void dozeTimeTick() {
+        int burnInYOffset = getBurnInOffset(mBurnInYOffset * 2, false /* xAxis */)
+                - mBurnInYOffset;
+        mIndicationArea.setTranslationY(burnInYOffset * mDarkAmount);
+    }
+
+    public void setAntiBurnInOffsetX(int burnInXOffset) {
+        if (mBurnInXOffset == burnInXOffset) {
+            return;
+        }
+        mBurnInXOffset = burnInXOffset;
+        mIndicationArea.setTranslationX(burnInXOffset);
+    }
+
     /**
      * Sets the alpha of the indication areas and affordances, excluding the lock icon.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
index fe3a455..5afff81 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBouncer.java
@@ -123,6 +123,7 @@
             return;
         }
         ensureView();
+        mIsScrimmed = isScrimmed;
 
         // On the keyguard, we want to show the bouncer when the user drags up, but it's
         // not correct to end the falsing session. We still need to verify if those touches
@@ -132,13 +133,13 @@
         if (isScrimmed) {
             setExpansion(EXPANSION_VISIBLE);
         }
-        mIsScrimmed = isScrimmed;
 
         if (resetSecuritySelection) {
             // showPrimarySecurityScreen() updates the current security method. This is needed in
             // case we are already showing and the current security method changed.
             showPrimarySecurityScreen();
         }
+
         if (mRoot.getVisibility() == View.VISIBLE || mShowingSoon) {
             return;
         }
@@ -168,8 +169,8 @@
         mCallback.onBouncerVisiblityChanged(true /* shown */);
     }
 
-    public boolean isShowingScrimmed() {
-        return isShowing() && mIsScrimmed;
+    public boolean isScrimmed() {
+        return mIsScrimmed;
     }
 
     public ViewGroup getLockIconContainer() {
@@ -281,6 +282,7 @@
                 StatsLog.KEYGUARD_BOUNCER_STATE_CHANGED__STATE__HIDDEN);
             mDismissCallbackRegistry.notifyDismissCancelled();
         }
+        mIsScrimmed = false;
         mFalsingManager.onBouncerHidden();
         mCallback.onBouncerVisiblityChanged(false /* shown */);
         cancelShowRunnable();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index 4c50d07..2bd8d41 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -17,7 +17,6 @@
 package com.android.systemui.statusbar.phone;
 
 import static com.android.systemui.ScreenDecorations.DisplayCutoutView.boundsFromDirection;
-import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset;
 
 import android.annotation.ColorInt;
 import android.content.Context;
@@ -102,19 +101,6 @@
      */
     private int mCutoutSideNudge = 0;
 
-    /**
-     * How much to move icons to avoid burn in.
-     */
-    private int mBurnInOffset;
-    private int mCurrentBurnInOffsetX;
-    private int mCurrentBurnInOffsetY;
-
-    /**
-     * Ratio representing being in ambient mode or not.
-     */
-    private float mDarkAmount;
-    private boolean mDozing;
-
     public KeyguardStatusBarView(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
@@ -186,8 +172,6 @@
                 R.dimen.system_icons_super_container_avatarless_margin_end);
         mCutoutSideNudge = getResources().getDimensionPixelSize(
                 R.dimen.display_cutout_margin_consumption);
-        mBurnInOffset = getResources().getDimensionPixelSize(
-                R.dimen.default_burn_in_prevention_offset);
         mShowPercentAvailable = getContext().getResources().getBoolean(
                 com.android.internal.R.bool.config_battery_percentage_setting_available);
     }
@@ -211,7 +195,7 @@
                 mMultiUserSwitch.setVisibility(View.GONE);
             }
         }
-        mBatteryView.setForceShowPercent(mBatteryCharging && mShowPercentAvailable || mDozing);
+        mBatteryView.setForceShowPercent(mBatteryCharging && mShowPercentAvailable);
     }
 
     private void updateSystemIconsLayoutParams() {
@@ -348,7 +332,6 @@
         mIconManager = new TintedIconManager(findViewById(R.id.statusIcons));
         Dependency.get(StatusBarIconController.class).addIconGroup(mIconManager);
         onThemeChanged();
-        updateDarkState();
     }
 
     @Override
@@ -492,7 +475,7 @@
             mIconManager.setTint(iconColor);
         }
 
-        applyDarkness(R.id.battery, mEmptyRect, intensity * (1f - mDarkAmount), iconColor);
+        applyDarkness(R.id.battery, mEmptyRect, intensity, iconColor);
         applyDarkness(R.id.clock, mEmptyRect, intensity, iconColor);
     }
 
@@ -513,48 +496,4 @@
             mBatteryView.dump(fd, pw, args);
         }
     }
-
-    public void setDozing(boolean dozing) {
-        if (mDozing == dozing) {
-            return;
-        }
-        mDozing = dozing;
-        setClipChildren(!dozing);
-        setClipToPadding(!dozing);
-        updateVisibilities();
-    }
-
-    public void setDarkAmount(float darkAmount) {
-        mDarkAmount = darkAmount;
-        if (darkAmount == 0) {
-            dozeTimeTick();
-        }
-        updateDarkState();
-    }
-
-    public void dozeTimeTick() {
-        mCurrentBurnInOffsetX = getBurnInOffset(mBurnInOffset, true /* xAxis */);
-        mCurrentBurnInOffsetY = getBurnInOffset(mBurnInOffset, false /* xAxis */);
-        updateDarkState();
-    }
-
-    private void updateDarkState() {
-        float alpha = 1f - mDarkAmount;
-        int visibility = alpha != 0f ? VISIBLE : INVISIBLE;
-        mCarrierLabel.setAlpha(alpha * alpha);
-        mStatusIconContainer.setAlpha(alpha);
-        mStatusIconContainer.setVisibility(visibility);
-
-        float iconsX = -mCurrentBurnInOffsetX;
-        if (mMultiUserSwitch.getVisibility() == VISIBLE) {
-            // Squared alpha to add a nice easing curve and avoid overlap during animation.
-            mMultiUserAvatar.setAlpha(alpha * alpha);
-            iconsX += mMultiUserAvatar.getPaddingLeft() + mMultiUserAvatar.getWidth()
-                    + mMultiUserAvatar.getPaddingRight();
-        }
-        mSystemIconsContainer.setTranslationX(iconsX * mDarkAmount);
-        mSystemIconsContainer.setTranslationY(mCurrentBurnInOffsetY * mDarkAmount);
-        updateIconsAndTextColors();
-    }
-
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavBarTintController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavBarTintController.java
index 9cfb1aa..bf5b60a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavBarTintController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavBarTintController.java
@@ -19,11 +19,14 @@
 import static android.view.Display.DEFAULT_DISPLAY;
 
 import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.Handler;
 import android.view.CompositionSamplingListener;
 import android.view.View;
 
+import com.android.systemui.R;
 import com.android.systemui.shared.system.QuickStepContract;
 
 import java.io.PrintWriter;
@@ -37,9 +40,6 @@
     public static final int MIN_COLOR_ADAPT_TRANSITION_TIME = 400;
     public static final int DEFAULT_COLOR_ADAPT_TRANSITION_TIME = 1700;
 
-    // Passing the threshold of this luminance value will make the button black otherwise white
-    private static final float LUMINANCE_THRESHOLD = 0.3f;
-
     private final Handler mHandler = new Handler();
     private final NavigationBarView mNavigationBarView;
     private final LightBarTransitionsController mLightBarController;
@@ -50,9 +50,17 @@
     private boolean mSamplingEnabled = false;
     private boolean mSamplingListenerRegistered = false;
 
-    private float mLastMediaLuma;
+    private float mLastMedianLuma;
+    private float mCurrentMedianLuma;
     private boolean mUpdateOnNextDraw;
 
+    private final int mNavBarHeight;
+    private final int mNavColorSampleMargin;
+
+    // Passing the threshold of this luminance value will make the button black otherwise white
+    private final float mLuminanceThreshold;
+    private final float mLuminanceChangeThreshold;
+
     public NavBarTintController(NavigationBarView navigationBarView,
             LightBarTransitionsController lightBarController) {
         mSamplingListener = new CompositionSamplingListener(
@@ -66,6 +74,13 @@
         mNavigationBarView.addOnAttachStateChangeListener(this);
         mNavigationBarView.addOnLayoutChangeListener(this);
         mLightBarController = lightBarController;
+
+        final Resources res = navigationBarView.getResources();
+        mNavBarHeight = res.getDimensionPixelSize(R.dimen.navigation_bar_height);
+        mNavColorSampleMargin =
+                res.getDimensionPixelSize(R.dimen.navigation_handle_sample_horizontal_margin);
+        mLuminanceThreshold = res.getFloat(R.dimen.navigation_luminance_threshold);
+        mLuminanceChangeThreshold = res.getFloat(R.dimen.navigation_luminance_change_threshold);
     }
 
     void onDraw() {
@@ -109,8 +124,11 @@
         if (view != null) {
             int[] pos = new int[2];
             view.getLocationOnScreen(pos);
-            final Rect samplingBounds = new Rect(pos[0], pos[1],
-                    pos[0] + view.getWidth(), pos[1] + view.getHeight());
+            Point displaySize = new Point();
+            view.getContext().getDisplay().getRealSize(displaySize);
+            final Rect samplingBounds = new Rect(pos[0] - mNavColorSampleMargin,
+                    displaySize.y - mNavBarHeight, pos[0] + view.getWidth() + mNavColorSampleMargin,
+                    displaySize.y);
             if (!samplingBounds.equals(mSamplingBounds)) {
                 mSamplingBounds.set(samplingBounds);
                 requestUpdateSamplingListener();
@@ -144,13 +162,19 @@
     }
 
     private void updateTint(float medianLuma) {
-        mLastMediaLuma = medianLuma;
-        if (medianLuma > LUMINANCE_THRESHOLD) {
-            // Black
-            mLightBarController.setIconsDark(true /* dark */, true /* animate */);
-        } else {
-            // White
-            mLightBarController.setIconsDark(false /* dark */, true /* animate */);
+        mLastMedianLuma = medianLuma;
+
+        // If the difference between the new luma and the current luma is larger than threshold
+        // then apply the current luma, this is to prevent small changes causing colors to flicker
+        if (Math.abs(mCurrentMedianLuma - mLastMedianLuma) > mLuminanceChangeThreshold) {
+            if (medianLuma > mLuminanceThreshold) {
+                // Black
+                mLightBarController.setIconsDark(true /* dark */, true /* animate */);
+            } else {
+                // White
+                mLightBarController.setIconsDark(false /* dark */, true /* animate */);
+            }
+            mCurrentMedianLuma = medianLuma;
         }
     }
 
@@ -162,7 +186,8 @@
                 : "false"));
         pw.println("  mSamplingListenerRegistered: " + mSamplingListenerRegistered);
         pw.println("  mSamplingBounds: " + mSamplingBounds);
-        pw.println("  mLastMediaLuma: " + mLastMediaLuma);
+        pw.println("  mLastMedianLuma: " + mLastMedianLuma);
+        pw.println("  mCurrentMedianLuma: " + mCurrentMedianLuma);
     }
 
     public static boolean isEnabled(Context context) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index bfbe886..f2d6241 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -1195,7 +1195,8 @@
         if (DEBUG) Log.d(TAG, String.format(
                 "onMeasure: (%dx%d) old: (%dx%d)", w, h, getMeasuredWidth(), getMeasuredHeight()));
 
-        final boolean newVertical = w > 0 && h > w;
+        final boolean newVertical = w > 0 && h > w
+                && !QuickStepContract.isGesturalMode(getContext());
         if (newVertical != mIsVertical) {
             mIsVertical = newVertical;
             if (DEBUG) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationHandle.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationHandle.java
index 968074c..81a425c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationHandle.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationHandle.java
@@ -68,7 +68,7 @@
         int height = mRadius * 2;
         int width = getWidth();
         int y = (navHeight - mBottom - height);
-        canvas.drawRoundRect(mRadius, y, width - mRadius, y + height, mRadius, mRadius, mPaint);
+        canvas.drawRoundRect(0, y, width, y + height, mRadius, mRadius, mPaint);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 2c4679e..02bad73 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -635,6 +635,7 @@
         }
         mNotificationStackScroller.setIntrinsicPadding(stackScrollerPadding);
         mNotificationStackScroller.setAntiBurnInOffsetX(mClockPositionResult.clockX);
+        mKeyguardBottomArea.setAntiBurnInOffsetX(mClockPositionResult.clockX);
 
         mStackScrollerMeasuringPass++;
         requestScrollerTopPaddingUpdate(animate);
@@ -1886,7 +1887,7 @@
         float newAlpha = Math.min(getKeyguardContentsAlpha(), alphaQsExpansion)
                 * mKeyguardStatusBarAnimateAlpha;
         mKeyguardStatusBar.setAlpha(newAlpha);
-        mKeyguardStatusBar.setVisibility(newAlpha != 0f ? VISIBLE : INVISIBLE);
+        mKeyguardStatusBar.setVisibility(newAlpha != 0f && !mDozing ? VISIBLE : INVISIBLE);
     }
 
     private void updateKeyguardBottomAreaAlpha() {
@@ -2373,12 +2374,11 @@
         positionClockAndNotifications();
     }
 
-    private static float interpolate(float t, float start, float end) {
-        return (1 - t) * start + t * end;
-    }
-
     private void updateDozingVisibilities(boolean animate) {
         mKeyguardBottomArea.setDozing(mDozing, animate);
+        if (!mDozing && animate) {
+            animateKeyguardStatusBarIn(StackStateAnimator.ANIMATION_DURATION_STANDARD);
+        }
     }
 
     @Override
@@ -2814,7 +2814,7 @@
         if (mDozing) {
             mNotificationStackScroller.setShowDarkShelf(!hasCustomClock());
         }
-        mKeyguardStatusBar.setDozing(mDozing);
+        mKeyguardBottomArea.setDozing(mDozing, animate);
 
         if (mBarState == StatusBarState.KEYGUARD
                 || mBarState == StatusBarState.SHADE_LOCKED) {
@@ -2829,7 +2829,6 @@
     public void onDozeAmountChanged(float linearAmount, float amount) {
         mInterpolatedDarkAmount = amount;
         mLinearDarkAmount = linearAmount;
-        mKeyguardStatusBar.setDarkAmount(mInterpolatedDarkAmount);
         mKeyguardStatusView.setDarkAmount(mInterpolatedDarkAmount);
         mKeyguardBottomArea.setDarkAmount(mInterpolatedDarkAmount);
         positionClockAndNotifications();
@@ -2861,7 +2860,7 @@
     }
 
     public void dozeTimeTick() {
-        mKeyguardStatusBar.dozeTimeTick();
+        mKeyguardBottomArea.dozeTimeTick();
         mKeyguardStatusView.dozeTimeTick();
         if (mInterpolatedDarkAmount > 0) {
             positionClockAndNotifications();
@@ -3040,6 +3039,7 @@
         }
 
         ViewGroup bouncerContainer = mBouncer.getLockIconContainer();
+        ViewGroup bottomContainer = mKeyguardBottomArea.getLockIconContainer();
         LockIcon lockIcon = mKeyguardBottomArea.getLockIcon();
 
         if (mBouncer.isAnimatingAway()) {
@@ -3051,9 +3051,21 @@
             return;
         }
 
+        // Lock icon needs to be re-parented in case of a scrimmed bouncer,
+        // otherwise it would be under the scrim.
+        if (mBouncer.isScrimmed() && bouncerContainer != null
+                && lockIcon.getParent() != bouncerContainer) {
+            ((ViewGroup) lockIcon.getParent()).removeView(lockIcon);
+            bouncerContainer.addView(lockIcon);
+        } else if (!mBouncer.isScrimmed() && bottomContainer != null
+                && lockIcon.getParent() != bottomContainer) {
+            ((ViewGroup) lockIcon.getParent()).removeView(lockIcon);
+            bottomContainer.addView(lockIcon);
+        }
+
         float translation = 0;
-        if (bouncerContainer != null) {
-            float bottomAreaContainerY = getCommonTop(lockIcon);
+        if (bouncerContainer != null && bottomContainer != null && !mBouncer.isScrimmed()) {
+            float bottomAreaContainerY = getCommonTop(bottomContainer);
             float bouncerLockY = getCommonTop(bouncerContainer);
             if (bouncerLockY < bottomAreaContainerY) {
                 translation = bouncerLockY - bottomAreaContainerY;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
index b7a7873..183fdb4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java
@@ -201,7 +201,7 @@
         mIconController.setIconVisibility(mSlotAlarmClock, false);
 
         // zen
-        mIconController.setIcon(mSlotZen, R.drawable.stat_sys_zen_important, null);
+        mIconController.setIcon(mSlotZen, R.drawable.stat_sys_dnd, null);
         mIconController.setIconVisibility(mSlotZen, false);
 
         // volume
@@ -339,11 +339,11 @@
             zenDescription = mContext.getString(R.string.quick_settings_dnd_label);
         } else if (zen == Global.ZEN_MODE_NO_INTERRUPTIONS) {
             zenVisible = true;
-            zenIconId = R.drawable.stat_sys_zen_none;
+            zenIconId = R.drawable.stat_sys_dnd;
             zenDescription = mContext.getString(R.string.interruption_level_none);
         } else if (zen == Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS) {
             zenVisible = true;
-            zenIconId = R.drawable.stat_sys_zen_important;
+            zenIconId = R.drawable.stat_sys_dnd;
             zenDescription = mContext.getString(R.string.interruption_level_priority);
         }
 
@@ -388,13 +388,12 @@
     }
 
     private final void updateBluetooth() {
-        int iconId = R.drawable.stat_sys_data_bluetooth;
+        int iconId = R.drawable.stat_sys_data_bluetooth_connected;
         String contentDescription =
                 mContext.getString(R.string.accessibility_quick_settings_bluetooth_on);
         boolean bluetoothVisible = false;
         if (mBluetooth != null) {
             if (mBluetooth.isBluetoothConnected()) {
-                iconId = R.drawable.stat_sys_data_bluetooth_connected;
                 contentDescription = mContext.getString(R.string.accessibility_bluetooth_connected);
                 bluetoothVisible = mBluetooth.isBluetoothEnabled();
             }
@@ -582,8 +581,8 @@
             String contentDescription = mContext.getString(hasMic
                     ? R.string.accessibility_status_bar_headset
                     : R.string.accessibility_status_bar_headphones);
-            mIconController.setIcon(mSlotHeadset, hasMic ? R.drawable.ic_headset_mic
-                    : R.drawable.ic_headset, contentDescription);
+            mIconController.setIcon(mSlotHeadset, hasMic ? R.drawable.stat_sys_headset_mic
+                    : R.drawable.stat_sys_headset, contentDescription);
             mIconController.setIconVisibility(mSlotHeadset, true);
         } else {
             mIconController.setIconVisibility(mSlotHeadset, false);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 1949bad..0d2fe13 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -92,7 +92,7 @@
     /**
      * Scrim opacity when the phone is about to wake-up.
      */
-    public static final float AOD2_SCRIM_ALPHA = 0.6f;
+    public static final float WAKE_SENSOR_SCRIM_ALPHA = 0.6f;
     /**
      * A scrim varies its opacity based on a busyness factor, for example
      * how many notifications are currently visible.
@@ -458,6 +458,23 @@
         mState.AOD.setAodFrontScrimAlpha(alpha);
     }
 
+    /**
+     * If the lock screen sensor is active.
+     */
+    public void setWakeLockScreenSensorActive(boolean active) {
+        for (ScrimState state : ScrimState.values()) {
+            state.setWakeLockScreenSensorActive(active);
+        }
+
+        if (mState == ScrimState.PULSING) {
+            float newBehindAlpha = mState.getBehindAlpha();
+            if (mCurrentBehindAlpha != newBehindAlpha) {
+                mCurrentBehindAlpha = newBehindAlpha;
+                updateScrims();
+            }
+        }
+    }
+
     protected void scheduleUpdate() {
         if (mUpdatePending) return;
 
@@ -904,10 +921,6 @@
         }
     }
 
-    public void setPulseReason(int pulseReason) {
-        ScrimState.PULSING.setPulseReason(pulseReason);
-    }
-
     public interface Callback {
         default void onStart() {
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
index 2f161d5..d152ecd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimState.java
@@ -19,7 +19,6 @@
 import android.graphics.Color;
 import android.os.Trace;
 
-import com.android.systemui.doze.DozeLog;
 import com.android.systemui.statusbar.ScrimView;
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
 
@@ -129,16 +128,15 @@
         @Override
         public void prepare(ScrimState previousState) {
             mCurrentInFrontAlpha = 0f;
-            if (mPulseReason == DozeLog.PULSE_REASON_NOTIFICATION
-                    || mPulseReason == DozeLog.PULSE_REASON_DOCKING
-                    || mPulseReason == DozeLog.PULSE_REASON_INTENT) {
-                mCurrentBehindAlpha = previousState.getBehindAlpha();
-            } else {
-                mCurrentBehindAlpha = ScrimController.AOD2_SCRIM_ALPHA;
-            }
             mCurrentBehindTint = Color.BLACK;
             mBlankScreen = mDisplayRequiresBlanking;
         }
+
+        @Override
+        public float getBehindAlpha() {
+            return mWakeLockScreenSensorActive ? ScrimController.WAKE_SENSOR_SCRIM_ALPHA
+                    : AOD.getBehindAlpha();
+        }
     },
 
     /**
@@ -199,7 +197,7 @@
     int mIndex;
     boolean mHasBackdrop;
     boolean mLaunchingAffordanceWithPreview;
-    int mPulseReason;
+    boolean mWakeLockScreenSensorActive;
 
     ScrimState(int index) {
         mIndex = index;
@@ -264,10 +262,6 @@
         mAodFrontScrimAlpha = aodFrontScrimAlpha;
     }
 
-    public void setPulseReason(int pulseReason) {
-        mPulseReason = pulseReason;
-    }
-
     public void setScrimBehindAlphaKeyguard(float scrimBehindAlphaKeyguard) {
         mScrimBehindAlphaKeyguard = scrimBehindAlphaKeyguard;
     }
@@ -287,4 +281,8 @@
     public void setHasBackdrop(boolean hasBackdrop) {
         mHasBackdrop = hasBackdrop;
     }
+
+    public void setWakeLockScreenSensorActive(boolean active) {
+        mWakeLockScreenSensorActive = active;
+    }
 }
\ No newline at end of file
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 5d52359..db91d01 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -434,6 +434,9 @@
         public void onUserSetupChanged() {
             final boolean userSetup = mDeviceProvisionedController.isUserSetup(
                     mDeviceProvisionedController.getCurrentUser());
+            // STOPSHIP(kozynski, b/129405675) Remove log
+            Log.d(TAG, "mUserSetupObserver - DeviceProvisionedListener called for user "
+                    + mDeviceProvisionedController.getCurrentUser());
             if (MULTIUSER_DEBUG) {
                 Log.d(TAG, String.format("User setup changed: userSetup=%s mUserSetup=%s",
                         userSetup, mUserSetup));
@@ -1297,13 +1300,16 @@
      * the user intends to use the lock screen user switcher, QS in not needed.
      */
     private void updateQsExpansionEnabled() {
-        mNotificationPanel.setQsExpansionEnabled(mDeviceProvisionedController.isDeviceProvisioned()
+        final boolean expandEnabled = mDeviceProvisionedController.isDeviceProvisioned()
                 && (mUserSetup || mUserSwitcherController == null
                         || !mUserSwitcherController.isSimpleUserSwitcher())
                 && ((mDisabled2 & StatusBarManager.DISABLE2_NOTIFICATION_SHADE) == 0)
                 && ((mDisabled2 & StatusBarManager.DISABLE2_QUICK_SETTINGS) == 0)
                 && !mDozing
-                && !ONLY_CORE_APPS);
+                && !ONLY_CORE_APPS;
+        mNotificationPanel.setQsExpansionEnabled(expandEnabled);
+        // STOPSHIP(kozynski, b/129405675) Remove log
+        Log.d(TAG, "updateQsExpansionEnabled - QS Expand enabled: " + expandEnabled);
     }
 
     public void addQsTile(ComponentName tile) {
@@ -3902,7 +3908,6 @@
 
         @Override
         public void pulseWhileDozing(@NonNull PulseCallback callback, int reason) {
-            mScrimController.setPulseReason(reason);
             if (reason == DozeLog.PULSE_REASON_SENSOR_LONG_PRESS) {
                 mPowerManager.wakeUp(SystemClock.uptimeMillis(), PowerManager.WAKE_REASON_GESTURE,
                         "com.android.systemui:LONG_PRESS");
@@ -3910,6 +3915,10 @@
                 return;
             }
 
+            if (reason == DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN) {
+                mScrimController.setWakeLockScreenSensorActive(true);
+            }
+
             boolean passiveAuthInterrupt = reason == DozeLog.PULSE_REASON_NOTIFICATION;
             // Set the state to pulsing, so ScrimController will know what to do once we ask it to
             // execute the transition. The pulse callback will then be invoked when the scrims
@@ -3928,6 +3937,7 @@
                     mPulsing = false;
                     callback.onPulseFinished();
                     updateNotificationPanelTouchState();
+                    mScrimController.setWakeLockScreenSensorActive(false);
                     setPulsing(false);
                 }
 
@@ -4004,7 +4014,10 @@
         }
 
         @Override
-        public void extendPulse() {
+        public void extendPulse(int reason) {
+            if (reason == DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN) {
+                mScrimController.setWakeLockScreenSensorActive(true);
+            }
             if (mDozeScrimController.isPulsing() && mAmbientPulseManager.hasNotifications()) {
                 mAmbientPulseManager.extendPulse();
             } else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 4412851..3b32d95 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -86,6 +86,7 @@
         public void onFullyShown() {
             updateStates();
             mStatusBar.wakeUpIfDozing(SystemClock.uptimeMillis(), mContainer, "BOUNCER_VISIBLE");
+            mNotificationPanelView.updateLockIcon();
         }
 
         @Override
@@ -96,6 +97,7 @@
         @Override
         public void onFullyHidden() {
             updateStates();
+            mNotificationPanelView.updateLockIcon();
         }
 
         @Override
@@ -758,8 +760,10 @@
     }
 
     public boolean bouncerNeedsScrimming() {
-        return mOccluded || mBouncer.willDismissWithAction()  || mBouncer.needsFullscreenBouncer()
-                || mStatusBar.isFullScreenUserSwitcherState() || mBouncer.isShowingScrimmed();
+        return mOccluded || mBouncer.willDismissWithAction()
+                || mStatusBar.isFullScreenUserSwitcherState()
+                || (mBouncer.isShowing() && mBouncer.isScrimmed())
+                || mBouncer.isFullscreenBouncer();
     }
 
     public void dump(PrintWriter pw) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.java
index f5e745f..db2523e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/DeviceProvisionedControllerImpl.java
@@ -21,9 +21,10 @@
 import android.content.Context;
 import android.database.ContentObserver;
 import android.net.Uri;
+import android.os.Handler;
 import android.provider.Settings.Global;
 import android.provider.Settings.Secure;
-import android.os.Handler;
+import android.util.Log;
 
 import com.android.systemui.settings.CurrentUserTracker;
 
@@ -39,6 +40,7 @@
 public class DeviceProvisionedControllerImpl extends CurrentUserTracker implements
         DeviceProvisionedController {
 
+    private static final String TAG = DeviceProvisionedControllerImpl.class.getSimpleName();
     private final ArrayList<DeviceProvisionedListener> mListeners = new ArrayList<>();
     private final ContentResolver mContentResolver;
     private final Context mContext;
@@ -59,6 +61,8 @@
         mSettingsObserver = new ContentObserver(mainHandler) {
             @Override
             public void onChange(boolean selfChange, Uri uri, int userId) {
+                // STOPSHIP(kozynski, b/129405675) Remove log
+                Log.d(TAG, "Setting change: " + uri);
                 if (mUserSetupUri.equals(uri)) {
                     notifySetupChanged();
                 } else {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index e5f709a..35a2450 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -288,7 +288,7 @@
                 addRow(AudioManager.STREAM_RING,
                         R.drawable.ic_volume_ringer, R.drawable.ic_volume_ringer_mute, true, false);
                 addRow(STREAM_ALARM,
-                        R.drawable.ic_volume_alarm, R.drawable.ic_volume_alarm_mute, true, false);
+                        R.drawable.ic_alarm, R.drawable.ic_volume_alarm_mute, true, false);
                 addRow(AudioManager.STREAM_VOICE_CALL,
                         com.android.internal.R.drawable.ic_phone,
                         com.android.internal.R.drawable.ic_phone, false, false);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
index f666d60..14bc71b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -71,6 +71,9 @@
 @TestableLooper.RunWithLooper(setAsMainLooper = true)
 public class BubbleControllerTest extends SysuiTestCase {
 
+    // Some APIs rely on the app being foreground, check is via pkg name
+    private static final String FOREGROUND_TEST_PKG_NAME = "com.android.systemui.tests";
+
     @Mock
     private NotificationEntryManager mNotificationEntryManager;
     @Mock
@@ -95,6 +98,7 @@
     private ExpandableNotificationRow mRow2;
     private ExpandableNotificationRow mNoChannelRow;
     private ExpandableNotificationRow mAutoExpandRow;
+    private ExpandableNotificationRow mSuppressNotifRow;
 
     @Mock
     private NotificationData mNotificationData;
@@ -126,9 +130,18 @@
         mRow = mNotificationTestHelper.createBubble(mDeleteIntent);
         mRow2 = mNotificationTestHelper.createBubble(mDeleteIntent);
         mNoChannelRow = mNotificationTestHelper.createBubble(mDeleteIntent);
-        Notification.BubbleMetadata metadata = getBuilder().setAutoExpandBubble(true).build();
-        mAutoExpandRow = mNotificationTestHelper.createBubble(metadata,
-                "com.android.systemui.tests");
+
+        // Some bubbles want to auto expand
+        Notification.BubbleMetadata autoExpandMetadata =
+                getBuilder().setAutoExpandBubble(true).build();
+        mAutoExpandRow = mNotificationTestHelper.createBubble(autoExpandMetadata,
+                FOREGROUND_TEST_PKG_NAME);
+
+        // Some bubbles want to suppress notifs
+        Notification.BubbleMetadata suppressNotifMetadata =
+                getBuilder().setSuppressInitialNotification(true).build();
+        mSuppressNotifRow = mNotificationTestHelper.createBubble(suppressNotifMetadata,
+                FOREGROUND_TEST_PKG_NAME);
 
         // Return non-null notification data from the NEM
         when(mNotificationEntryManager.getNotificationData()).thenReturn(mNotificationData);
@@ -317,7 +330,7 @@
     }
 
     @Test
-    public void testAutoExpandFailsNotForeground() {
+    public void testAutoExpand_FailsNotForeground() {
         assertFalse(mBubbleController.isStackExpanded());
 
         // Add the auto expand bubble
@@ -334,7 +347,7 @@
     }
 
     @Test
-    public void testAutoExpandSucceedsForeground() {
+    public void testAutoExpand_SucceedsForeground() {
         final CountDownLatch latch = new CountDownLatch(1);
         BroadcastReceiver receiver = new BroadcastReceiver() {
             @Override
@@ -372,6 +385,57 @@
         mContext.unregisterReceiver(receiver);
     }
 
+    @Test
+    public void testSuppressNotif_FailsNotForeground() {
+        // Add the suppress notif bubble
+        mEntryListener.onPendingEntryAdded(mSuppressNotifRow.getEntry());
+        mBubbleController.updateBubble(mSuppressNotifRow.getEntry(), true /* updatePosition */);
+
+        // Should be a bubble & should show in shade because we weren't forground
+        assertTrue(mSuppressNotifRow.getEntry().isBubble());
+        assertTrue(mSuppressNotifRow.getEntry().showInShadeWhenBubble());
+
+        // # of bubbles should change
+        verify(mBubbleStateChangeListener).onHasBubblesChanged(true /* hasBubbles */);
+    }
+
+    @Test
+    public void testSuppressNotif_SucceedsForeground() {
+        final CountDownLatch latch = new CountDownLatch(1);
+        BroadcastReceiver receiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                latch.countDown();
+            }
+        };
+        IntentFilter filter = new IntentFilter(BubblesTestActivity.BUBBLE_ACTIVITY_OPENED);
+        mContext.registerReceiver(receiver, filter);
+
+        assertFalse(mBubbleController.isStackExpanded());
+
+        // Make ourselves foreground
+        Intent i = new Intent(mContext, BubblesTestActivity.class);
+        i.setFlags(FLAG_ACTIVITY_NEW_TASK);
+        mContext.startActivity(i);
+
+        try {
+            latch.await(100, TimeUnit.MILLISECONDS);
+        } catch (InterruptedException e) {
+            e.printStackTrace();
+        }
+
+        // Add the suppress notif bubble
+        mEntryListener.onPendingEntryAdded(mSuppressNotifRow.getEntry());
+        mBubbleController.updateBubble(mSuppressNotifRow.getEntry(), true /* updatePosition */);
+
+        // Should be a bubble & should NOT show in shade because we were foreground
+        assertTrue(mSuppressNotifRow.getEntry().isBubble());
+        assertFalse(mSuppressNotifRow.getEntry().showInShadeWhenBubble());
+
+        // # of bubbles should change
+        verify(mBubbleStateChangeListener).onHasBubblesChanged(true /* hasBubbles */);
+        mContext.unregisterReceiver(receiver);
+    }
 
     @Test
     public void testMarkNewNotificationAsBubble() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java
index dc42872..abfa755 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeHostFake.java
@@ -86,7 +86,7 @@
     }
 
     @Override
-    public void extendPulse() {
+    public void extendPulse(int reason) {
         pulseExtended = true;
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeWallpaperStateTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeWallpaperStateTest.java
index beba905..87ae85f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeWallpaperStateTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeWallpaperStateTest.java
@@ -45,12 +45,11 @@
     private DozeWallpaperState mDozeWallpaperState;
     @Mock IWallpaperManager mIWallpaperManager;
     @Mock DozeParameters mDozeParameters;
-    @Mock DozeMachine mMachine;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        mDozeWallpaperState = new DozeWallpaperState(mMachine, mIWallpaperManager, mDozeParameters);
+        mDozeWallpaperState = new DozeWallpaperState(mIWallpaperManager, mDozeParameters);
     }
 
     @Test
@@ -110,28 +109,18 @@
     }
 
     @Test
-    public void testTransitionTo_notificationPulseIsAmbientMode() throws RemoteException {
-        when(mMachine.getPulseReason()).thenReturn(DozeLog.PULSE_REASON_NOTIFICATION);
-        mDozeWallpaperState.transitionTo(DozeMachine.State.DOZE_REQUEST_PULSE,
-                DozeMachine.State.DOZE_PULSING);
-        verify(mIWallpaperManager).setInAmbientMode(eq(true), eq(0L));
-    }
-
-    @Test
     public void testTransitionTo_wakeFromPulseIsNotAmbientMode() throws RemoteException {
-        when(mMachine.getPulseReason()).thenReturn(DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN);
         mDozeWallpaperState.transitionTo(DozeMachine.State.DOZE_AOD,
                 DozeMachine.State.DOZE_REQUEST_PULSE);
         reset(mIWallpaperManager);
 
         mDozeWallpaperState.transitionTo(DozeMachine.State.DOZE_REQUEST_PULSE,
-                DozeMachine.State.DOZE_PULSING);
+                DozeMachine.State.DOZE_PULSING_BRIGHT);
         verify(mIWallpaperManager).setInAmbientMode(eq(false), anyLong());
     }
 
     @Test
     public void testTransitionTo_animatesWhenWakingUpFromPulse() throws RemoteException {
-        when(mMachine.getPulseReason()).thenReturn(DozeLog.PULSE_REASON_NOTIFICATION);
         mDozeWallpaperState.transitionTo(DozeMachine.State.DOZE_REQUEST_PULSE,
                 DozeMachine.State.DOZE_PULSING);
         reset(mIWallpaperManager);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
index f51e473..5928a07 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
@@ -265,6 +265,12 @@
         state.mIsPowerSaver = true;
         shouldShow = mPowerUI.shouldShowHybridWarning(state.get());
         assertThat(shouldShow).isFalse();
+
+        state.mIsPowerSaver = false;
+        // if disabled we should not show the low warning.
+        state.mIsLowLevelWarningEnabled = false;
+        shouldShow = mPowerUI.shouldShowHybridWarning(state.get());
+        assertThat(shouldShow).isFalse();
     }
 
     @Test
@@ -365,7 +371,7 @@
         assertThat(refreshedEstimate.getEstimateMillis()).isEqualTo(BELOW_HYBRID_THRESHOLD);
         BatteryStateSnapshot snapshot = new BatteryStateSnapshot(
                 BATTERY_LEVEL_10, false, false, 0, BatteryManager.BATTERY_HEALTH_GOOD,
-                0, 0, -1, 0, 0, false);
+                0, 0, -1, 0, 0, false, true);
         mPowerUI.mLastBatteryStateSnapshot = snapshot;
 
         // query again since the estimate was -1
@@ -375,7 +381,7 @@
         assertThat(refreshedEstimate.getEstimateMillis()).isEqualTo(BELOW_SEVERE_HYBRID_THRESHOLD);
         snapshot = new BatteryStateSnapshot(
                 BATTERY_LEVEL_10, false, false, 0, BatteryManager.BATTERY_HEALTH_GOOD, 0,
-                0, BELOW_SEVERE_HYBRID_THRESHOLD, 0, 0, false);
+                0, BELOW_SEVERE_HYBRID_THRESHOLD, 0, 0, false, true);
         mPowerUI.mLastBatteryStateSnapshot = snapshot;
 
         // Battery level hasn't changed, so we don't query again
@@ -536,13 +542,14 @@
         public long mTimeRemainingMillis = Duration.ofHours(24).toMillis();
         public boolean mIsBasedOnUsage = true;
         public boolean mIsHybrid = true;
+        public boolean mIsLowLevelWarningEnabled = true;
 
         public BatteryStateSnapshot get() {
             if (mIsHybrid) {
                 return new BatteryStateSnapshot(mBatteryLevel, mIsPowerSaver, mPlugged, mBucket,
                         mBatteryStatus, mSevereLevelThreshold, mLowLevelThreshold,
                         mTimeRemainingMillis, mSevereThresholdMillis, mLowThresholdMillis,
-                        mIsBasedOnUsage);
+                        mIsBasedOnUsage, mIsLowLevelWarningEnabled);
             } else {
                 return new BatteryStateSnapshot(mBatteryLevel, mIsPowerSaver, mPlugged, mBucket,
                         mBatteryStatus, mSevereLevelThreshold, mLowLevelThreshold);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
index 8c5f6f2..5ea4636 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationTestHelper.java
@@ -212,7 +212,7 @@
      *
      * @return a notification with no special properties
      */
-    private Notification createNotification() {
+    public Notification createNotification() {
         return createNotification(false /* isGroupSummary */, null /* groupKey */);
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
index 0aa103f..8077e3f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
@@ -37,7 +37,9 @@
 import static org.mockito.Mockito.when;
 
 import android.app.AppOpsManager;
+import android.app.Notification;
 import android.app.NotificationChannel;
+import android.os.UserHandle;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
 import android.testing.TestableLooper.RunWithLooper;
@@ -355,4 +357,30 @@
         mGroupRow.setUserExpanded(true);
         Assert.assertTrue(mGroupRow.isExpanded());
     }
+
+    @Test
+    public void testGetIsNonblockable() throws Exception {
+        ExpandableNotificationRow row =
+                mNotificationTestHelper.createRow(mNotificationTestHelper.createNotification());
+
+        assertFalse(row.getIsNonblockable());
+    }
+
+    @Test
+    public void testGetIsNonblockable_oemLocked() throws Exception {
+        ExpandableNotificationRow row =
+                mNotificationTestHelper.createRow(mNotificationTestHelper.createNotification());
+        row.getEntry().channel.setImportanceLockedByOEM(true);
+
+        assertTrue(row.getIsNonblockable());
+    }
+
+    @Test
+    public void testGetIsNonblockable_criticalDeviceFunction() throws Exception {
+        ExpandableNotificationRow row =
+                mNotificationTestHelper.createRow(mNotificationTestHelper.createNotification());
+        row.getEntry().channel.setImportanceLockedByCriticalDeviceFunction(true);
+
+        assertTrue(row.getIsNonblockable());
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
index e84dd68..c2e60d9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBouncerTest.java
@@ -21,6 +21,7 @@
 import static org.mockito.ArgumentMatchers.anyFloat;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.verify;
@@ -336,11 +337,25 @@
     }
 
     @Test
-    public void testIsShowingScrimmed() {
+    public void testIsShowingScrimmed_true() {
+        doAnswer(invocation -> {
+            assertThat(mBouncer.isScrimmed()).isTrue();
+            return null;
+        }).when(mExpansionCallback).onFullyShown();
         mBouncer.show(false /* resetSecuritySelection */, true /* animate */);
-        assertThat(mBouncer.isShowingScrimmed()).isTrue();
+        assertThat(mBouncer.isScrimmed()).isTrue();
+        mBouncer.hide(false /* destroyView */);
+        assertThat(mBouncer.isScrimmed()).isFalse();
+    }
+
+    @Test
+    public void testIsShowingScrimmed_false() {
+        doAnswer(invocation -> {
+            assertThat(mBouncer.isScrimmed()).isFalse();
+            return null;
+        }).when(mExpansionCallback).onFullyShown();
         mBouncer.show(false /* resetSecuritySelection */, false /* animate */);
-        assertThat(mBouncer.isShowingScrimmed()).isFalse();
+        assertThat(mBouncer.isScrimmed()).isFalse();
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
index 232c6a2..3b56e45 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
@@ -60,6 +60,8 @@
     @Mock
     private KeyguardStatusView mKeyguardStatusView;
     @Mock
+    private KeyguardBottomAreaView mKeyguardBottomArea;
+    @Mock
     private KeyguardStatusBarView mKeyguardStatusBar;
     private NotificationPanelView mNotificationPanelView;
 
@@ -113,6 +115,7 @@
             mNotificationStackScroller = mNotificationStackScrollLayout;
             mKeyguardStatusView = NotificationPanelViewTest.this.mKeyguardStatusView;
             mKeyguardStatusBar = NotificationPanelViewTest.this.mKeyguardStatusBar;
+            mKeyguardBottomArea = NotificationPanelViewTest.this.mKeyguardBottomArea;
         }
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 539851f..191c983 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -46,7 +46,6 @@
 import com.android.internal.colorextraction.ColorExtractor.GradientColors;
 import com.android.internal.util.function.TriConsumer;
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.doze.DozeLog;
 import com.android.systemui.statusbar.ScrimView;
 import com.android.systemui.util.wakelock.WakeLock;
 import com.android.systemui.utils.os.FakeHandler;
@@ -140,7 +139,6 @@
         assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_FULLY_TRANSPARENT);
 
         // Pulsing notification should conserve AOD wallpaper.
-        mScrimController.setPulseReason(DozeLog.PULSE_REASON_NOTIFICATION);
         mScrimController.transitionTo(ScrimState.PULSING);
         mScrimController.finishAnimationsImmediately();
         assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_FULLY_TRANSPARENT);
@@ -225,14 +223,17 @@
         mScrimController.finishAnimationsImmediately();
         assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_FULLY_OPAQUE);
 
-        mScrimController.setPulseReason(DozeLog.PULSE_REASON_SENSOR_WAKE_LOCK_SCREEN);
         mScrimController.transitionTo(ScrimState.PULSING);
         mScrimController.finishAnimationsImmediately();
         // Front scrim should be transparent
         // Back scrim should be semi-transparent so the user can see the wallpaper
         // Pulse callback should have been invoked
-        assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_SEMI_TRANSPARENT);
+        assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_FULLY_OPAQUE);
         assertScrimTint(mScrimBehind, true /* tinted */);
+
+        mScrimController.setWakeLockScreenSensorActive(true);
+        mScrimController.finishAnimationsImmediately();
+        assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_SEMI_TRANSPARENT);
     }
 
     @Test
@@ -486,7 +487,6 @@
     @Test
     public void testHoldsPulsingWallpaperAnimationLock() {
         // Pre-conditions
-        mScrimController.setPulseReason(DozeLog.PULSE_REASON_NOTIFICATION);
         mScrimController.transitionTo(ScrimState.PULSING);
         mScrimController.finishAnimationsImmediately();
         reset(mWakeLock);
@@ -508,30 +508,6 @@
     }
 
     @Test
-    public void testWillHidePulsingWallpaper_whenNotification() {
-        mScrimController.setWallpaperSupportsAmbientMode(false);
-        mScrimController.transitionTo(ScrimState.AOD);
-        mScrimController.finishAnimationsImmediately();
-        mScrimController.setPulseReason(DozeLog.PULSE_REASON_NOTIFICATION);
-        mScrimController.transitionTo(ScrimState.PULSING);
-        mScrimController.finishAnimationsImmediately();
-        assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_FULLY_OPAQUE);
-        assertScrimTint(mScrimBehind, true);
-    }
-
-    @Test
-    public void testWillHidePulsingWallpaper_whenDocking() {
-        mScrimController.setWallpaperSupportsAmbientMode(false);
-        mScrimController.transitionTo(ScrimState.AOD);
-        mScrimController.finishAnimationsImmediately();
-        mScrimController.setPulseReason(DozeLog.PULSE_REASON_DOCKING);
-        mScrimController.transitionTo(ScrimState.PULSING);
-        mScrimController.finishAnimationsImmediately();
-        assertScrimVisibility(VISIBILITY_FULLY_TRANSPARENT, VISIBILITY_FULLY_OPAQUE);
-        assertScrimTint(mScrimBehind, true);
-    }
-
-    @Test
     public void testConservesExpansionOpacityAfterTransition() {
         mScrimController.transitionTo(ScrimState.UNLOCKED);
         mScrimController.setPanelExpansion(0.5f);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index 1a27765..7d347d5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -120,7 +120,8 @@
 
     @Test
     public void onPanelExpansionChanged_neverHidesScrimmedBouncer() {
-        when(mBouncer.isShowingScrimmed()).thenReturn(true);
+        when(mBouncer.isShowing()).thenReturn(true);
+        when(mBouncer.isScrimmed()).thenReturn(true);
         mStatusBarKeyguardViewManager.onPanelExpansionChanged(0.5f /* expansion */,
                 true /* tracking */);
         verify(mBouncer).setExpansion(eq(KeyguardBouncer.EXPANSION_VISIBLE));
diff --git a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_bluetooth_share_icon.xml b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_bluetooth_share_icon.xml
new file mode 100644
index 0000000..5f7d519
--- /dev/null
+++ b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_bluetooth_share_icon.xml
@@ -0,0 +1,27 @@
+<!--
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:tint="@*android:color/accent_device_default"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M17.12,7.38c0-2.96-2.41-5.38-5.37-5.38H11v7.94L6.03,4.97c-0.29-0.29-0.77-0.29-1.06,0s-0.29,0.77,0,1.06L10.94,12 l-5.97,5.97c-0.29,0.29-0.29,0.77,0,1.06c0.15,0.15,0.34,0.22,0.53,0.22s0.38-0.07,0.53-0.22L11,14.06V22h0.75 c2.96,0,5.37-2.41,5.37-5.38c0-1.97-1.06-3.69-2.64-4.62C16.06,11.06,17.12,9.34,17.12,7.38z M15.62,16.62 c0,1.88-1.34,3.45-3.12,3.8v-7.6C14.28,13.17,15.62,14.75,15.62,16.62z M12.5,11.18v-7.6c1.78,0.35,3.12,1.92,3.12,3.8 S14.28,10.83,12.5,11.18z" />
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_invert_colors.xml b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_invert_colors.xml
deleted file mode 100644
index 59e7838..0000000
--- a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_invert_colors.xml
+++ /dev/null
@@ -1,30 +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.
- */
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24">
-
-    <path
-        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
-    <path
-        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M12.62,2.23A1,1,0,0,0,12,2a1.07,1.07,0,0,0-0.63 0.22 C9.48,3.75,4,8.5,4,14a7.89,7.89,0,0,0,8,8,8,8,0,0,0,8-8C20,8.5,14.5,3.73,12.62,2.23ZM12,21a6.92,6.92,0,0,1-7-7C5,9.16,9.89,4.71,12,3Z" />
-</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_qs_airplane.xml b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_qs_airplane.xml
new file mode 100644
index 0000000..9743ceb
--- /dev/null
+++ b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_qs_airplane.xml
@@ -0,0 +1,26 @@
+<!--
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="18dp"
+    android:height="18dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M22,15.89v-2.57c0-1.1-0.65-2.09-1.67-2.53L14.5,8.28V3.75c0-1.38-1.12-2.5-2.5-2.5s-2.5,1.12-2.5,2.5v4.53l-5.83,2.51 C2.65,11.22,2,12.22,2,13.32v2.57l7.5-1.28v3.03l-1.47,1.17C7.38,19.34,7,20.12,7,20.96v1.33l4.96-0.3L17,22.3v-1.33 c0-0.84-0.38-1.62-1.03-2.15l-1.47-1.17v-3.03L22,15.89z M15.03,19.98c0.23,0.18,0.38,0.44,0.44,0.72l-3.52-0.2l-3.43,0.2 c0.06-0.28,0.21-0.53,0.44-0.72L11,18.36v-5.53l-7.5,1.28v-0.79c0-0.5,0.3-0.95,0.76-1.15L11,9.27V3.75c0-0.55,0.45-1,1-1 s1,0.45,1,1v5.52l6.74,2.9c0.46,0.2,0.76,0.65,0.76,1.15v0.79L13,12.83v5.53L15.03,19.98z" />
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_qs_auto_rotate.xml b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_qs_auto_rotate.xml
new file mode 100644
index 0000000..8dfa4a4
--- /dev/null
+++ b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_qs_auto_rotate.xml
@@ -0,0 +1,29 @@
+<!--
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M2.75,6.5v4.75H7.5c0.41,0,0.75-0.34,0.75-0.75S7.91,9.75,7.5,9.75H5.39l4.5-4.22c0.89-0.84,2.27-0.82,3.13,0.05l4.94,4.95 c0.29,0.29,0.77,0.29,1.06,0c0.29-0.29,0.29-0.77,0-1.06l-4.94-4.95c-1.44-1.44-3.73-1.48-5.22-0.08L4.25,8.77V6.5 c0-0.41-0.34-0.75-0.75-0.75S2.75,6.09,2.75,6.5z" />
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M21.25,17.5v-4.75H16.5c-0.41,0-0.75,0.34-0.75,0.75s0.34,0.75,0.75,0.75h2.11l-4.5,4.22c-0.89,0.84-2.27,0.82-3.13-0.05 l-4.94-4.95c-0.29-0.29-0.77-0.29-1.06,0c-0.29,0.29-0.29,0.77,0,1.06l4.94,4.95c0.74,0.74,1.69,1.11,2.65,1.11 c0.92,0,1.84-0.34,2.57-1.02l4.62-4.33v2.27c0,0.41,0.34,0.75,0.75,0.75S21.25,17.91,21.25,17.5z" />
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_invert_colors.xml b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_qs_bluetooth.xml
similarity index 60%
copy from packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_invert_colors.xml
copy to packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_qs_bluetooth.xml
index 173824b..c12a2eb 100644
--- a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_invert_colors.xml
+++ b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_qs_bluetooth.xml
@@ -21,8 +21,6 @@
     android:viewportHeight="24">
 
     <path
-        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M12.62,2.23A1,1,0,0,0,12,2a1.07,1.07,0,0,0-0.63 0.22 C9.48,3.75,4,8.5,4,14a7.89,7.89,0,0,0,8,8,8,8,0,0,0,8-8C20,8.5,14.5,3.73,12.62,2.23ZM5.5,14c0-4.4,4.32-8.53,6.5-10.33V20.49A6.43,6.43,0,0,1,5.5,14Z" />
+        android:fillColor="@android:color/white"
+        android:pathData="M17.12,7.38c0-2.96-2.41-5.38-5.37-5.38H11v7.94L6.03,4.97c-0.29-0.29-0.77-0.29-1.06,0s-0.29,0.77,0,1.06L10.94,12 l-5.97,5.97c-0.29,0.29-0.29,0.77,0,1.06c0.15,0.15,0.34,0.22,0.53,0.22s0.38-0.07,0.53-0.22L11,14.06V22h0.75 c2.96,0,5.37-2.41,5.37-5.38c0-1.97-1.06-3.69-2.64-4.62C16.06,11.06,17.12,9.34,17.12,7.38z M15.62,16.62 c0,1.88-1.34,3.45-3.12,3.8v-7.6C14.28,13.17,15.62,14.75,15.62,16.62z M12.5,11.18v-7.6c1.78,0.35,3.12,1.92,3.12,3.8 S14.28,10.83,12.5,11.18z" />
 </vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_invert_colors.xml b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_qs_dnd.xml
similarity index 60%
copy from packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_invert_colors.xml
copy to packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_qs_dnd.xml
index 173824b..d364646 100644
--- a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_invert_colors.xml
+++ b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_qs_dnd.xml
@@ -15,14 +15,15 @@
  */
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
+    android:width="17dp"
+    android:height="17dp"
     android:viewportWidth="24"
     android:viewportHeight="24">
 
     <path
-        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+        android:fillColor="@android:color/white"
+        android:pathData="M12,22c5.52,0,10-4.48,10-10c0-5.52-4.48-10-10-10S2,6.48,2,12C2,17.52,6.48,22,12,22z M12,3.5c4.69,0,8.5,3.81,8.5,8.5 c0,4.69-3.81,8.5-8.5,8.5S3.5,16.69,3.5,12C3.5,7.31,7.31,3.5,12,3.5z" />
     <path
-        android:fillColor="#000000"
-        android:pathData="M12.62,2.23A1,1,0,0,0,12,2a1.07,1.07,0,0,0-0.63 0.22 C9.48,3.75,4,8.5,4,14a7.89,7.89,0,0,0,8,8,8,8,0,0,0,8-8C20,8.5,14.5,3.73,12.62,2.23ZM5.5,14c0-4.4,4.32-8.53,6.5-10.33V20.49A6.43,6.43,0,0,1,5.5,14Z" />
+        android:fillColor="@android:color/white"
+        android:pathData="M6.75,12.75h10.5c0.41,0,0.75-0.34,0.75-0.75s-0.34-0.75-0.75-0.75H6.75C6.34,11.25,6,11.59,6,12S6.34,12.75,6.75,12.75z" />
 </vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_signal_flashlight.xml b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_qs_flashlight.xml
similarity index 67%
rename from packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_signal_flashlight.xml
rename to packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_qs_flashlight.xml
index 1526691..cce36e3 100644
--- a/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_signal_flashlight.xml
+++ b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_qs_flashlight.xml
@@ -21,13 +21,9 @@
     android:viewportHeight="24">
 
     <path
-        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+        android:fillColor="@android:color/white"
+        android:pathData="M11,22h2c1.1,0,2-0.9,2-2V10c1.95-1.17,3-3.5,3-6V3H6v1c0,2.5,1.05,4.83,3,6v10C9,21.1,9.9,22,11,22z M16.48,4.5 C16.45,5.03,16.35,5.53,16.2,6H7.8C7.65,5.53,7.55,5.03,7.52,4.5H16.48z M8.51,7.5h6.99c-0.35,0.5-0.77,0.92-1.26,1.21L13.5,9.15 V20c0,0.28-0.22,0.5-0.5,0.5h-2c-0.28,0-0.5-0.22-0.5-0.5V9.15L9.77,8.71C9.28,8.42,8.85,8,8.51,7.5z" />
     <path
-        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M11,22h2a2,2,0,0,0,2-2V10a6.84,6.84,0,0,0,3-6V3H6V4a6.84,6.84,0,0,0,3,6V20A2,2,0,0,0,11,22ZM17,4a8.26,8.26,0,0,1-0.07,1H7.07A8.26,8.26,0,0,1,7,4ZM7.28,6h9.45a5.24,5.24,0,0,1-2.24,3.14L14,9.43V20a1,1,0,0,1-1,1H11a1,1,0,0,1-1-1V9.43l-0.49-0.29A5.25,5.25,0,0,1,7.28,6Z" />
-    <path
-        android:fillColor="#000000"
+        android:fillColor="@android:color/white"
         android:pathData="M 12 13 C 12.5522847498 13 13 13.4477152502 13 14 C 13 14.5522847498 12.5522847498 15 12 15 C 11.4477152502 15 11 14.5522847498 11 14 C 11 13.4477152502 11.4477152502 13 12 13 Z" />
 </vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_invert_colors.xml b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_settings_bluetooth.xml
similarity index 60%
copy from packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_invert_colors.xml
copy to packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_settings_bluetooth.xml
index 173824b..c12a2eb 100644
--- a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_invert_colors.xml
+++ b/packages/overlays/IconPackCircularAndroidOverlay/res/drawable/ic_settings_bluetooth.xml
@@ -21,8 +21,6 @@
     android:viewportHeight="24">
 
     <path
-        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M12.62,2.23A1,1,0,0,0,12,2a1.07,1.07,0,0,0-0.63 0.22 C9.48,3.75,4,8.5,4,14a7.89,7.89,0,0,0,8,8,8,8,0,0,0,8-8C20,8.5,14.5,3.73,12.62,2.23ZM5.5,14c0-4.4,4.32-8.53,6.5-10.33V20.49A6.43,6.43,0,0,1,5.5,14Z" />
+        android:fillColor="@android:color/white"
+        android:pathData="M17.12,7.38c0-2.96-2.41-5.38-5.37-5.38H11v7.94L6.03,4.97c-0.29-0.29-0.77-0.29-1.06,0s-0.29,0.77,0,1.06L10.94,12 l-5.97,5.97c-0.29,0.29-0.29,0.77,0,1.06c0.15,0.15,0.34,0.22,0.53,0.22s0.38-0.07,0.53-0.22L11,14.06V22h0.75 c2.96,0,5.37-2.41,5.37-5.38c0-1.97-1.06-3.69-2.64-4.62C16.06,11.06,17.12,9.34,17.12,7.38z M15.62,16.62 c0,1.88-1.34,3.45-3.12,3.8v-7.6C14.28,13.17,15.62,14.75,15.62,16.62z M12.5,11.18v-7.6c1.78,0.35,3.12,1.92,3.12,3.8 S14.28,10.83,12.5,11.18z" />
 </vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_airplanemode_active.xml b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_airplanemode_active.xml
new file mode 100644
index 0000000..8dbae49
--- /dev/null
+++ b/packages/overlays/IconPackCircularSettingsOverlay/res/drawable/ic_airplanemode_active.xml
@@ -0,0 +1,26 @@
+<!--
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M22,15.89v-2.57c0-1.1-0.65-2.09-1.67-2.53L14.5,8.28V3.75c0-1.38-1.12-2.5-2.5-2.5s-2.5,1.12-2.5,2.5v4.53l-5.83,2.51 C2.65,11.22,2,12.22,2,13.32v2.57l7.5-1.28v3.03l-1.47,1.17C7.38,19.34,7,20.12,7,20.96v1.33l4.96-0.3L17,22.3v-1.33 c0-0.84-0.38-1.62-1.03-2.15l-1.47-1.17v-3.03L22,15.89z M15.03,19.98c0.23,0.18,0.38,0.44,0.44,0.72l-3.52-0.2l-3.43,0.2 c0.06-0.28,0.21-0.53,0.44-0.72L11,18.36v-5.53l-7.5,1.28v-0.79c0-0.5,0.3-0.95,0.76-1.15L11,9.27V3.75c0-0.55,0.45-1,1-1 s1,0.45,1,1v5.52l6.74,2.9c0.46,0.2,0.76,0.65,0.76,1.15v0.79L13,12.83v5.53L15.03,19.98z" />
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_dnd.xml b/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_dnd.xml
deleted file mode 100644
index 3e32b3b..0000000
--- a/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_dnd.xml
+++ /dev/null
@@ -1,33 +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.
- */
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24">
-
-    <path
-        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
-    <path
-        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M12,22A10,10,0,1,0,2,12,10,10,0,0,0,12,22ZM12,3a9,9,0,1,1-9,9A9,9,0,0,1,12,3Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M7,12.5H17a0.5 0.5 ,0,0,0,0-1H7a0.5 0.5 ,0,0,0,0,1Z" />
-</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_lockscreen_ime.xml b/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_lockscreen_ime.xml
deleted file mode 100644
index 04a2c24..0000000
--- a/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_lockscreen_ime.xml
+++ /dev/null
@@ -1,57 +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.
- */
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24">
-
-    <path
-        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
-    <path
-        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M21,21a2,2,0,0,0,2-2V6a2,2,0,0,0-2-2H3A2,2,0,0,0,1,6V19a2,2,0,0,0,2,2ZM2,19V6A1,1,0,0,1,3,5H21a1,1,0,0,1,1,1V19a1,1,0,0,1-1,1H3A1,1,0,0,1,2,19Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M 9.5 8 L 10.5 8 Q 11 8 11 8.5 L 11 9.5 Q 11 10 10.5 10 L 9.5 10 Q 9 10 9 9.5 L 9 8.5 Q 9 8 9.5 8 Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M 5.5 8 L 6.5 8 Q 7 8 7 8.5 L 7 9.5 Q 7 10 6.5 10 L 5.5 10 Q 5 10 5 9.5 L 5 8.5 Q 5 8 5.5 8 Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M 13.5 8 L 14.5 8 Q 15 8 15 8.5 L 15 9.5 Q 15 10 14.5 10 L 13.5 10 Q 13 10 13 9.5 L 13 8.5 Q 13 8 13.5 8 Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M 9.5 12 L 10.5 12 Q 11 12 11 12.5 L 11 13.5 Q 11 14 10.5 14 L 9.5 14 Q 9 14 9 13.5 L 9 12.5 Q 9 12 9.5 12 Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M 5.5 12 L 6.5 12 Q 7 12 7 12.5 L 7 13.5 Q 7 14 6.5 14 L 5.5 14 Q 5 14 5 13.5 L 5 12.5 Q 5 12 5.5 12 Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M 13.5 12 L 14.5 12 Q 15 12 15 12.5 L 15 13.5 Q 15 14 14.5 14 L 13.5 14 Q 13 14 13 13.5 L 13 12.5 Q 13 12 13.5 12 Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M 17.5 8 L 18.5 8 Q 19 8 19 8.5 L 19 9.5 Q 19 10 18.5 10 L 17.5 10 Q 17 10 17 9.5 L 17 8.5 Q 17 8 17.5 8 Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M 17.5 12 L 18.5 12 Q 19 12 19 12.5 L 19 13.5 Q 19 14 18.5 14 L 17.5 14 Q 17 14 17 13.5 L 17 12.5 Q 17 12 17.5 12 Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M8.5,17h7a0.5 0.5 ,0,0,0,0-1h-7a0.5 0.5 ,0,0,0,0,1Z" />
-</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_qs_auto_rotate.xml b/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_qs_auto_rotate.xml
deleted file mode 100644
index f98e2b8..0000000
--- a/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_qs_auto_rotate.xml
+++ /dev/null
@@ -1,33 +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.
- */
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24">
-
-    <path
-        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
-    <path
-        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M3.5,6a0.5 0.5 ,0,0,0-0.5 0.5 V11H7.5a0.5 0.5 ,0,0,0,0-1H4.76l5-4.65a2.49,2.49,0,0,1,3.48 0.05 l4.95,4.95a0.49 0.49 ,0,1,0,0.7-0.7L13.91,4.7A3.47,3.47,0,0,0,9,4.62L4,9.35V6.5A0.5 0.5 ,0,0,0,3.5,6Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M20.5,18a0.5 0.5 ,0,0,0,0.5-0.5V13H16.5a0.5 0.5 ,0,0,0,0,1h2.74l-5,4.65a2.49,2.49,0,0,1-3.48,0l-5-5a0.49 0.49 ,0,0,0-0.7 0.7 l4.94,5a3.47,3.47,0,0,0,4.87 0.08 l5-4.73V17.5A0.5 0.5 ,0,0,0,20.5,18Z" />
-</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_qs_brightness_auto_on.xml b/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_qs_brightness_auto_on.xml
deleted file mode 100644
index fc990d8..0000000
--- a/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_qs_brightness_auto_on.xml
+++ /dev/null
@@ -1,33 +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.
- */
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24">
-
-    <path
-        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
-    <path
-        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M3.41,14.72A2,2,0,0,1,4,16.14V18a2,2,0,0,0,2,2H7.86a2,2,0,0,1,1.42 0.59 l1.31,1.31a2,2,0,0,0,2.82,0l1.31-1.31A2,2,0,0,1,16.14,20H18a2,2,0,0,0,2-2V16.14a2,2,0,0,1,0.59-1.42l1.31-1.31a2,2,0,0,0,0-2.82L20.59,9.28A2,2,0,0,1,20,7.86V6a2,2,0,0,0-2-2H16.14a2,2,0,0,1-1.42-0.59L13.41,2.1a2,2,0,0,0-2.82,0L9.28,3.41A2,2,0,0,1,7.86,4H6A2,2,0,0,0,4,6V7.86a2,2,0,0,1-0.59,1.42L2.1,10.59a2,2,0,0,0,0,2.82Zm-0.6-3.43L4.12,10A3,3,0,0,0,5,7.86V6A1,1,0,0,1,6,5H7.86A3,3,0,0,0,10,4.12l1.31-1.31a1,1,0,0,1,1.42,0L14,4.12A3,3,0,0,0,16.14,5H18a1,1,0,0,1,1,1V7.86A3,3,0,0,0,19.88,10l1.31,1.31a1,1,0,0,1,0,1.42L19.88,14A3,3,0,0,0,19,16.14V18a1,1,0,0,1-1,1H16.14a3,3,0,0,0-2.12 0.88 l-1.31,1.31a1,1,0,0,1-1.42,0L10,19.88A3,3,0,0,0,7.86,19H6a1,1,0,0,1-1-1V16.14A3,3,0,0,0,4.12,14L2.81,12.71a1,1,0,0,1,0-1.42Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M10,14.61h4L14.85,17H17L13.11,7H10.87L7,17H9.15Zm1.92-5.44h0.11l1.29,3.71H10.63Z" />
-</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_qs_cast_on.xml b/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_qs_cast_on.xml
deleted file mode 100644
index d12cf9e..0000000
--- a/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_qs_cast_on.xml
+++ /dev/null
@@ -1,42 +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.
- */
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24">
-
-    <path
-        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
-    <path
-        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M22,17.5V6.5A2.5,2.5,0,0,0,19.5,4H4.5A2.5,2.5,0,0,0,2,6.5v2a0.5 0.5 ,0,0,0,1,0v-2A1.5,1.5,0,0,1,4.5,5h15A1.5,1.5,0,0,1,21,6.5v11A1.5,1.5,0,0,1,19.5,19h-6a0.5 0.5 ,0,0,0,0,1h6A2.5,2.5,0,0,0,22,17.5Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M2.21,19.61A1,1,0,0,0,3,20a1,1,0,0,0,0-2H3a1,1,0,0,0-0.79,1.61Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M2.5,12A7.5,7.5,0,0,1,10,19.5a0.5 0.5 ,0,0,0,1,0A8.51,8.51,0,0,0,2.5,11a0.5 0.5 ,0,0,0,0,1Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M2.5,16A3.5,3.5,0,0,1,6,19.5a0.5 0.5 ,0,0,0,1,0A4.51,4.51,0,0,0,2.5,15a0.5 0.5 ,0,0,0,0,1Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M16.5,15h-3a0.5 0.5 ,0,0,0,0,1h3A1.5,1.5,0,0,0,18,14.5v-5A1.5,1.5,0,0,0,16.5,8H6.5a0.5 0.5 ,0,0,0,0,1h10a0.5 0.5 ,0,0,1,0.5 0.5 v5A0.5 0.5 ,0,0,1,16.5,15Z" />
-</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_settings_16dp.xml b/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_settings_16dp.xml
deleted file mode 100644
index 33d172c..0000000
--- a/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_settings_16dp.xml
+++ /dev/null
@@ -1,33 +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.
- */
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="16dp"
-    android:height="16dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24">
-
-    <path
-        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
-    <path
-        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M5.31,19.26a1.6,1.6,0,0,0,0.53-0.09l1.8-0.7c0.26 0.16 0.52 0.31 0.79 0.45 l0.27,1.84A1.44,1.44,0,0,0,10.15,22h3.7a1.46,1.46,0,0,0,1.46-1.19l0.27-1.87c0.26-0.13 0.52 -0.28 0.78 -0.44l1.8 0.7 a1.47,1.47,0,0,0,0.54 0.1 A1.44,1.44,0,0,0,20,18.58l1.86-3.14a1.4,1.4,0,0,0-0.37-1.81l-1.52-1.17c0-0.14,0-0.29,0-0.45s0-0.3,0-0.44l1.52-1.17a1.41,1.41,0,0,0,0.36-1.83L20,5.47a1.46,1.46,0,0,0-1.29-0.73,1.69,1.69,0,0,0-0.53 0.09 l-1.8 0.7 c-0.26-0.16-0.52-0.31-0.79-0.45l-0.27-1.84A1.44,1.44,0,0,0,13.84,2h-3.7A1.45,1.45,0,0,0,8.7,3.22L8.43,5.08q-0.39 0.21 -0.78 0.45 L5.84,4.82a1.47,1.47,0,0,0-0.54-0.1,1.43,1.43,0,0,0-1.25 0.72 L2.2,8.55a1.37,1.37,0,0,0,0.37,1.83l1.52,1.17c0,0.14,0,0.3,0,0.45s0,0.3,0,0.44L2.56,13.61a1.42,1.42,0,0,0-0.36,1.83L4,18.53A1.46,1.46,0,0,0,5.31,19.26ZM3.16,14.4l1.53-1.16 0.43 -0.33,0-0.53c0-0.13,0-0.25,0-0.38s0-0.26,0-0.39l0-0.53-0.42-0.33L3.17,9.58a0.38 0.38 ,0,0,1-0.11-0.52L4.92,5.93a0.43 0.43 ,0,0,1,0.38-0.21 0.47 0.47,0,0,1,0.17,0l1.81 0.71 0.48 0.19 0.43-0.27A6.39,6.39,0,0,1,8.9,6l0.45-0.24 0.07 -0.5 0.27 -1.88A0.44 0.44 ,0,0,1,10.14,3h3.7a0.44 0.44 ,0,0,1,0.46 0.38 l0.27,1.85 0.08 0.51 0.46 0.24a5.3,5.3,0,0,1,0.7 0.4 l0.43 0.27 0.47-0.19,1.78-0.69a0.63 0.63 ,0,0,1,0.19,0,0.47 0.47 ,0,0,1,0.43 0.24 l1.83,3.08a0.42 0.42 ,0,0,1-0.1 0.55 l-1.52,1.16-0.42 0.33 ,0,0.53c0,0.13,0,0.25,0,0.38s0,0.26,0,0.39l0,0.53 0.42 0.33,1.51,1.15a0.42 0.42 ,0,0,1,0.13 0.52 l-1.87,3.16a0.43 0.43 ,0,0,1-0.39 0.21 0.57 0.57 ,0,0,1-0.18,0l-1.8-0.71-0.47-0.18-0.43 0.27 a7.46,7.46,0,0,1-0.71 0.41 l-0.45 0.24 -0.07 0.5 -0.27,1.86a0.47 0.47 ,0,0,1-0.47 0.34 h-3.7a0.44 0.44 ,0,0,1-0.46-0.38l-0.27-1.85-0.08-0.51L8.88,18a5.3,5.3,0,0,1-0.7-0.4l-0.43-0.27-0.47 0.19 -1.78 0.69 a0.58 0.58 ,0,0,1-0.19,0A0.48 0.48 ,0,0,1,4.89,18L3.08,15A0.42 0.42 ,0,0,1,3.16,14.4Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M12,15.91A3.92,3.92,0,1,0,8,12,4,4,0,0,0,12,15.91Zm0-6.83A2.92,2.92,0,1,1,9,12,3,3,0,0,1,12,9.08Z" />
-</vector>
diff --git a/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_signal_airplane.xml b/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_signal_airplane.xml
deleted file mode 100644
index a5ef380..0000000
--- a/packages/overlays/IconPackCircularSystemUIOverlay/res/drawable/ic_signal_airplane.xml
+++ /dev/null
@@ -1,30 +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.
- */
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24">
-
-    <path
-        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
-    <path
-        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M2.8,15l7.2-0.73v3.49L8,19.38a1.52,1.52,0,0,0-0.54,1.16v1a0.52 0.52 ,0,0,0,0.17 0.38 0.51 0.51 ,0,0,0,0.39 0.12 L12,21.5l3.94 0.5 H16a0.5 0.5 ,0,0,0,0.33-0.12 0.52 0.52,0,0,0,0.17-0.38v-1A1.52,1.52,0,0,0,16,19.38l-2-1.62V14.27l7.2 0.73 a0.51 0.51 ,0,0,0,0.55-0.5,3.49,3.49,0,0,0-2.15-3.23L14,8.94V3.5a2,2,0,0,0-4,0V8.94L4.4,11.27A3.49,3.49,0,0,0,2.25,14.5a0.51 0.51 ,0,0,0,0.55 0.5 Zm2-2.81,5.9-2.45A0.5 0.5 ,0,0,0,11,9.28V3.5a1,1,0,0,1,2,0V9.28a0.5 0.5 ,0,0,0,0.31 0.46 l5.9,2.45a2.51,2.51,0,0,1,1.48,1.75l-7.14-0.72a0.52 0.52 ,0,0,0-0.38 0.13 0.5 0.5 ,0,0,0-0.17 0.37 V18a0.53 0.53 ,0,0,0,0.18 0.39 l2.14,1.76a0.53 0.53 ,0,0,1,0.18 0.39 v0.39l-3.44-0.43h-0.12l-3.44 0.43 v-0.39a0.53 0.53 ,0,0,1,0.18-0.39l2.14-1.76A0.53 0.53 ,0,0,0,11,18V13.72a0.5 0.5 ,0,0,0-0.17-0.37 0.52 0.52,0,0,0-0.38-0.13l-7.14 0.72 A2.51,2.51,0,0,1,4.79,12.19Z" />
-</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_bluetooth_share_icon.xml b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_bluetooth_share_icon.xml
new file mode 100644
index 0000000..c5c3f06
--- /dev/null
+++ b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_bluetooth_share_icon.xml
@@ -0,0 +1,27 @@
+<!--
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:tint="@*android:color/accent_device_default"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M17.21,6.79l-4.5-4.5c-0.29-0.29-0.72-0.37-1.09-0.22C11.25,2.23,11,2.6,11,3v6.59l-3.8-3.8c-0.39-0.39-1.02-0.39-1.41,0 c-0.39,0.39-0.39,1.02,0,1.41l4.8,4.8l-4.8,4.8c-0.39,0.39-0.39,1.02,0,1.41c0.39,0.39,1.02,0.39,1.41,0l3.8-3.8V21 c0,0.4,0.24,0.77,0.62,0.92C11.74,21.98,11.87,22,12,22c0.26,0,0.52-0.1,0.71-0.29l4.5-4.5c0.39-0.39,0.39-1.02,0-1.41L13.42,12 l3.79-3.79C17.6,7.82,17.6,7.18,17.21,6.79z M15.09,16.5L13,18.58v-4.17L15.09,16.5z M13,9.58V5.42l2.08,2.08L13,9.58z" />
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_qs_airplane.xml b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_qs_airplane.xml
new file mode 100644
index 0000000..85260c0
--- /dev/null
+++ b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_qs_airplane.xml
@@ -0,0 +1,26 @@
+<!--
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="18dp"
+    android:height="18dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M2.65,15.8L10,13.5V19l-1.6,1.2C8.15,20.39,8,20.69,8,21v0.67c0,0.17,0.14,0.28,0.31,0.24c1.94-0.55,1.3-0.37,3.19-0.91 c1.21,0.35,1.99,0.57,3.19,0.91c0.17,0.04,0.31-0.07,0.31-0.24V21c0-0.31-0.15-0.61-0.4-0.8L13,19v-5.5l7.35,2.3 c0.32,0.1,0.65-0.14,0.65-0.48v-0.49c0-0.52-0.27-1-0.7-1.27L13,9V3.5C13,2.67,12.33,2,11.5,2S10,2.67,10,3.5V9l-7.3,4.56 C2.27,13.83,2,14.31,2,14.83v0.49C2,15.66,2.33,15.9,2.65,15.8z" />
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_qs_auto_rotate.xml b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_qs_auto_rotate.xml
similarity index 60%
rename from packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_qs_auto_rotate.xml
rename to packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_qs_auto_rotate.xml
index f823812..bcdb618 100644
--- a/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_qs_auto_rotate.xml
+++ b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_qs_auto_rotate.xml
@@ -21,11 +21,9 @@
     android:viewportHeight="24">
 
     <path
-        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+        android:fillColor="@android:color/white"
+        android:pathData="M16.41,10.96h2.83l-8.18-8.18c-0.62-0.62-1.65-0.6-2.29,0.04L4.27,7.31L2.85,5.89C2.54,5.58,2,5.8,2,6.25v4.25 C2,10.78,2.22,11,2.5,11h4.25c0.45,0,0.67-0.54,0.35-0.85L5.69,8.73l4.24-4.24L16.41,10.96z" />
     <path
-        android:fillColor="#000000"
-        android:pathData="M16.41,11h2.83L11.05,2.78a1.62,1.62,0,0,0-2.29,0L4.27,7.31,2.85,5.89A0.5 0.5 ,0,0,0,2,6.25V10.5a0.5 0.5 ,0,0,0,0.5 0.5 H6.75a0.5 0.5 ,0,0,0,0.36-0.85L5.69,8.73,9.93,4.49Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M22,13.51a0.5 0.5 ,0,0,0-0.5-0.5H17.25a0.5 0.5 ,0,0,0-0.36 0.85 l1.35,1.35-4.31,4.31L7.44,13H4.61l8.19,8.18a1.62,1.62,0,0,0,2.29,0l4.57-4.55,1.49,1.49a0.5 0.5 ,0,0,0,0.85-0.36Z" />
+        android:fillColor="@android:color/white"
+        android:pathData="M22,13.51c0-0.28-0.22-0.5-0.5-0.5h-4.25c-0.45,0-0.67,0.54-0.35,0.85l1.34,1.34l-4.31,4.31l-6.48-6.48H4.61l8.19,8.19 c0.62,0.62,1.65,0.6,2.29-0.04l4.57-4.55l1.49,1.49c0.32,0.31,0.85,0.09,0.85-0.35V13.51z" />
 </vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_invert_colors.xml b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_qs_bluetooth.xml
similarity index 60%
copy from packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_invert_colors.xml
copy to packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_qs_bluetooth.xml
index 173824b..cf7cab5 100644
--- a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_invert_colors.xml
+++ b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_qs_bluetooth.xml
@@ -21,8 +21,6 @@
     android:viewportHeight="24">
 
     <path
-        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M12.62,2.23A1,1,0,0,0,12,2a1.07,1.07,0,0,0-0.63 0.22 C9.48,3.75,4,8.5,4,14a7.89,7.89,0,0,0,8,8,8,8,0,0,0,8-8C20,8.5,14.5,3.73,12.62,2.23ZM5.5,14c0-4.4,4.32-8.53,6.5-10.33V20.49A6.43,6.43,0,0,1,5.5,14Z" />
+        android:fillColor="@android:color/white"
+        android:pathData="M17.21,6.79l-4.5-4.5c-0.29-0.29-0.72-0.37-1.09-0.22C11.25,2.23,11,2.6,11,3v6.59l-3.8-3.8c-0.39-0.39-1.02-0.39-1.41,0 c-0.39,0.39-0.39,1.02,0,1.41l4.8,4.8l-4.8,4.8c-0.39,0.39-0.39,1.02,0,1.41c0.39,0.39,1.02,0.39,1.41,0l3.8-3.8V21 c0,0.4,0.24,0.77,0.62,0.92C11.74,21.98,11.87,22,12,22c0.26,0,0.52-0.1,0.71-0.29l4.5-4.5c0.39-0.39,0.39-1.02,0-1.41L13.42,12 l3.79-3.79C17.6,7.82,17.6,7.18,17.21,6.79z M15.09,16.5L13,18.58v-4.17L15.09,16.5z M13,9.58V5.42l2.08,2.08L13,9.58z" />
 </vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_dnd.xml b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_qs_dnd.xml
similarity index 72%
rename from packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_dnd.xml
rename to packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_qs_dnd.xml
index e6086f3..a094698 100644
--- a/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_dnd.xml
+++ b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_qs_dnd.xml
@@ -15,14 +15,12 @@
  */
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
+    android:width="17dp"
+    android:height="17dp"
     android:viewportWidth="24"
     android:viewportHeight="24">
 
     <path
-        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M12,22A10,10,0,1,0,2,12,10,10,0,0,0,12,22ZM8,11h8a1,1,0,0,1,0,2H8a1,1,0,0,1,0-2Z" />
+        android:fillColor="@android:color/white"
+        android:pathData="M12,22c5.52,0,10-4.48,10-10c0-5.52-4.48-10-10-10S2,6.48,2,12C2,17.52,6.48,22,12,22z M8,11h8c0.55,0,1,0.45,1,1 s-0.45,1-1,1H8c-0.55,0-1-0.45-1-1S7.45,11,8,11z" />
 </vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_invert_colors.xml b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_qs_flashlight.xml
similarity index 68%
rename from packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_invert_colors.xml
rename to packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_qs_flashlight.xml
index 173824b..4427305 100644
--- a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_invert_colors.xml
+++ b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_qs_flashlight.xml
@@ -21,8 +21,9 @@
     android:viewportHeight="24">
 
     <path
-        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+        android:fillColor="@android:color/white"
+        android:pathData="M10,22h4c0.55,0,1-0.45,1-1V10c1.1,0,2-0.9,2-2V5.5H7V8c0,1.1,0.9,2,2,2v11C9,21.55,9.45,22,10,22z M11,12 c0-0.55,0.45-1,1-1s1,0.45,1,1v2c0,0.55-0.45,1-1,1s-1-0.45-1-1V12z" />
     <path
-        android:fillColor="#000000"
-        android:pathData="M12.62,2.23A1,1,0,0,0,12,2a1.07,1.07,0,0,0-0.63 0.22 C9.48,3.75,4,8.5,4,14a7.89,7.89,0,0,0,8,8,8,8,0,0,0,8-8C20,8.5,14.5,3.73,12.62,2.23ZM5.5,14c0-4.4,4.32-8.53,6.5-10.33V20.49A6.43,6.43,0,0,1,5.5,14Z" />
+        android:fillColor="@android:color/white"
+        android:pathData="M17,3c0-0.55-0.45-1-1-1H8C7.45,2,7,2.45,7,3v0.96h10V3z" />
 </vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_invert_colors.xml b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_settings_bluetooth.xml
similarity index 60%
rename from packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_invert_colors.xml
rename to packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_settings_bluetooth.xml
index 0564c73..cf7cab5 100644
--- a/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_invert_colors.xml
+++ b/packages/overlays/IconPackFilledAndroidOverlay/res/drawable/ic_settings_bluetooth.xml
@@ -21,8 +21,6 @@
     android:viewportHeight="24">
 
     <path
-        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M17.44,7.71,12.7,3a1,1,0,0,0-1.41,0h0L6.56,7.71a8.21,8.21,0,0,0-0.62,11.1,8,8,0,0,0,12.12,0A8.21,8.21,0,0,0,17.44,7.71ZM12,19.59A6,6,0,0,1,7.76,9.35L12,5.1Z" />
+        android:fillColor="@android:color/white"
+        android:pathData="M17.21,6.79l-4.5-4.5c-0.29-0.29-0.72-0.37-1.09-0.22C11.25,2.23,11,2.6,11,3v6.59l-3.8-3.8c-0.39-0.39-1.02-0.39-1.41,0 c-0.39,0.39-0.39,1.02,0,1.41l4.8,4.8l-4.8,4.8c-0.39,0.39-0.39,1.02,0,1.41c0.39,0.39,1.02,0.39,1.41,0l3.8-3.8V21 c0,0.4,0.24,0.77,0.62,0.92C11.74,21.98,11.87,22,12,22c0.26,0,0.52-0.1,0.71-0.29l4.5-4.5c0.39-0.39,0.39-1.02,0-1.41L13.42,12 l3.79-3.79C17.6,7.82,17.6,7.18,17.21,6.79z M15.09,16.5L13,18.58v-4.17L15.09,16.5z M13,9.58V5.42l2.08,2.08L13,9.58z" />
 </vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_invert_colors.xml b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_airplanemode_active.xml
similarity index 62%
copy from packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_invert_colors.xml
copy to packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_airplanemode_active.xml
index 173824b..bddc57e 100644
--- a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_invert_colors.xml
+++ b/packages/overlays/IconPackFilledSettingsOverlay/res/drawable/ic_airplanemode_active.xml
@@ -21,8 +21,6 @@
     android:viewportHeight="24">
 
     <path
-        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M12.62,2.23A1,1,0,0,0,12,2a1.07,1.07,0,0,0-0.63 0.22 C9.48,3.75,4,8.5,4,14a7.89,7.89,0,0,0,8,8,8,8,0,0,0,8-8C20,8.5,14.5,3.73,12.62,2.23ZM5.5,14c0-4.4,4.32-8.53,6.5-10.33V20.49A6.43,6.43,0,0,1,5.5,14Z" />
+        android:fillColor="@android:color/white"
+        android:pathData="M2.65,15.8L10,13.5V19l-1.6,1.2C8.15,20.39,8,20.69,8,21v0.67c0,0.17,0.14,0.28,0.31,0.24c1.94-0.55,1.3-0.37,3.19-0.91 c1.21,0.35,1.99,0.57,3.19,0.91c0.17,0.04,0.31-0.07,0.31-0.24V21c0-0.31-0.15-0.61-0.4-0.8L13,19v-5.5l7.35,2.3 c0.32,0.1,0.65-0.14,0.65-0.48v-0.49c0-0.52-0.27-1-0.7-1.27L13,9V3.5C13,2.67,12.33,2,11.5,2S10,2.67,10,3.5V9l-7.3,4.56 C2.27,13.83,2,14.31,2,14.83v0.49C2,15.66,2.33,15.9,2.65,15.8z" />
 </vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_lockscreen_ime.xml b/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_lockscreen_ime.xml
deleted file mode 100644
index 8b9f562..0000000
--- a/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_lockscreen_ime.xml
+++ /dev/null
@@ -1,55 +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.
- */
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24">
-
-    <path
-        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M3,21H21a2,2,0,0,0,2-2V6a2,2,0,0,0-2-2H3A2,2,0,0,0,1,6V19A2,2,0,0,0,3,21ZM3,6H21V19H3Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M 9 8 H 11 V 10 H 9 V 8 Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M 5 8 H 7 V 10 H 5 V 8 Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M 8 16 H 16 V 17 H 8 V 16 Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M 13 8 H 15 V 10 H 13 V 8 Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M 9 12 H 11 V 14 H 9 V 12 Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M 5 12 H 7 V 14 H 5 V 12 Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M 13 12 H 15 V 14 H 13 V 12 Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M 17 8 H 19 V 10 H 17 V 8 Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M 17 12 H 19 V 14 H 17 V 12 Z" />
-</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_qs_brightness_auto_on.xml b/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_qs_brightness_auto_on.xml
deleted file mode 100644
index f3b1c01..0000000
--- a/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_qs_brightness_auto_on.xml
+++ /dev/null
@@ -1,31 +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.
- */
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24">
-
-    <path
-        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M10,14.61h4L14.85,17H17L13.11,7H10.87L7,17H9.15Zm1.54-4.24 0.38 -1.2h0.11l0.38,1.2 0.91 ,2.51H10.63Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M4,20H8.69L12,23.31,15.31,20H20V15.31L23.31,12,20,8.69V4H15.31L12,0.69,8.69,4H4V8.69L0.69,12,4,15.31Zm-0.48-8L6,9.52V6H9.52L12,3.52,14.48,6H18V9.52L20.48,12,18,14.48V18H14.48L12,20.48,9.52,18H6V14.48Z" />
-</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_qs_cast_on.xml b/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_qs_cast_on.xml
deleted file mode 100644
index 0fd763b..0000000
--- a/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_qs_cast_on.xml
+++ /dev/null
@@ -1,40 +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.
- */
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24">
-
-    <path
-        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M1.82,16.08a5,5,0,0,1,4.1,4.08,1,1,0,0,0,1,0.84,1,1,0,0,0,1-1.14,7,7,0,0,0-5.8-5.78,1,1,0,0,0-0.29,2Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M19,7H5V8.63A13,13,0,0,1,13.37,17H19Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M3,5H21V19H14v2h7a2,2,0,0,0,2-2V5a2,2,0,0,0-2-2H3A2,2,0,0,0,1,5V8H3Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M1.85,12A9.06,9.06,0,0,1,10,20.12a1,1,0,0,0,1,0.88,1,1,0,0,0,1-1.1,11,11,0,0,0-9.87-9.85A1,1,0,0,0,1,11,1,1,0,0,0,1.85,12Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M2,21H4a3,3,0,0,0-3-3v2A1,1,0,0,0,2,21Z" />
-</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_settings_16dp.xml b/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_settings_16dp.xml
deleted file mode 100644
index d292b13..0000000
--- a/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_settings_16dp.xml
+++ /dev/null
@@ -1,28 +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.
- */
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="16dp"
-    android:height="16dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24">
-
-    <path
-        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M21.64,8.39,20,5.63a1.12,1.12,0,0,0-1.36-0.5L16.54,6A7.26,7.26,0,0,0,15,5.12l-0.27-2.2A1.1,1.1,0,0,0,13.59,2H10.41a1.1,1.1,0,0,0-1.11 0.92 L9,5.11A7.1,7.1,0,0,0,7.46,6L5.32,5.12A1.12,1.12,0,0,0,4,5.62L2.36,8.38A1.1,1.1,0,0,0,2.6,9.8l1.94,1.45a6.06,6.06,0,0,0,0,0.75,6.34,6.34,0,0,0,0,0.76L2.6,14.2a1.09,1.09,0,0,0-0.24,1.41L4,18.37a1.12,1.12,0,0,0,1.36 0.5 L7.46,18A7.26,7.26,0,0,0,9,18.88l0.27,2.19a1.1,1.1,0,0,0,1.11 0.93 h3.18a1.11,1.11,0,0,0,1.11-0.92L15,18.89A7.26,7.26,0,0,0,16.54,18l2.14 0.91 a1.12,1.12,0,0,0,1.36-0.5l1.6-2.76a1.1,1.1,0,0,0-0.24-1.42l-1.94-1.45a7.24,7.24,0,0,0,0-1.52L21.4,9.8A1.09,1.09,0,0,0,21.64,8.39ZM12,15.5A3.5,3.5,0,1,1,15.5,12,3.5,3.5,0,0,1,12,15.5Z" />
-</vector>
diff --git a/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_signal_airplane.xml b/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_signal_airplane.xml
deleted file mode 100644
index 999a9bf..0000000
--- a/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_signal_airplane.xml
+++ /dev/null
@@ -1,28 +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.
- */
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24">
-
-    <path
-        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M3.15,15.8l7.35-2.3V19L8.9,20.2a1,1,0,0,0-0.4 0.8 v0.67a0.24 0.24 ,0,0,0,0.31 0.24 L12,21l3.19 0.91 a0.24 0.24 ,0,0,0,0.31-0.24V21a1,1,0,0,0-0.4-0.8L13.5,19V13.5l7.35,2.3a0.5 0.5 ,0,0,0,0.65-0.48v-0.49a1.5,1.5,0,0,0-0.7-1.27L13.5,9V3.5a1.5,1.5,0,0,0-3,0V9L3.2,13.56a1.5,1.5,0,0,0-0.7,1.27v0.49A0.5 0.5 ,0,0,0,3.15,15.8Z" />
-</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_signal_flashlight.xml b/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_signal_flashlight.xml
deleted file mode 100644
index 1ffb32b..0000000
--- a/packages/overlays/IconPackFilledSystemUIOverlay/res/drawable/ic_signal_flashlight.xml
+++ /dev/null
@@ -1,31 +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.
- */
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24">
-
-    <path
-        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M10,22h4a1,1,0,0,0,1-1V10a2,2,0,0,0,2-2V5.5H7V8a2,2,0,0,0,2,2V21A1,1,0,0,0,10,22Zm2-10a1.5,1.5,0,1,1-1.5,1.5A1.5,1.5,0,0,1,12,12Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M17,3a1,1,0,0,0-1-1H8A1,1,0,0,0,7,3V4H17Z" />
-</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_bluetooth_share_icon.xml b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_bluetooth_share_icon.xml
new file mode 100644
index 0000000..bd06e7c
--- /dev/null
+++ b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_bluetooth_share_icon.xml
@@ -0,0 +1,27 @@
+<!--
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:tint="@*android:color/accent_device_default"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M17.53,6.72l-4.75-4.75c-0.21-0.21-0.54-0.28-0.82-0.16C11.68,1.92,11.5,2.2,11.5,2.5v7.69L7.53,6.22 c-0.29-0.29-0.77-0.29-1.06,0s-0.29,0.77,0,1.06L11.19,12l-4.72,4.72c-0.29,0.29-0.29,0.77,0,1.06s0.77,0.29,1.06,0l3.97-3.97v7.69 c0,0.3,0.18,0.58,0.46,0.69c0.09,0.04,0.19,0.06,0.29,0.06c0.2,0,0.39-0.08,0.53-0.22l4.75-4.75c0.29-0.29,0.29-0.77,0-1.06 L13.31,12l4.22-4.22C17.82,7.49,17.82,7.01,17.53,6.72z M15.94,16.75L13,19.69v-5.88L15.94,16.75z M13,10.19V4.31l2.94,2.94 L13,10.19z" />
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_qs_airplane.xml b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_qs_airplane.xml
new file mode 100644
index 0000000..5f9bdd2
--- /dev/null
+++ b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_qs_airplane.xml
@@ -0,0 +1,26 @@
+<!--
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="18dp"
+    android:height="18dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M2.52,16.17c0.32,0.23,0.74,0.31,1.11,0.19l5.87-1.84v3.87L8,19.52c-0.31,0.24-0.5,0.61-0.5,1v0.75 c0,0.69,0.56,1.25,1.25,1.25h6.5c0.69,0,1.25-0.56,1.25-1.25v-0.75c0-0.39-0.19-0.76-0.5-1l-1.5-1.12v-3.87l5.88,1.84 c0.38,0.12,0.79,0.05,1.11-0.19c0.32-0.23,0.51-0.61,0.51-1.01l0-1.84c0-0.63-0.34-1.21-0.89-1.52L14.5,8.06V4 c0-1.38-1.12-2.5-2.5-2.5S9.5,2.62,9.5,4v4.07L2.89,11.8C2.35,12.11,2,12.7,2,13.33l0,1.83C2.01,15.56,2.2,15.94,2.52,16.17z M3.63,13.11L11,8.94V4c0-0.55,0.45-1,1-1s1,0.45,1,1v4.94l7.37,4.17c0.08,0.04,0.13,0.13,0.13,0.22l0,1.5L13,12.48v6.66l2,1.5 v0.38H9v-0.38l2-1.5v-6.66l-7.5,2.34l0-1.49C3.5,13.24,3.55,13.15,3.63,13.11z" />
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_qs_auto_rotate.xml b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_qs_auto_rotate.xml
new file mode 100644
index 0000000..0f9effd
--- /dev/null
+++ b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_qs_auto_rotate.xml
@@ -0,0 +1,29 @@
+<!--
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M3.5,7C3.09,7,2.75,7.34,2.75,7.75v2.73c0,0.41,0.34,0.75,0.75,0.75h2.75c0.41,0,0.75-0.34,0.75-0.75S6.66,9.73,6.25,9.73 H5.33l5.42-5.42l6.47,6.47c0.15,0.15,0.34,0.22,0.53,0.22s0.38-0.07,0.53-0.22c0.29-0.29,0.29-0.77,0-1.06l-7-7 c-0.29-0.29-0.77-0.29-1.06,0L4.25,8.69V7.75C4.25,7.34,3.91,7,3.5,7z" />
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M20.5,17c0.41,0,0.75-0.34,0.75-0.75V13.5c0-0.41-0.34-0.75-0.75-0.75h-2.75c-0.41,0-0.75,0.34-0.75,0.75 s0.34,0.75,0.75,0.75h0.94l-5.44,5.44l-6.47-6.47c-0.29-0.29-0.77-0.29-1.06,0s-0.29,0.77,0,1.06l7,7 c0.15,0.15,0.34,0.22,0.53,0.22s0.38-0.07,0.53-0.22l5.97-5.97v0.94C19.75,16.66,20.09,17,20.5,17z" />
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_qs_bluetooth.xml b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_qs_bluetooth.xml
new file mode 100644
index 0000000..d2eb2d3
--- /dev/null
+++ b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_qs_bluetooth.xml
@@ -0,0 +1,26 @@
+<!--
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M17.53,6.72l-4.75-4.75c-0.21-0.21-0.54-0.28-0.82-0.16C11.68,1.92,11.5,2.2,11.5,2.5v7.69L7.53,6.22 c-0.29-0.29-0.77-0.29-1.06,0s-0.29,0.77,0,1.06L11.19,12l-4.72,4.72c-0.29,0.29-0.29,0.77,0,1.06s0.77,0.29,1.06,0l3.97-3.97v7.69 c0,0.3,0.18,0.58,0.46,0.69c0.09,0.04,0.19,0.06,0.29,0.06c0.2,0,0.39-0.08,0.53-0.22l4.75-4.75c0.29-0.29,0.29-0.77,0-1.06 L13.31,12l4.22-4.22C17.82,7.49,17.82,7.01,17.53,6.72z M15.94,16.75L13,19.69v-5.88L15.94,16.75z M13,10.19V4.31l2.94,2.94 L13,10.19z" />
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_qs_dnd.xml b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_qs_dnd.xml
new file mode 100644
index 0000000..77a84ba
--- /dev/null
+++ b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_qs_dnd.xml
@@ -0,0 +1,29 @@
+<!--
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="17dp"
+    android:height="17dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M16.25,11.25h-8.5C7.34,11.25,7,11.59,7,12s0.34,0.75,0.75,0.75h8.5c0.41,0,0.75-0.34,0.75-0.75S16.66,11.25,16.25,11.25z" />
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M12,2C6.49,2,2,6.49,2,12s4.49,10,10,10c0,0,0.01,0,0.01,0c5.5,0,9.98-4.47,9.99-9.98V12C22,6.49,17.51,2,12,2z M20.5,12.02c0,4.68-3.81,8.48-8.49,8.48c0,0-0.01,0-0.01,0c-4.69,0-8.5-3.81-8.5-8.5S7.31,3.5,12,3.5s8.5,3.81,8.5,8.5V12.02z" />
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_signal_flashlight.xml b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_qs_flashlight.xml
similarity index 68%
rename from packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_signal_flashlight.xml
rename to packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_qs_flashlight.xml
index 3bde46f..9168c20 100644
--- a/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_signal_flashlight.xml
+++ b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_qs_flashlight.xml
@@ -21,11 +21,9 @@
     android:viewportHeight="24">
 
     <path
-        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
+        android:fillColor="@android:color/white"
+        android:pathData="M17,2H7C6.59,2,6.25,2.34,6.25,2.75v5c0,0.14,0.04,0.27,0.11,0.39l1.89,3.07v10.04C8.25,21.66,8.59,22,9,22h6 c0.41,0,0.75-0.34,0.75-0.75v-9.79l1.89-3.07c0.07-0.12,0.11-0.25,0.11-0.39V2.75C17.75,2.34,17.41,2,17,2z M16.25,7.79 l-1.89,3.07c-0.07,0.12-0.11,0.25-0.11,0.39v9.25h-4.5V11c0-0.14-0.04-0.27-0.11-0.39L7.75,7.54V6.5h8.5V7.79z M16.25,5h-8.5V3.5 h8.5V5z" />
     <path
-        android:fillColor="#000000"
-        android:pathData="M9,22h6a0.76 0.76 ,0,0,0,0.75-0.75V11.46l1.89-3.07A0.77 0.77 ,0,0,0,17.75,8V2.75A0.76 0.76 ,0,0,0,17,2H7a0.76 0.76 ,0,0,0-0.75 0.75 v5a0.77 0.77 ,0,0,0,0.11 0.39 l1.89,3.07v10A0.76 0.76 ,0,0,0,9,22ZM16.25,3.5V5H7.75V3.5Zm-8.5,4v-1h8.5V7.79l-1.89,3.07a0.77 0.77 ,0,0,0-0.11 0.39 V20.5H9.75V11a0.77 0.77 ,0,0,0-0.11-0.39Z" />
-    <path
-        android:fillColor="#000000"
+        android:fillColor="@android:color/white"
         android:pathData="M 12 12.75 C 12.6903559373 12.75 13.25 13.3096440627 13.25 14 C 13.25 14.6903559373 12.6903559373 15.25 12 15.25 C 11.3096440627 15.25 10.75 14.6903559373 10.75 14 C 10.75 13.3096440627 11.3096440627 12.75 12 12.75 Z" />
 </vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_settings_bluetooth.xml b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_settings_bluetooth.xml
new file mode 100644
index 0000000..d2eb2d3
--- /dev/null
+++ b/packages/overlays/IconPackRoundedAndroidOverlay/res/drawable/ic_settings_bluetooth.xml
@@ -0,0 +1,26 @@
+<!--
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M17.53,6.72l-4.75-4.75c-0.21-0.21-0.54-0.28-0.82-0.16C11.68,1.92,11.5,2.2,11.5,2.5v7.69L7.53,6.22 c-0.29-0.29-0.77-0.29-1.06,0s-0.29,0.77,0,1.06L11.19,12l-4.72,4.72c-0.29,0.29-0.29,0.77,0,1.06s0.77,0.29,1.06,0l3.97-3.97v7.69 c0,0.3,0.18,0.58,0.46,0.69c0.09,0.04,0.19,0.06,0.29,0.06c0.2,0,0.39-0.08,0.53-0.22l4.75-4.75c0.29-0.29,0.29-0.77,0-1.06 L13.31,12l4.22-4.22C17.82,7.49,17.82,7.01,17.53,6.72z M15.94,16.75L13,19.69v-5.88L15.94,16.75z M13,10.19V4.31l2.94,2.94 L13,10.19z" />
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_airplanemode_active.xml b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_airplanemode_active.xml
new file mode 100644
index 0000000..e884edb
--- /dev/null
+++ b/packages/overlays/IconPackRoundedSettingsOverlay/res/drawable/ic_airplanemode_active.xml
@@ -0,0 +1,26 @@
+<!--
+/**
+ * Copyright (c) 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ * * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M2.52,16.17c0.32,0.23,0.74,0.31,1.11,0.19l5.87-1.84v3.87L8,19.52c-0.31,0.24-0.5,0.61-0.5,1v0.75 c0,0.69,0.56,1.25,1.25,1.25h6.5c0.69,0,1.25-0.56,1.25-1.25v-0.75c0-0.39-0.19-0.76-0.5-1l-1.5-1.12v-3.87l5.88,1.84 c0.38,0.12,0.79,0.05,1.11-0.19c0.32-0.23,0.51-0.61,0.51-1.01l0-1.84c0-0.63-0.34-1.21-0.89-1.52L14.5,8.06V4 c0-1.38-1.12-2.5-2.5-2.5S9.5,2.62,9.5,4v4.07L2.89,11.8C2.35,12.11,2,12.7,2,13.33l0,1.83C2.01,15.56,2.2,15.94,2.52,16.17z M3.63,13.11L11,8.94V4c0-0.55,0.45-1,1-1s1,0.45,1,1v4.94l7.37,4.17c0.08,0.04,0.13,0.13,0.13,0.22l0,1.5L13,12.48v6.66l2,1.5 v0.38H9v-0.38l2-1.5v-6.66l-7.5,2.34l0-1.49C3.5,13.24,3.55,13.15,3.63,13.11z" />
+</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_dnd.xml b/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_dnd.xml
deleted file mode 100644
index a9a32ee..0000000
--- a/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_dnd.xml
+++ /dev/null
@@ -1,31 +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.
- */
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24">
-
-    <path
-        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M7.25,12.75h9.5a0.75 0.75 ,0,0,0,0-1.5H7.25a0.75 0.75 ,0,0,0,0,1.5Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M12,22h0A10,10,0,0,0,22,12v0A10,10,0,1,0,12,22ZM12,3.5A8.51,8.51,0,0,1,20.5,12h0.75l-0.75,0A8.49,8.49,0,0,1,12,20.5h0a8.5,8.5,0,0,1,0-17Z" />
-</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_lockscreen_ime.xml b/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_lockscreen_ime.xml
deleted file mode 100644
index 7897fa3a..0000000
--- a/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_lockscreen_ime.xml
+++ /dev/null
@@ -1,55 +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.
- */
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24">
-
-    <path
-        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M3,21H21a2,2,0,0,0,2-2V6a2,2,0,0,0-2-2H3A2,2,0,0,0,1,6V19A2,2,0,0,0,3,21ZM2.5,6A0.51 0.51 ,0,0,1,3,5.5H21a0.51 0.51 ,0,0,1,0.5 0.5 V19a0.51 0.51 ,0,0,1-0.5 0.5 H3a0.51 0.51 ,0,0,1-0.5-0.5Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M 9.5 8 L 10.5 8 Q 11 8 11 8.5 L 11 9.5 Q 11 10 10.5 10 L 9.5 10 Q 9 10 9 9.5 L 9 8.5 Q 9 8 9.5 8 Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M 5.5 8 L 6.5 8 Q 7 8 7 8.5 L 7 9.5 Q 7 10 6.5 10 L 5.5 10 Q 5 10 5 9.5 L 5 8.5 Q 5 8 5.5 8 Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M8.75,17.5h6.5a0.75 0.75 ,0,0,0,0-1.5H8.75a0.75 0.75 ,0,0,0,0,1.5Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M 13.5 8 L 14.5 8 Q 15 8 15 8.5 L 15 9.5 Q 15 10 14.5 10 L 13.5 10 Q 13 10 13 9.5 L 13 8.5 Q 13 8 13.5 8 Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M 9.5 12 L 10.5 12 Q 11 12 11 12.5 L 11 13.5 Q 11 14 10.5 14 L 9.5 14 Q 9 14 9 13.5 L 9 12.5 Q 9 12 9.5 12 Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M 5.5 12 L 6.5 12 Q 7 12 7 12.5 L 7 13.5 Q 7 14 6.5 14 L 5.5 14 Q 5 14 5 13.5 L 5 12.5 Q 5 12 5.5 12 Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M 13.5 12 L 14.5 12 Q 15 12 15 12.5 L 15 13.5 Q 15 14 14.5 14 L 13.5 14 Q 13 14 13 13.5 L 13 12.5 Q 13 12 13.5 12 Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M 17.5 8 L 18.5 8 Q 19 8 19 8.5 L 19 9.5 Q 19 10 18.5 10 L 17.5 10 Q 17 10 17 9.5 L 17 8.5 Q 17 8 17.5 8 Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M 17.5 12 L 18.5 12 Q 19 12 19 12.5 L 19 13.5 Q 19 14 18.5 14 L 17.5 14 Q 17 14 17 13.5 L 17 12.5 Q 17 12 17.5 12 Z" />
-</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_qs_auto_rotate.xml b/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_qs_auto_rotate.xml
deleted file mode 100644
index fe7ecfd..0000000
--- a/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_qs_auto_rotate.xml
+++ /dev/null
@@ -1,31 +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.
- */
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24">
-
-    <path
-        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M3,6.81a0.75 0.75 ,0,0,0-0.75 0.75 v2.83a0.74 0.74 ,0,0,0,0.75 0.75 H5.8a0.75 0.75 ,0,1,0,0-1.5h-1l5.6-5.59,7.07,7.06a0.75 0.75 ,0,0,0,1.06-1.06l-7.6-7.6a0.75 0.75 ,0,0,0-1.06,0L3.72,8.62V7.56A0.76 0.76 ,0,0,0,3,6.81Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M21,12.85H18.21a0.75 0.75 ,0,0,0,0,1.5h1L13.59,20,6.52,12.89a0.75 0.75 ,0,0,0-1.06,0,0.74 0.74 ,0,0,0,0,1.06l7.6,7.6a0.75 0.75 ,0,0,0,1.06,0l6.17-6.17v1.06a0.75 0.75 ,0,1,0,1.5,0V13.6A0.76 0.76 ,0,0,0,21,12.85Z" />
-</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_qs_brightness_auto_on.xml b/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_qs_brightness_auto_on.xml
deleted file mode 100644
index 9bf1274..0000000
--- a/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_qs_brightness_auto_on.xml
+++ /dev/null
@@ -1,52 +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.
- */
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24">
-
-    <path
-        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M12.75,2.25V0.75a0.75 0.75 ,0,0,0-1.5,0v1.5a0.75 0.75 ,0,0,0,1.5,0Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M4.57,5.64a0.79 0.79 ,0,0,0,1.07,0,0.77 0.77 ,0,0,0,0-1.07L4.58,3.51A0.76 0.76 ,0,0,0,3.51,4.58Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M0.75,12.75h1.5a0.75 0.75 ,0,0,0,0-1.5H0.75a0.75 0.75 ,0,0,0,0,1.5Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M3.51,20.49a0.76 0.76 ,0,0,0,1.07,0l1.06-1.06a0.76 0.76 ,0,1,0-1.07-1.07L3.51,19.42A0.77 0.77 ,0,0,0,3.51,20.49Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M11.25,21.75v1.5a0.75 0.75 ,0,0,0,1.5,0v-1.5a0.75 0.75 ,0,0,0-1.5,0Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M20,20.71a0.79 0.79 ,0,0,0,0.53-0.22 0.77 0.77,0,0,0,0-1.07l-1.06-1.06a0.76 0.76 ,0,0,0-1.07,1.07l1.06,1.06A0.79 0.79 ,0,0,0,20,20.71Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M23.25,11.25h-1.5a0.75 0.75 ,0,0,0,0,1.5h1.5a0.75 0.75 ,0,0,0,0-1.5Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M19.42,3.51,18.36,4.57a0.77 0.77 ,0,0,0,0,1.07 0.79 0.79,0,0,0,1.07,0l1.06-1.06a0.76 0.76 ,0,0,0-1.07-1.07Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M14.85,17H17L13.11,7H10.87L7,17H9.15L10,14.61h4Zm-4.22-4.12,1.31-3.71h0.11l1.29,3.71Z" />
-</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_qs_cast_on.xml b/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_qs_cast_on.xml
deleted file mode 100644
index 34ca21a..0000000
--- a/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_qs_cast_on.xml
+++ /dev/null
@@ -1,40 +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.
- */
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24">
-
-    <path
-        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M22,18V5.5A1.5,1.5,0,0,0,20.5,4h-17A1.5,1.5,0,0,0,2,5.53V8.46a0.75 0.75 ,0,0,0,1.5,0v-3l17,0V18H13.15a0.75 0.75 ,0,1,0,0,1.5h7.38A1.5,1.5,0,0,0,22,18Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M3.25,19.5a1.25,1.25,0,0,0,0-2.5h0a1.25,1.25,0,0,0,0,2.5Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M2,11.25a0.76 0.76 ,0,0,0,0.75 0.75 A6.75,6.75,0,0,1,9.5,18.75a0.75 0.75 ,0,0,0,1.5,0A8.25,8.25,0,0,0,2.75,10.5 0.76 0.76,0,0,0,2,11.25Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M2.75,15.25a3.5,3.5,0,0,1,3.5,3.5 0.75 0.75,0,0,0,1.5,0,5,5,0,0,0-5-5,0.75 0.75 ,0,0,0,0,1.5Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M13.25,15a0.75 0.75 ,0,0,0,0,1.5h5a0.76 0.76 ,0,0,0,0.75-0.75v-8A0.76 0.76 ,0,0,0,18.25,7H5.75A0.76 0.76 ,0,0,0,5,7.75V8.5a0.75 0.75 ,0,0,0,1.5,0h11V15Z" />
-</vector>
\ No newline at end of file
diff --git a/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_settings_16dp.xml b/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_settings_16dp.xml
deleted file mode 100644
index 4237323..0000000
--- a/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_settings_16dp.xml
+++ /dev/null
@@ -1,31 +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.
- */
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="16dp"
-    android:height="16dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24">
-
-    <path
-        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M2.2,15.53,4,18.7a1.46,1.46,0,0,0,1.28 0.75 ,1.61,1.61,0,0,0,0.53-0.1l1.8-0.72a9,9,0,0,0,0.79 0.46 L8.7,21a1.45,1.45,0,0,0,1.45,1.27h3.7A1.47,1.47,0,0,0,15.31,21l0.27-1.91c0.26-0.14 0.52 -0.29 0.78 -0.46l1.8 0.72 a1.47,1.47,0,0,0,0.54 0.1 A1.43,1.43,0,0,0,20,18.75l1.86-3.22a1.47,1.47,0,0,0-0.37-1.86l-1.52-1.19c0-0.15,0-0.3,0-0.46s0-0.31,0-0.46l1.52-1.19a1.47,1.47,0,0,0,0.36-1.88L20,5.31a1.46,1.46,0,0,0-1.29-0.75,1.71,1.71,0,0,0-0.53 0.1 l-1.8 0.72 a9,9,0,0,0-0.79-0.46L15.29,3a1.45,1.45,0,0,0-1.45-1.27h-3.7A1.46,1.46,0,0,0,8.7,3L8.43,4.92c-0.26 0.14 -0.52 0.29 -0.78 0.46 L5.84,4.65a1.47,1.47,0,0,0-0.54-0.1,1.42,1.42,0,0,0-1.25 0.73 L2.2,8.47a1.44,1.44,0,0,0,0.37,1.88l1.52,1.19c0,0.15,0,0.31,0,0.46s0,0.31,0,0.46L2.56,13.65A1.48,1.48,0,0,0,2.2,15.53ZM5,13.64l0.63-0.49,0-0.79c0-0.12,0-0.23,0-0.36s0-0.24,0-0.36l0-0.79L5,10.36,3.52,9.19,5.33,6.06l1.76 0.71 0.73 0.29 0.65-0.42a6.59,6.59,0,0,1,0.67-0.4l0.67-0.36 0.11 -0.75 0.26 -1.87h3.63l0.27,1.87 0.1 0.77 0.69 0.35a6,6,0,0,1,0.66 0.39 l0.65 0.42 0.73-0.29,1.76-0.71L20.5,9.21,19,10.38l-0.63 0.49 0.05 0.79 c0,0.12,0,0.23,0,0.36s0,0.24,0,0.36l-0.05 0.79 0.63 0.49 ,1.48,1.17L18.68,18l-1.76-0.7L16.19,17l-0.65 0.42 a6.59,6.59,0,0,1-0.67 0.4 l-0.67 0.36 -0.11 0.75 -0.26,1.84H10.18l-0.27-1.87-0.1-0.77-0.69-0.35a6,6,0,0,1-0.66-0.39L7.81,17l-0.73 0.29 L5.33,18,3.52,14.8Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M12,16a4,4,0,1,0-4-4A4,4,0,0,0,12,16Zm0-6.5A2.5,2.5,0,1,1,9.5,12,2.5,2.5,0,0,1,12,9.5Z" />
-</vector>
diff --git a/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_signal_airplane.xml b/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_signal_airplane.xml
deleted file mode 100644
index 2d36a39..0000000
--- a/packages/overlays/IconPackRoundedSystemUIOverlay/res/drawable/ic_signal_airplane.xml
+++ /dev/null
@@ -1,28 +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.
- */
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
-    android:viewportWidth="24"
-    android:viewportHeight="24">
-
-    <path
-        android:pathData="M 0 0 H 24 V 24 H 0 V 0 Z" />
-    <path
-        android:fillColor="#000000"
-        android:pathData="M2.52,16.17a1.25,1.25,0,0,0,1.11 0.19 L9.5,14.52v3.87L8,19.52a1.26,1.26,0,0,0-0.5,1v0.75a1.25,1.25,0,0,0,1.25,1.25h6.5a1.25,1.25,0,0,0,1.25-1.25v-0.75a1.26,1.26,0,0,0-0.5-1l-1.5-1.13V14.52l5.88,1.84a1.23,1.23,0,0,0,1.11-0.19,1.25,1.25,0,0,0,0.51-1V13.33a1.74,1.74,0,0,0-0.89-1.52L14.5,8.06V3.75a2.5,2.5,0,0,0-5,0V8.06L2.89,11.8A1.78,1.78,0,0,0,2,13.33v1.83A1.25,1.25,0,0,0,2.52,16.17Zm1.11-3.06L11,8.94V3.75a1,1,0,0,1,2,0V8.94l7.37,4.17a0.26 0.26 ,0,0,1,0.13 0.22 v1.49L13,12.48v6.66l2,1.5V21H9v-0.38l2-1.5V12.48L3.51,14.82V13.33A0.25 0.25 ,0,0,1,3.63,13.11Z" />
-</vector>
\ No newline at end of file
diff --git a/packages/overlays/NavigationBarModeGesturalOverlay/res/values/config.xml b/packages/overlays/NavigationBarModeGesturalOverlay/res/values/config.xml
index 48c3769..545a3cc 100644
--- a/packages/overlays/NavigationBarModeGesturalOverlay/res/values/config.xml
+++ b/packages/overlays/NavigationBarModeGesturalOverlay/res/values/config.xml
@@ -22,4 +22,8 @@
          1: 2 button mode (back, home buttons + swipe up for overview)
          2: gestures only for back, home and overview -->
     <integer name="config_navBarInteractionMode">2</integer>
+
+    <!-- Controls whether the nav bar can move from the bottom to the side in landscape.
+         Only applies if the device display is not square. -->
+    <bool name="config_navBarCanMove">false</bool>
 </resources>
\ No newline at end of file
diff --git a/packages/overlays/NavigationBarModeGesturalOverlay/res/values/dimens.xml b/packages/overlays/NavigationBarModeGesturalOverlay/res/values/dimens.xml
index 721d11b..c839b2c 100644
--- a/packages/overlays/NavigationBarModeGesturalOverlay/res/values/dimens.xml
+++ b/packages/overlays/NavigationBarModeGesturalOverlay/res/values/dimens.xml
@@ -19,6 +19,8 @@
 <resources>
     <!-- Height of the bottom navigation / system bar. -->
     <dimen name="navigation_bar_height">16dp</dimen>
+    <!-- Height of the bottom navigation bar in portrait; often the same as @dimen/navigation_bar_height -->
+    <dimen name="navigation_bar_height_landscape">16dp</dimen>
     <!-- Width of the navigation bar when it is placed vertically on the screen -->
     <dimen name="navigation_bar_width">16dp</dimen>
     <!-- Height of the bottom navigation / system bar. -->
diff --git a/rs/java/android/renderscript/RenderScript.java b/rs/java/android/renderscript/RenderScript.java
index 85c82bc..f4c2777 100644
--- a/rs/java/android/renderscript/RenderScript.java
+++ b/rs/java/android/renderscript/RenderScript.java
@@ -447,27 +447,33 @@
         validate();
         return rsnAllocationCreateTyped(mContext, type, mip, usage, pointer);
     }
-    native long rsnAllocationCreateFromBitmap(long con, long type, int mip, Bitmap bmp, int usage);
+    native long rsnAllocationCreateFromBitmap(long con, long type, int mip, long bitmapHandle,
+                int usage);
     synchronized long nAllocationCreateFromBitmap(long type, int mip, Bitmap bmp, int usage) {
         validate();
-        return rsnAllocationCreateFromBitmap(mContext, type, mip, bmp, usage);
+        return rsnAllocationCreateFromBitmap(mContext, type, mip, bmp.getNativeInstance(), usage);
     }
 
-    native long rsnAllocationCreateBitmapBackedAllocation(long con, long type, int mip, Bitmap bmp, int usage);
-    synchronized long nAllocationCreateBitmapBackedAllocation(long type, int mip, Bitmap bmp, int usage) {
+    native long rsnAllocationCreateBitmapBackedAllocation(long con, long type, int mip, long bitmapHandle,
+                int usage);
+    synchronized long nAllocationCreateBitmapBackedAllocation(long type, int mip, Bitmap bmp,
+                int usage) {
         validate();
-        return rsnAllocationCreateBitmapBackedAllocation(mContext, type, mip, bmp, usage);
+        return rsnAllocationCreateBitmapBackedAllocation(mContext, type, mip, bmp.getNativeInstance(),
+                usage);
     }
 
-    native long rsnAllocationCubeCreateFromBitmap(long con, long type, int mip, Bitmap bmp, int usage);
+    native long rsnAllocationCubeCreateFromBitmap(long con, long type, int mip, long bitmapHandle,
+                int usage);
     synchronized long nAllocationCubeCreateFromBitmap(long type, int mip, Bitmap bmp, int usage) {
         validate();
-        return rsnAllocationCubeCreateFromBitmap(mContext, type, mip, bmp, usage);
+        return rsnAllocationCubeCreateFromBitmap(mContext, type, mip, bmp.getNativeInstance(),
+                usage);
     }
-    native long  rsnAllocationCreateBitmapRef(long con, long type, Bitmap bmp);
+    native long  rsnAllocationCreateBitmapRef(long con, long type, long bitmapHandle);
     synchronized long nAllocationCreateBitmapRef(long type, Bitmap bmp) {
         validate();
-        return rsnAllocationCreateBitmapRef(mContext, type, bmp);
+        return rsnAllocationCreateBitmapRef(mContext, type, bmp.getNativeInstance());
     }
     native long  rsnAllocationCreateFromAssetStream(long con, int mips, int assetStream, int usage);
     synchronized long nAllocationCreateFromAssetStream(int mips, int assetStream, int usage) {
@@ -475,10 +481,10 @@
         return rsnAllocationCreateFromAssetStream(mContext, mips, assetStream, usage);
     }
 
-    native void  rsnAllocationCopyToBitmap(long con, long alloc, Bitmap bmp);
+    native void  rsnAllocationCopyToBitmap(long con, long alloc, long bitmapHandle);
     synchronized void nAllocationCopyToBitmap(long alloc, Bitmap bmp) {
         validate();
-        rsnAllocationCopyToBitmap(mContext, alloc, bmp);
+        rsnAllocationCopyToBitmap(mContext, alloc, bmp.getNativeInstance());
     }
 
     native void rsnAllocationSyncAll(long con, long alloc, int src);
@@ -487,8 +493,10 @@
         rsnAllocationSyncAll(mContext, alloc, src);
     }
 
-    native ByteBuffer rsnAllocationGetByteBuffer(long con, long alloc, long[] stride, int xBytesSize, int dimY, int dimZ);
-    synchronized ByteBuffer nAllocationGetByteBuffer(long alloc, long[] stride, int xBytesSize, int dimY, int dimZ) {
+    native ByteBuffer rsnAllocationGetByteBuffer(long con, long alloc, long[] stride,
+                int xBytesSize, int dimY, int dimZ);
+    synchronized ByteBuffer nAllocationGetByteBuffer(long alloc, long[] stride, int xBytesSize,
+                int dimY, int dimZ) {
         validate();
         return rsnAllocationGetByteBuffer(mContext, alloc, stride, xBytesSize, dimY, dimZ);
     }
@@ -529,10 +537,10 @@
         validate();
         rsnAllocationGenerateMipmaps(mContext, alloc);
     }
-    native void  rsnAllocationCopyFromBitmap(long con, long alloc, Bitmap bmp);
+    native void  rsnAllocationCopyFromBitmap(long con, long alloc, long bitmapHandle);
     synchronized void nAllocationCopyFromBitmap(long alloc, Bitmap bmp) {
         validate();
-        rsnAllocationCopyFromBitmap(mContext, alloc, bmp);
+        rsnAllocationCopyFromBitmap(mContext, alloc, bmp.getNativeInstance());
     }
 
 
diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp
index 52d0e08e..dfee961 100644
--- a/rs/jni/android_renderscript_RenderScript.cpp
+++ b/rs/jni/android_renderscript_RenderScript.cpp
@@ -1321,10 +1321,10 @@
 
 static jlong
 nAllocationCreateFromBitmap(JNIEnv *_env, jobject _this, jlong con, jlong type, jint mip,
-                            jobject jbitmap, jint usage)
+                            jlong bitmapPtr, jint usage)
 {
     SkBitmap bitmap;
-    GraphicsJNI::getSkBitmap(_env, jbitmap, &bitmap);
+    bitmap::toBitmap(bitmapPtr).getSkBitmap(&bitmap);
 
     const void* ptr = bitmap.getPixels();
     jlong id = (jlong)(uintptr_t)rsAllocationCreateFromBitmap((RsContext)con,
@@ -1335,10 +1335,10 @@
 
 static jlong
 nAllocationCreateBitmapBackedAllocation(JNIEnv *_env, jobject _this, jlong con, jlong type,
-                                        jint mip, jobject jbitmap, jint usage)
+                                        jint mip, jlong bitmapPtr, jint usage)
 {
     SkBitmap bitmap;
-    GraphicsJNI::getSkBitmap(_env, jbitmap, &bitmap);
+    bitmap::toBitmap(bitmapPtr).getSkBitmap(&bitmap);
 
     const void* ptr = bitmap.getPixels();
     jlong id = (jlong)(uintptr_t)rsAllocationCreateTyped((RsContext)con,
@@ -1349,10 +1349,10 @@
 
 static jlong
 nAllocationCubeCreateFromBitmap(JNIEnv *_env, jobject _this, jlong con, jlong type, jint mip,
-                                jobject jbitmap, jint usage)
+                                jlong bitmapPtr, jint usage)
 {
     SkBitmap bitmap;
-    GraphicsJNI::getSkBitmap(_env, jbitmap, &bitmap);
+    bitmap::toBitmap(bitmapPtr).getSkBitmap(&bitmap);
 
     const void* ptr = bitmap.getPixels();
     jlong id = (jlong)(uintptr_t)rsAllocationCubeCreateFromBitmap((RsContext)con,
@@ -1362,10 +1362,10 @@
 }
 
 static void
-nAllocationCopyFromBitmap(JNIEnv *_env, jobject _this, jlong con, jlong alloc, jobject jbitmap)
+nAllocationCopyFromBitmap(JNIEnv *_env, jobject _this, jlong con, jlong alloc, jlong bitmapPtr)
 {
     SkBitmap bitmap;
-    GraphicsJNI::getSkBitmap(_env, jbitmap, &bitmap);
+    bitmap::toBitmap(bitmapPtr).getSkBitmap(&bitmap);
     int w = bitmap.width();
     int h = bitmap.height();
 
@@ -1376,10 +1376,10 @@
 }
 
 static void
-nAllocationCopyToBitmap(JNIEnv *_env, jobject _this, jlong con, jlong alloc, jobject jbitmap)
+nAllocationCopyToBitmap(JNIEnv *_env, jobject _this, jlong con, jlong alloc, jlong bitmapPtr)
 {
     SkBitmap bitmap;
-    GraphicsJNI::getSkBitmap(_env, jbitmap, &bitmap);
+    bitmap::toBitmap(bitmapPtr).getSkBitmap(&bitmap);
 
     void* ptr = bitmap.getPixels();
     rsAllocationCopyToBitmap((RsContext)con, (RsAllocation)alloc, ptr, bitmap.computeByteSize());
@@ -2866,13 +2866,13 @@
 {"rsnTypeCreate",                    "(JJIIIZZI)J",                           (void*)nTypeCreate },
 {"rsnTypeGetNativeData",             "(JJ[J)V",                               (void*)nTypeGetNativeData },
 
-{"rsnAllocationCreateTyped",         "(JJIIJ)J",                               (void*)nAllocationCreateTyped },
-{"rsnAllocationCreateFromBitmap",    "(JJILandroid/graphics/Bitmap;I)J",      (void*)nAllocationCreateFromBitmap },
-{"rsnAllocationCreateBitmapBackedAllocation",    "(JJILandroid/graphics/Bitmap;I)J",      (void*)nAllocationCreateBitmapBackedAllocation },
-{"rsnAllocationCubeCreateFromBitmap","(JJILandroid/graphics/Bitmap;I)J",      (void*)nAllocationCubeCreateFromBitmap },
+{"rsnAllocationCreateTyped",         "(JJIIJ)J",                              (void*)nAllocationCreateTyped },
+{"rsnAllocationCreateFromBitmap",    "(JJIJI)J",                              (void*)nAllocationCreateFromBitmap },
+{"rsnAllocationCreateBitmapBackedAllocation",    "(JJIJI)J",                  (void*)nAllocationCreateBitmapBackedAllocation },
+{"rsnAllocationCubeCreateFromBitmap","(JJIJI)J",                              (void*)nAllocationCubeCreateFromBitmap },
 
-{"rsnAllocationCopyFromBitmap",      "(JJLandroid/graphics/Bitmap;)V",        (void*)nAllocationCopyFromBitmap },
-{"rsnAllocationCopyToBitmap",        "(JJLandroid/graphics/Bitmap;)V",        (void*)nAllocationCopyToBitmap },
+{"rsnAllocationCopyFromBitmap",      "(JJJ)V",                                (void*)nAllocationCopyFromBitmap },
+{"rsnAllocationCopyToBitmap",        "(JJJ)V",                                (void*)nAllocationCopyToBitmap },
 
 {"rsnAllocationSyncAll",             "(JJI)V",                                (void*)nAllocationSyncAll },
 {"rsnAllocationSetupBufferQueue",    "(JJI)V",                                (void*)nAllocationSetupBufferQueue },
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 7020e7e..fdc3567 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -42,6 +42,7 @@
 import android.database.ContentObserver;
 import android.graphics.Rect;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.Parcelable;
@@ -61,6 +62,7 @@
 import android.util.LocalLog;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.SparseBooleanArray;
 import android.view.autofill.AutofillId;
 import android.view.autofill.AutofillManager;
 import android.view.autofill.AutofillManager.SmartSuggestionMode;
@@ -72,6 +74,8 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.infra.AbstractRemoteService;
+import com.android.internal.infra.GlobalWhitelistState;
+import com.android.internal.infra.WhitelistHelper;
 import com.android.internal.os.IResultReceiver;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.Preconditions;
@@ -146,6 +150,7 @@
     private final LocalLog mWtfHistory = new LocalLog(50);
 
     private final AutofillCompatState mAutofillCompatState = new AutofillCompatState();
+
     private final LocalService mLocalService = new LocalService();
     private final ActivityManagerInternal mAm;
 
@@ -178,6 +183,8 @@
     @GuardedBy("mLock")
     int mAugmentedServiceRequestTimeoutMs;
 
+    final AugmentedAutofillState mAugmentedAutofillState = new AugmentedAutofillState();
+
     public AutofillManagerService(Context context) {
         super(context,
                 new SecureSettingsServiceNameResolver(context, Settings.Secure.AUTOFILL_SERVICE),
@@ -187,7 +194,7 @@
 
         DeviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_AUTOFILL,
                 ActivityThread.currentApplication().getMainExecutor(),
-                (namespace, key, value) -> onDeviceConfigChange(key, value));
+                (namespace, key, value) -> onDeviceConfigChange(key));
 
         setLogLevelFromSettings();
         setMaxPartitionsFromSettings();
@@ -201,15 +208,20 @@
         mAugmentedAutofillResolver = new FrameworkResourcesServiceNameResolver(getContext(),
                 com.android.internal.R.string.config_defaultAugmentedAutofillService);
         mAugmentedAutofillResolver.setOnTemporaryServiceNameChangedCallback(
-                (u, s) -> getServiceForUserLocked(u).updateRemoteAugmentedAutofillService());
+                (u, s, t) -> onAugmentedServiceNameChanged(u, s, t));
 
         if (mSupportedSmartSuggestionModes != AutofillManager.FLAG_SMART_SUGGESTION_OFF) {
-            // Must eager load the services so they bind to the augmented autofill service
             final UserManager um = getContext().getSystemService(UserManager.class);
             final List<UserInfo> users = um.getUsers();
             for (int i = 0; i < users.size(); i++) {
                 final int userId = users.get(i).id;
+                // Must eager load the services so they bind to the augmented autofill service
                 getServiceForUserLocked(userId);
+
+                // And also set the global state
+                mAugmentedAutofillState.setServiceInfo(userId,
+                        mAugmentedAutofillResolver.getServiceName(userId),
+                        mAugmentedAutofillResolver.isTemporary(userId));
             }
         }
     }
@@ -258,7 +270,7 @@
         }
     }
 
-    private void onDeviceConfigChange(@NonNull String key, @Nullable String value) {
+    private void onDeviceConfigChange(@NonNull String key) {
         switch (key) {
             case AutofillManager.DEVICE_CONFIG_AUTOFILL_SMART_SUGGESTION_SUPPORTED_MODES:
             case AutofillManager.DEVICE_CONFIG_AUGMENTED_SERVICE_IDLE_UNBIND_TIMEOUT:
@@ -270,6 +282,14 @@
         }
     }
 
+    private void onAugmentedServiceNameChanged(@UserIdInt int userId, @Nullable String serviceName,
+            boolean isTemporary) {
+        mAugmentedAutofillState.setServiceInfo(userId, serviceName, isTemporary);
+        synchronized (mLock) {
+            getServiceForUserLocked(userId).updateRemoteAugmentedAutofillService();
+        }
+    }
+
     @Override // from AbstractMasterSystemService
     protected AutofillManagerServiceImpl newServiceLocked(@UserIdInt int resolvedUserId,
             boolean disabled) {
@@ -783,15 +803,7 @@
             final boolean compatModeEnabled = mAutofillCompatState.isCompatibilityModeRequested(
                     packageName, versionCode, userId);
             final AutofillOptions options = new AutofillOptions(loggingLevel, compatModeEnabled);
-
-            synchronized (mLock) {
-                final AutofillManagerServiceImpl service =
-                        getServiceForUserLocked(UserHandle.getCallingUserId());
-                if (service != null) {
-                    service.setAugmentedAutofillWhitelistLocked(options, packageName);
-                }
-            }
-
+            mAugmentedAutofillState.injectAugmentedAutofillInfo(options, userId, packageName);
             return options;
         }
     }
@@ -934,6 +946,89 @@
         }
     }
 
+    /**
+     * Augmented autofill metadata associated with all services.
+     *
+     * <p>This object is defined here instead of on each {@link AutofillManagerServiceImpl} because
+     * it cannot hold a lock on the main lock when
+     * {@link AugmentedAutofillState#injectAugmentedAutofillInfo(AutofillOptions, int, String)}
+     * is called by external services.
+     */
+    static final class AugmentedAutofillState extends GlobalWhitelistState {
+
+        @GuardedBy("mGlobalWhitelistStateLock")
+        private final SparseArray<String> mServicePackages = new SparseArray<>();
+        @GuardedBy("mGlobalWhitelistStateLock")
+        private final SparseBooleanArray mTemporaryServices = new SparseBooleanArray();
+
+        private void setServiceInfo(@UserIdInt int userId, @Nullable String serviceName,
+                boolean isTemporary) {
+            synchronized (mGlobalWhitelistStateLock) {
+                if (isTemporary) {
+                    mTemporaryServices.put(userId, true);
+                } else {
+                    mTemporaryServices.delete(userId);
+                }
+                if (serviceName != null) {
+                    final ComponentName componentName =
+                            ComponentName.unflattenFromString(serviceName);
+                    if (componentName == null) {
+                        Slog.w(TAG, "setServiceInfo(): invalid name: " + serviceName);
+                        mServicePackages.remove(userId);
+                    } else {
+                        mServicePackages.put(userId, componentName.getPackageName());
+                    }
+                } else {
+                    mServicePackages.remove(userId);
+                }
+            }
+        }
+
+        public void injectAugmentedAutofillInfo(@NonNull AutofillOptions options,
+                @UserIdInt int userId, @NonNull String packageName) {
+            synchronized (mGlobalWhitelistStateLock) {
+                if (mWhitelisterHelpers == null) return;
+                final WhitelistHelper helper = mWhitelisterHelpers.get(userId);
+                if (helper != null) {
+                    options.augmentedAutofillEnabled = helper.isWhitelisted(packageName);
+                    options.whitelistedActivitiesForAugmentedAutofill = helper
+                            .getWhitelistedComponents(packageName);
+                }
+            }
+        }
+
+        @Override
+        public boolean isWhitelisted(@UserIdInt int userId, @NonNull ComponentName componentName) {
+            synchronized (mGlobalWhitelistStateLock) {
+                if (!super.isWhitelisted(userId, componentName)) return false;
+
+                if (Build.IS_USER && mTemporaryServices.get(userId)) {
+                    final String packageName = componentName.getPackageName();
+                    if (!packageName.equals(mServicePackages.get(userId))) {
+                        Slog.w(TAG, "Ignoring package " + packageName + " for augmented autofill "
+                                + "while using temporary service " + mServicePackages.get(userId));
+                        return false;
+                    }
+                }
+            }
+            return true;
+        }
+
+        @Override
+        public void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
+            super.dump(prefix, pw);
+
+            synchronized (mGlobalWhitelistStateLock) {
+                if (mServicePackages.size() > 0) {
+                    pw.print(prefix); pw.print("Service packages: "); pw.println(mServicePackages);
+                }
+                if (mTemporaryServices.size() > 0) {
+                    pw.print(prefix); pw.print("Temp services: "); pw.println(mTemporaryServices);
+                }
+            }
+        }
+    }
+
     final class AutoFillManagerServiceStub extends IAutoFillManager.Stub {
         @Override
         public void addClient(IAutoFillManagerClient client, ComponentName componentName,
@@ -1370,6 +1465,8 @@
                         pw.println(); pw.println("WTF history:"); pw.println();
                         mWtfHistory.reverseDump(fd, pw, args);
                     }
+                    pw.println("Augmented Autofill State: ");
+                    mAugmentedAutofillState.dump(prefix, pw);
                 }
             } finally {
                 sDebug = realDebug;
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index fe540bf..4bd6fbd3 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -31,7 +31,6 @@
 import android.app.ActivityManagerInternal;
 import android.app.ActivityTaskManager;
 import android.app.IActivityTaskManager;
-import android.content.AutofillOptions;
 import android.content.ComponentName;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
@@ -40,7 +39,6 @@
 import android.metrics.LogMaker;
 import android.os.AsyncTask;
 import android.os.Binder;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
@@ -76,7 +74,6 @@
 
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
-import com.android.internal.infra.WhitelistHelper;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.server.LocalServices;
@@ -170,12 +167,6 @@
     @Nullable
     private ServiceInfo mRemoteAugmentedAutofillServiceInfo;
 
-    /**
-     * List of packages/activities that are whitelisted to be trigger augmented autofill.
-     */
-    @GuardedBy("mLock")
-    private final WhitelistHelper mAugmentedWhitelistHelper = new WhitelistHelper();
-
     AutofillManagerServiceImpl(AutofillManagerService master, Object lock,
             LocalLog uiLatencyHistory, LocalLog wtfHistory, int userId, AutoFillUI ui,
             AutofillCompatState autofillCompatState,
@@ -951,8 +942,6 @@
             pw.println(mRemoteAugmentedAutofillServiceInfo);
         }
 
-        mAugmentedWhitelistHelper.dump(prefix, "Augmented autofill whitelist", pw);
-
         pw.print(prefix); pw.print("Field classification enabled: ");
             pw.println(isFieldClassificationEnabledLocked());
         pw.print(prefix); pw.print("Compat pkgs: ");
@@ -1234,27 +1223,7 @@
 
     @GuardedBy("mLock")
     boolean isWhitelistedForAugmentedAutofillLocked(@NonNull ComponentName componentName) {
-        if (Build.IS_USER && mMaster.mAugmentedAutofillResolver.isTemporary(mUserId)) {
-            final String serviceName = mMaster.mAugmentedAutofillResolver.getServiceName(mUserId);
-            final ComponentName component = ComponentName.unflattenFromString(serviceName);
-            final String servicePackage = component == null ? null : component.getPackageName();
-            final String packageName = componentName.getPackageName();
-            if (!packageName.equals(servicePackage)) {
-                Slog.w(TAG, "Ignoring package " + packageName + " for augmented autofill while "
-                        + "using temporary service " + servicePackage);
-                return false;
-            }
-        }
-
-        return mAugmentedWhitelistHelper.isWhitelisted(componentName);
-    }
-
-    @GuardedBy("mLock")
-    void setAugmentedAutofillWhitelistLocked(@NonNull AutofillOptions options,
-            @NonNull String packageName) {
-        options.augmentedAutofillEnabled = mAugmentedWhitelistHelper.isWhitelisted(packageName);
-        options.whitelistedActivitiesForAugmentedAutofill = mAugmentedWhitelistHelper
-                .getWhitelistedComponents(packageName);
+        return mMaster.mAugmentedAutofillState.isWhitelisted(mUserId, componentName);
     }
 
     /**
@@ -1268,7 +1237,7 @@
             if (mMaster.verbose) {
                 Slog.v(TAG, "whitelisting packages: " + packages + "and activities: " + components);
             }
-            mAugmentedWhitelistHelper.setWhitelist(packages, components);
+            mMaster.mAugmentedAutofillState.setWhitelist(mUserId, packages, components);
         }
     }
 
@@ -1280,7 +1249,7 @@
         if (mMaster.verbose) {
             Slog.v(TAG, "resetting augmented autofill whitelist");
         }
-        whitelistForAugmentedAutofillPackages(null, null);
+        mMaster.mAugmentedAutofillState.resetWhitelist(mUserId);
     }
 
     private void sendStateToClients(boolean resetClient) {
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index c62794d..0402b8f 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -2540,13 +2540,14 @@
         boolean saveOnFinish = true;
         final SaveInfo saveInfo = response.getSaveInfo();
         final AutofillId saveTriggerId;
+        final int flags;
         if (saveInfo != null) {
             saveTriggerId = saveInfo.getTriggerId();
             if (saveTriggerId != null) {
                 writeLog(MetricsEvent.AUTOFILL_EXPLICIT_SAVE_TRIGGER_DEFINITION);
             }
-            mSaveOnAllViewsInvisible =
-                    (saveInfo.getFlags() & SaveInfo.FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE) != 0;
+            flags = saveInfo.getFlags();
+            mSaveOnAllViewsInvisible = (flags & SaveInfo.FLAG_SAVE_ON_ALL_VIEWS_INVISIBLE) != 0;
 
             // We only need to track views if we want to save once they become invisible.
             if (mSaveOnAllViewsInvisible) {
@@ -2561,11 +2562,12 @@
                     Collections.addAll(trackedViews, saveInfo.getOptionalIds());
                 }
             }
-            if ((saveInfo.getFlags() & SaveInfo.FLAG_DONT_SAVE_ON_FINISH) != 0) {
+            if ((flags & SaveInfo.FLAG_DONT_SAVE_ON_FINISH) != 0) {
                 saveOnFinish = false;
             }
 
         } else {
+            flags = 0;
             saveTriggerId = null;
         }
 
@@ -2592,7 +2594,8 @@
         try {
             if (sVerbose) {
                 Slog.v(TAG, "updateTrackedIdsLocked(): " + trackedViews + " => " + fillableIds
-                        + " triggerId: " + saveTriggerId + " saveOnFinish:" + saveOnFinish);
+                        + " triggerId: " + saveTriggerId + " saveOnFinish:" + saveOnFinish
+                        + " flags: " + flags + " hasSaveInfo: " + (saveInfo != null));
             }
             mClient.setTrackedViews(id, toArray(trackedViews), mSaveOnAllViewsInvisible,
                     saveOnFinish, toArray(fillableIds), saveTriggerId);
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 3865b27..a7404bc 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -72,7 +72,9 @@
 import com.android.internal.util.CollectionUtils;
 import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.server.FgThread;
+import com.android.server.LocalServices;
 import com.android.server.SystemService;
+import com.android.server.wm.ActivityTaskManagerInternal;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -84,6 +86,7 @@
 import java.io.IOException;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
@@ -519,6 +522,11 @@
             if (size(old) == size(associations)) return;
 
             Set<Association> finalAssociations = associations;
+            Set<String> companionAppPackages = new HashSet<>();
+            for (Association association : finalAssociations) {
+                companionAppPackages.add(association.companionAppPackage);
+            }
+
             file.write((out) -> {
                 XmlSerializer xml = Xml.newSerializer();
                 try {
@@ -542,6 +550,9 @@
                 }
 
             });
+            ActivityTaskManagerInternal atmInternal = LocalServices.getService(
+                    ActivityTaskManagerInternal.class);
+            atmInternal.setCompanionAppPackages(userId, companionAppPackages);
         }
     }
 
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
index b2760e0..9b02c4e 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
@@ -18,6 +18,7 @@
 
 import static android.Manifest.permission.MANAGE_CONTENT_CAPTURE;
 import static android.content.Context.CONTENT_CAPTURE_MANAGER_SERVICE;
+import static android.view.contentcapture.ContentCaptureHelper.toList;
 import static android.view.contentcapture.ContentCaptureManager.RESULT_CODE_FALSE;
 import static android.view.contentcapture.ContentCaptureManager.RESULT_CODE_OK;
 import static android.view.contentcapture.ContentCaptureManager.RESULT_CODE_SECURITY_EXCEPTION;
@@ -40,6 +41,7 @@
 import android.content.pm.UserInfo;
 import android.database.ContentObserver;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -50,9 +52,12 @@
 import android.provider.DeviceConfig;
 import android.provider.Settings;
 import android.service.contentcapture.ActivityEvent.ActivityEventType;
+import android.util.ArraySet;
 import android.util.LocalLog;
 import android.util.Slog;
+import android.util.SparseArray;
 import android.util.SparseBooleanArray;
+import android.view.contentcapture.ContentCaptureCondition;
 import android.view.contentcapture.ContentCaptureHelper;
 import android.view.contentcapture.ContentCaptureManager;
 import android.view.contentcapture.IContentCaptureManager;
@@ -60,6 +65,7 @@
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.infra.AbstractRemoteService;
+import com.android.internal.infra.GlobalWhitelistState;
 import com.android.internal.os.IResultReceiver;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.Preconditions;
@@ -117,10 +123,13 @@
     @GuardedBy("mLock") int mDevCfgLogHistorySize;
     @GuardedBy("mLock") int mDevCfgIdleUnbindTimeoutMs;
 
+    final GlobalContentCaptureOptions mGlobalContentCaptureOptions =
+            new GlobalContentCaptureOptions();
+
     public ContentCaptureManagerService(@NonNull Context context) {
         super(context, new FrameworkResourcesServiceNameResolver(context,
                 com.android.internal.R.string.config_defaultContentCaptureService),
-                UserManager.DISALLOW_CONTENT_CAPTURE, /* refreshServiceOnPackageUpdate=*/ false);
+                UserManager.DISALLOW_CONTENT_CAPTURE, /* refreshServiceOnPackageUpdate= */ false);
         DeviceConfig.addOnPropertyChangedListener(DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
                 ActivityThread.currentApplication().getMainExecutor(),
                 (namespace, key, value) -> onDeviceConfigChange(key, value));
@@ -136,12 +145,12 @@
             mRequestsHistory = null;
         }
 
-        // Sets which services are disabled by settings
         final UserManager um = getContext().getSystemService(UserManager.class);
         final List<UserInfo> users = um.getUsers();
         for (int i = 0; i < users.size(); i++) {
             final int userId = users.get(i).id;
             final boolean disabled = !isEnabledBySettings(userId);
+            // Sets which services are disabled by settings
             if (disabled) {
                 Slog.i(mTag, "user " + userId + " disabled by settings");
                 if (mDisabledBySettings == null) {
@@ -149,6 +158,10 @@
                 }
                 mDisabledBySettings.put(userId, true);
             }
+            // Sets the global options for the service.
+            mGlobalContentCaptureOptions.setServiceInfo(userId,
+                    mServiceNameResolver.getServiceName(userId),
+                    mServiceNameResolver.isTemporary(userId));
         }
     }
 
@@ -188,6 +201,14 @@
     }
 
     @Override // from AbstractMasterSystemService
+    protected void onServiceNameChanged(@UserIdInt int userId, @NonNull String serviceName,
+            boolean isTemporary) {
+        mGlobalContentCaptureOptions.setServiceInfo(userId, serviceName, isTemporary);
+
+        super.onServiceNameChanged(userId, serviceName, isTemporary);
+    }
+
+    @Override // from AbstractMasterSystemService
     protected void enforceCallingPermissionForManagement() {
         getContext().enforceCallingPermission(MANAGE_CONTENT_CAPTURE, mTag);
     }
@@ -429,23 +450,16 @@
     }
 
     @GuardedBy("mLock")
-    private boolean assertCalledByServiceLocked(@NonNull String methodName, @UserIdInt int userId,
-            int callingUid, @NonNull IResultReceiver result) {
-        final boolean isService = isCalledByServiceLocked(methodName, userId, callingUid);
-        if (isService) return true;
-
-        try {
-            result.send(RESULT_CODE_SECURITY_EXCEPTION, /* resultData= */ null);
-        } catch (RemoteException e) {
-            Slog.w(mTag, "Unable to send isContentCaptureFeatureEnabled(): " + e);
+    private void assertCalledByServiceLocked(@NonNull String methodName) {
+        if (!isCalledByServiceLocked(methodName)) {
+            throw new SecurityException("caller is not user's ContentCapture service");
         }
-        return false;
     }
 
     @GuardedBy("mLock")
-    private boolean isCalledByServiceLocked(@NonNull String methodName, @UserIdInt int userId,
-            int callingUid) {
-
+    private boolean isCalledByServiceLocked(@NonNull String methodName) {
+        final int userId = UserHandle.getCallingUserId();
+        final int callingUid = Binder.getCallingUid();
         final String serviceName = mServiceNameResolver.getServiceName(userId);
         if (serviceName == null) {
             Slog.e(mTag, methodName + ": called by UID " + callingUid
@@ -453,7 +467,7 @@
             return false;
         }
 
-        final ComponentName serviceComponent  = ComponentName.unflattenFromString(serviceName);
+        final ComponentName serviceComponent = ComponentName.unflattenFromString(serviceName);
         if (serviceComponent == null) {
             Slog.w(mTag, methodName + ": invalid service name: " + serviceName);
             return false;
@@ -478,6 +492,27 @@
         return true;
     }
 
+    /**
+     * Executes the given {@code runnable} and if it throws a {@link SecurityException},
+     * send it back to the receiver.
+     *
+     * @return whether the exception was thrown or not.
+     */
+    private boolean throwsSecurityException(@NonNull IResultReceiver result,
+            @NonNull Runnable runable) {
+        try {
+            runable.run();
+            return false;
+        } catch (SecurityException e) {
+            try {
+                result.send(RESULT_CODE_SECURITY_EXCEPTION, bundleFor(e.getMessage()));
+            } catch (RemoteException e2) {
+                Slog.w(mTag, "Unable to send security exception (" + e + "): ", e2);
+            }
+        }
+        return true;
+    }
+
     @Override // from AbstractMasterSystemService
     protected void dumpLocked(String prefix, PrintWriter pw) {
         super.dumpLocked(prefix, pw);
@@ -496,13 +531,15 @@
         pw.print(prefix2); pw.print("logHistorySize: "); pw.println(mDevCfgLogHistorySize);
         pw.print(prefix2); pw.print("idleUnbindTimeoutMs: ");
         pw.println(mDevCfgIdleUnbindTimeoutMs);
+        pw.print(prefix); pw.println("Global Options:");
+        mGlobalContentCaptureOptions.dump(prefix2, pw);
     }
 
     final class ContentCaptureManagerServiceStub extends IContentCaptureManager.Stub {
 
         @Override
         public void startSession(@NonNull IBinder activityToken,
-                @NonNull ComponentName componentName, @NonNull String sessionId, int flags,
+                @NonNull ComponentName componentName, int sessionId, int flags,
                 @NonNull IResultReceiver result) {
             Preconditions.checkNotNull(activityToken);
             Preconditions.checkNotNull(sessionId);
@@ -519,7 +556,7 @@
         }
 
         @Override
-        public void finishSession(@NonNull String sessionId) {
+        public void finishSession(int sessionId) {
             Preconditions.checkNotNull(sessionId);
             final int userId = UserHandle.getCallingUserId();
 
@@ -547,6 +584,8 @@
         @Override
         public void removeUserData(@NonNull UserDataRemovalRequest request) {
             Preconditions.checkNotNull(request);
+            assertCalledByPackageOwner(request.getPackageName());
+
             final int userId = UserHandle.getCallingUserId();
             synchronized (mLock) {
                 final ContentCapturePerUserService service = getServiceForUserLocked(userId);
@@ -556,13 +595,14 @@
 
         @Override
         public void isContentCaptureFeatureEnabled(@NonNull IResultReceiver result) {
-            final int userId = UserHandle.getCallingUserId();
             boolean enabled;
             synchronized (mLock) {
-                final boolean isService = assertCalledByServiceLocked(
-                        "isContentCaptureFeatureEnabled()", userId, Binder.getCallingUid(), result);
-                if (!isService) return;
+                if (throwsSecurityException(result,
+                        () -> assertCalledByServiceLocked("isContentCaptureFeatureEnabled()"))) {
+                    return;
+                }
 
+                final int userId = UserHandle.getCallingUserId();
                 enabled = !mDisabledByDeviceConfig && !isDisabledBySettingsLocked(userId);
             }
             try {
@@ -574,15 +614,8 @@
 
         @Override
         public void getServiceSettingsActivity(@NonNull IResultReceiver result) {
-            try {
-                enforceCallingPermissionForManagement();
-            } catch (SecurityException e) {
-                try {
-                    result.send(RESULT_CODE_SECURITY_EXCEPTION, bundleFor(e.getMessage()));
-                } catch (RemoteException e2) {
-                    Slog.w(mTag, "Unable to send getServiceSettingsIntent() exception: " + e2);
-                    return;
-                }
+            if (throwsSecurityException(result, () -> enforceCallingPermissionForManagement())) {
+                return;
             }
 
             final int userId = UserHandle.getCallingUserId();
@@ -600,13 +633,34 @@
         }
 
         @Override
+        public void getContentCaptureConditions(@NonNull String packageName,
+                @NonNull IResultReceiver result) {
+            if (throwsSecurityException(result, () -> assertCalledByPackageOwner(packageName))) {
+                return;
+            }
+
+            final int userId = UserHandle.getCallingUserId();
+            final ArrayList<ContentCaptureCondition> conditions;
+            synchronized (mLock) {
+                final ContentCapturePerUserService service = getServiceForUserLocked(userId);
+                conditions = service == null ? null
+                        : toList(service.getContentCaptureConditionsLocked(packageName));
+            }
+            try {
+                result.send(RESULT_CODE_OK, bundleFor(conditions));
+            } catch (RemoteException e) {
+                Slog.w(mTag, "Unable to send getServiceComponentName(): " + e);
+            }
+        }
+
+        @Override
         public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
             if (!DumpUtils.checkDumpPermission(getContext(), mTag, pw)) return;
 
             boolean showHistory = true;
             if (args != null) {
                 for (String arg : args) {
-                    switch(arg) {
+                    switch (arg) {
                         case "--no-history":
                             showHistory = false;
                             break;
@@ -670,13 +724,7 @@
 
         @Override
         public ContentCaptureOptions getOptionsForPackage(int userId, @NonNull String packageName) {
-            synchronized (mLock) {
-                final ContentCapturePerUserService service = peekServiceForUserLocked(userId);
-                if (service != null) {
-                    return service.getOptionsForPackageLocked(packageName);
-                }
-            }
-            return null;
+            return mGlobalContentCaptureOptions.getOptions(userId, packageName);
         }
 
         @Override
@@ -690,4 +738,92 @@
             }
         }
     }
+
+    /**
+     * Content capture options associated with all services.
+     *
+     * <p>This object is defined here instead of on each {@link ContentCapturePerUserService}
+     * because it cannot hold a lock on the main lock when
+     * {@link GlobalContentCaptureOptions#getOptions(int, String)} is called by external services.
+     */
+    final class GlobalContentCaptureOptions extends GlobalWhitelistState {
+
+        @GuardedBy("mGlobalWhitelistStateLock")
+        private final SparseArray<String> mServicePackages = new SparseArray<>();
+        @GuardedBy("mGlobalWhitelistStateLock")
+        private final SparseBooleanArray mTemporaryServices = new SparseBooleanArray();
+
+        private void setServiceInfo(@UserIdInt int userId, @Nullable String serviceName,
+                boolean isTemporary) {
+            synchronized (mGlobalWhitelistStateLock) {
+                if (isTemporary) {
+                    mTemporaryServices.put(userId, true);
+                } else {
+                    mTemporaryServices.delete(userId);
+                }
+                if (serviceName != null) {
+                    final ComponentName componentName =
+                            ComponentName.unflattenFromString(serviceName);
+                    if (componentName == null) {
+                        Slog.w(mTag, "setServiceInfo(): invalid name: " + serviceName);
+                        mServicePackages.remove(userId);
+                    } else {
+                        mServicePackages.put(userId, componentName.getPackageName());
+                    }
+                } else {
+                    mServicePackages.remove(userId);
+                }
+            }
+        }
+
+        @Nullable
+        @GuardedBy("mGlobalWhitelistStateLock")
+        public ContentCaptureOptions getOptions(@UserIdInt int userId,
+                @NonNull String packageName) {
+            synchronized (mGlobalWhitelistStateLock) {
+                if (!isWhitelisted(userId, packageName)) {
+                    if (packageName.equals(mServicePackages.get(userId))) {
+                        if (verbose) Slog.v(mTag, "getOptionsForPackage() lite for " + packageName);
+                        return new ContentCaptureOptions(mDevCfgLoggingLevel);
+                    }
+                    if (verbose) {
+                        Slog.v(mTag, "getOptionsForPackage(" + packageName + "): not whitelisted");
+                    }
+                    return null;
+                }
+
+                final ArraySet<ComponentName> whitelistedComponents =
+                        getWhitelistedComponents(userId, packageName);
+                if (Build.IS_USER && mServiceNameResolver.isTemporary(userId)) {
+                    if (!packageName.equals(mServicePackages.get(userId))) {
+                        Slog.w(mTag, "Ignoring package " + packageName
+                                + " while using temporary service " + mServicePackages.get(userId));
+                        return null;
+                    }
+                }
+                final ContentCaptureOptions options = new ContentCaptureOptions(mDevCfgLoggingLevel,
+                        mDevCfgMaxBufferSize, mDevCfgIdleFlushingFrequencyMs,
+                        mDevCfgTextChangeFlushingFrequencyMs, mDevCfgLogHistorySize,
+                        whitelistedComponents);
+                if (verbose) {
+                    Slog.v(mTag, "getOptionsForPackage(" + packageName + "): " + options);
+                }
+                return options;
+            }
+        }
+
+        @Override
+        public void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
+            super.dump(prefix, pw);
+
+            synchronized (mGlobalWhitelistStateLock) {
+                if (mServicePackages.size() > 0) {
+                    pw.print(prefix); pw.print("Service packages: "); pw.println(mServicePackages);
+                }
+                if (mTemporaryServices.size() > 0) {
+                    pw.print(prefix); pw.print("Temp services: "); pw.println(mTemporaryServices);
+                }
+            }
+        }
+    }
 }
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
index f0c6f7e..5649526 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCapturePerUserService.java
@@ -17,6 +17,7 @@
 package com.android.server.contentcapture;
 
 import static android.service.contentcapture.ContentCaptureService.setClientState;
+import static android.view.contentcapture.ContentCaptureSession.NO_SESSION_ID;
 import static android.view.contentcapture.ContentCaptureSession.STATE_DISABLED;
 import static android.view.contentcapture.ContentCaptureSession.STATE_DUPLICATED_ID;
 import static android.view.contentcapture.ContentCaptureSession.STATE_INTERNAL_ERROR;
@@ -54,6 +55,8 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Slog;
+import android.util.SparseArray;
+import android.view.contentcapture.ContentCaptureCondition;
 import android.view.contentcapture.UserDataRemovalRequest;
 
 import com.android.internal.annotations.GuardedBy;
@@ -78,8 +81,7 @@
     private static final String TAG = ContentCapturePerUserService.class.getSimpleName();
 
     @GuardedBy("mLock")
-    private final ArrayMap<String, ContentCaptureServerSession> mSessions =
-            new ArrayMap<>();
+    private final SparseArray<ContentCaptureServerSession> mSessions = new SparseArray<>();
 
     /**
      * Reference to the remote service.
@@ -101,6 +103,13 @@
     private final WhitelistHelper mWhitelistHelper = new WhitelistHelper();
 
     /**
+     * List of conditions keyed by package.
+     */
+    @GuardedBy("mLock")
+    private final ArrayMap<String, ArraySet<ContentCaptureCondition>> mConditionsByPkg =
+            new ArrayMap<>();
+
+    /**
      * When {@code true}, remote service died but service state is kept so it's restored after
      * the system re-binds to it.
      */
@@ -226,9 +235,8 @@
     // TODO(b/119613670): log metrics
     @GuardedBy("mLock")
     public void startSessionLocked(@NonNull IBinder activityToken,
-            @NonNull ActivityPresentationInfo activityPresentationInfo,
-            @NonNull String sessionId, int uid, int flags,
-            @NonNull IResultReceiver clientReceiver) {
+            @NonNull ActivityPresentationInfo activityPresentationInfo, int sessionId, int uid,
+            int flags, @NonNull IResultReceiver clientReceiver) {
         if (activityPresentationInfo == null) {
             Slog.w(TAG, "basic activity info is null");
             setClientState(clientReceiver, STATE_DISABLED | STATE_INTERNAL_ERROR,
@@ -238,7 +246,8 @@
         final int taskId = activityPresentationInfo.taskId;
         final int displayId = activityPresentationInfo.displayId;
         final ComponentName componentName = activityPresentationInfo.componentName;
-        final boolean whiteListed = isWhitelistedLocked(componentName);
+        final boolean whiteListed = mMaster.mGlobalContentCaptureOptions.isWhitelisted(mUserId,
+                componentName);
         final ComponentName serviceComponentName = getServiceComponentName();
         final boolean enabled = isEnabledLocked();
         if (mMaster.mRequestsHistory != null) {
@@ -315,14 +324,9 @@
         newSession.notifySessionStartedLocked(clientReceiver);
     }
 
-    @GuardedBy("mLock")
-    private boolean isWhitelistedLocked(@NonNull ComponentName componentName) {
-        return mWhitelistHelper.isWhitelisted(componentName);
-    }
-
     // TODO(b/119613670): log metrics
     @GuardedBy("mLock")
-    public void finishSessionLocked(@NonNull String sessionId) {
+    public void finishSessionLocked(int sessionId) {
         if (!isEnabledLocked()) {
             return;
         }
@@ -386,8 +390,8 @@
     @GuardedBy("mLock")
     public boolean sendActivityAssistDataLocked(@NonNull IBinder activityToken,
             @NonNull Bundle data) {
-        final String id = getSessionId(activityToken);
-        if (id != null) {
+        final int id = getSessionId(activityToken);
+        if (id != NO_SESSION_ID) {
             final ContentCaptureServerSession session = mSessions.get(id);
             final Bundle assistData = data.getBundle(ASSIST_KEY_DATA);
             final AssistStructure assistStructure = data.getParcelable(ASSIST_KEY_STRUCTURE);
@@ -403,7 +407,7 @@
     }
 
     @GuardedBy("mLock")
-    public void removeSessionLocked(@NonNull String sessionId) {
+    public void removeSessionLocked(int sessionId) {
         mSessions.remove(sessionId);
     }
 
@@ -480,7 +484,7 @@
                 return null;
             }
         }
-        ContentCaptureOptions options = new ContentCaptureOptions(mMaster.mDevCfgLoggingLevel,
+        final ContentCaptureOptions options = new ContentCaptureOptions(mMaster.mDevCfgLoggingLevel,
                 mMaster.mDevCfgMaxBufferSize, mMaster.mDevCfgIdleFlushingFrequencyMs,
                 mMaster.mDevCfgTextChangeFlushingFrequencyMs, mMaster.mDevCfgLogHistorySize,
                 whitelistedComponents);
@@ -491,6 +495,13 @@
     }
 
     @GuardedBy("mLock")
+    @Nullable
+    ArraySet<ContentCaptureCondition> getContentCaptureConditionsLocked(
+            @NonNull String packageName) {
+        return mConditionsByPkg.get(packageName);
+    }
+
+    @GuardedBy("mLock")
     void onActivityEventLocked(@NonNull ComponentName componentName, @ActivityEventType int type) {
         if (mRemoteService == null) {
             if (mMaster.debug) Slog.d(mTag, "onActivityEvent(): no remote service");
@@ -522,9 +533,7 @@
             mRemoteService.dump(prefix2, pw);
         }
 
-        mWhitelistHelper.dump(prefix, "Whitelist", pw);
-
-        if (mSessions.isEmpty()) {
+        if (mSessions.size() == 0) {
             pw.print(prefix); pw.println("no sessions");
         } else {
             final int sessionsSize = mSessions.size();
@@ -542,14 +551,14 @@
      * Returns the session id associated with the given activity.
      */
     @GuardedBy("mLock")
-    private String getSessionId(@NonNull IBinder activityToken) {
+    private int getSessionId(@NonNull IBinder activityToken) {
         for (int i = 0; i < mSessions.size(); i++) {
             ContentCaptureServerSession session = mSessions.valueAt(i);
             if (session.isActivitySession(activityToken)) {
                 return mSessions.keyAt(i);
             }
         }
-        return null;
+        return NO_SESSION_ID;
     }
 
     /**
@@ -560,7 +569,7 @@
         if (mMaster.verbose) {
             Slog.v(TAG, "resetting content capture whitelist");
         }
-        mWhitelistHelper.setWhitelist((List) null, null);
+        mMaster.mGlobalContentCaptureOptions.resetWhitelist(mUserId);
     }
 
     private final class ContentCaptureServiceRemoteCallback extends
@@ -576,9 +585,24 @@
                         + ", " + (activities == null
                         ? "null_activities" : activities.size() + " activities") + ")");
             }
-            synchronized (mLock) {
-                mWhitelistHelper.setWhitelist(packages, activities);
+            mMaster.mGlobalContentCaptureOptions.setWhitelist(mUserId, packages, activities);
+        }
+
+        @Override
+        public void setContentCaptureConditions(String packageName,
+                List<ContentCaptureCondition> conditions) {
+            if (mMaster.verbose) {
+                Slog.v(TAG, "setContentCaptureConditions(" + packageName + "): "
+                        + (conditions == null ? "null" : conditions.size() + " conditions"));
             }
+            synchronized (mLock) {
+                if (conditions == null) {
+                    mConditionsByPkg.remove(packageName);
+                } else {
+                    mConditionsByPkg.put(packageName, new ArraySet<>(conditions));
+                }
+            }
+            // TODO(b/119613670): log metrics
         }
 
         @Override
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java
index 9b2c05f..1ad66d8 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureServerSession.java
@@ -16,6 +16,7 @@
 package com.android.server.contentcapture;
 
 import static android.service.contentcapture.ContentCaptureService.setClientState;
+import static android.view.contentcapture.ContentCaptureSession.NO_SESSION_ID;
 import static android.view.contentcapture.ContentCaptureSession.STATE_ACTIVE;
 import static android.view.contentcapture.ContentCaptureSession.STATE_DISABLED;
 import static android.view.contentcapture.ContentCaptureSession.STATE_SERVICE_RESURRECTED;
@@ -57,7 +58,7 @@
     /**
      * Canonical session id.
      */
-    private final String mId;
+    private final int mId;
 
     /**
      * UID of the app whose contents is being captured.
@@ -66,11 +67,12 @@
 
     ContentCaptureServerSession(@NonNull IBinder activityToken,
             @NonNull ContentCapturePerUserService service, @NonNull ComponentName appComponentName,
-            @NonNull IResultReceiver sessionStateReceiver,
-            int taskId, int displayId, @NonNull String sessionId, int uid, int flags) {
+            @NonNull IResultReceiver sessionStateReceiver, int taskId, int displayId, int sessionId,
+            int uid, int flags) {
+        Preconditions.checkArgument(sessionId != NO_SESSION_ID);
         mActivityToken = activityToken;
         mService = service;
-        mId = Preconditions.checkNotNull(sessionId);
+        mId = sessionId;
         mUid = uid;
         mContentCaptureContext = new ContentCaptureContext(/* clientContext= */ null,
                 appComponentName, taskId, displayId, flags);
diff --git a/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java b/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java
index 0afe252..3fa3fdf 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java
@@ -98,9 +98,8 @@
      * Called by {@link ContentCaptureServerSession} to generate a call to the
      * {@link RemoteContentCaptureService} to indicate the session was created.
      */
-    public void onSessionStarted(@Nullable ContentCaptureContext context,
-            @NonNull String sessionId, int uid, @NonNull IResultReceiver clientReceiver,
-            int initialState) {
+    public void onSessionStarted(@Nullable ContentCaptureContext context, int sessionId, int uid,
+            @NonNull IResultReceiver clientReceiver, int initialState) {
         scheduleAsyncRequest(
                 (s) -> s.onSessionStarted(context, sessionId, uid, clientReceiver, initialState));
     }
@@ -109,15 +108,14 @@
      * Called by {@link ContentCaptureServerSession} to generate a call to the
      * {@link RemoteContentCaptureService} to indicate the session was finished.
      */
-    public void onSessionFinished(@NonNull String sessionId) {
+    public void onSessionFinished(int sessionId) {
         scheduleAsyncRequest((s) -> s.onSessionFinished(sessionId));
     }
 
     /**
      * Called by {@link ContentCaptureServerSession} to send snapshot data to the service.
      */
-    public void onActivitySnapshotRequest(@NonNull String sessionId,
-            @NonNull SnapshotData snapshotData) {
+    public void onActivitySnapshotRequest(int sessionId, @NonNull SnapshotData snapshotData) {
         scheduleAsyncRequest((s) -> s.onActivitySnapshot(sessionId, snapshotData));
     }
 
diff --git a/services/core/Android.bp b/services/core/Android.bp
index c154240..9e1b3b8 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -51,6 +51,7 @@
         "android.hardware.configstore-V1.0-java",
         "android.hardware.contexthub-V1.0-java",
         "android.hidl.manager-V1.2-java",
+        "dnsresolver_aidl_interface-java",
         "netd_aidl_interface-java",
         "netd_event_listener_interface-java",
     ],
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 3d918fc..0f39029 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -3825,6 +3825,7 @@
                 Slog.w(TAG, "Failure sending alarm.", e);
             }
             Trace.traceEnd(Trace.TRACE_TAG_POWER);
+            decrementAlarmCount(alarm.uid);
         }
     }
 
@@ -4148,6 +4149,10 @@
         public void handleMessage(Message msg) {
             switch (msg.what) {
                 case ALARM_EVENT: {
+                    // This code is used when the kernel timer driver is not available, which
+                    // shouldn't happen. Here, we try our best to simulate it, which may be useful
+                    // when porting Android to a new device. Note that we can't wake up a device
+                    // this way, so WAKE_UP alarms will be delivered only when the device is awake.
                     ArrayList<Alarm> triggerList = new ArrayList<Alarm>();
                     synchronized (mLock) {
                         final long nowELAPSED = mInjector.getElapsedRealtime();
@@ -4167,6 +4172,7 @@
                                 removeImpl(alarm.operation, null);
                             }
                         }
+                        decrementAlarmCount(alarm.uid);
                     }
                     break;
                 }
@@ -4760,7 +4766,6 @@
                 mAppWakeupHistory.recordAlarmForPackage(alarm.sourcePackage,
                         UserHandle.getUserId(alarm.creatorUid), nowELAPSED);
             }
-            decrementAlarmCount(alarm.uid);
             final BroadcastStats bs = inflight.mBroadcastStats;
             bs.count++;
             if (bs.nesting == 0) {
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index 39f7f0f..6a9f5b6 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -357,10 +357,27 @@
                 && (oldPlugged || mLastBatteryLevel > mLowBatteryWarningLevel);
     }
 
+    private boolean shouldShutdownLocked() {
+        if (mHealthInfo.batteryLevel > 0) {
+            return false;
+        }
+
+        // Battery-less devices should not shutdown.
+        if (!mHealthInfo.batteryPresent) {
+            return false;
+        }
+
+        // If battery state is not CHARGING, shutdown.
+        // - If battery present and state == unknown, this is an unexpected error state.
+        // - If level <= 0 and state == full, this is also an unexpected state
+        // - All other states (NOT_CHARGING, DISCHARGING) means it is not charging.
+        return mHealthInfo.batteryStatus != BatteryManager.BATTERY_STATUS_CHARGING;
+    }
+
     private void shutdownIfNoPowerLocked() {
         // shut down gracefully if our battery is critically low and we are not powered.
         // wait until the system has booted before attempting to display the shutdown dialog.
-        if (mHealthInfo.batteryLevel == 0 && !isPoweredLocked(BatteryManager.BATTERY_PLUGGED_ANY)) {
+        if (shouldShutdownLocked()) {
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 2be92cd..1169eeb 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -63,6 +63,7 @@
 import android.net.ConnectivityManager;
 import android.net.ICaptivePortal;
 import android.net.IConnectivityManager;
+import android.net.IDnsResolver;
 import android.net.IIpConnectivityMetrics;
 import android.net.INetd;
 import android.net.INetdEventCallback;
@@ -294,6 +295,8 @@
 
     private INetworkManagementService mNMS;
     @VisibleForTesting
+    protected IDnsResolver mDnsResolver;
+    @VisibleForTesting
     protected INetd mNetd;
     private INetworkStatsService mStatsService;
     private INetworkPolicyManager mPolicyManager;
@@ -525,6 +528,11 @@
         return sMagicDecoderRing.get(what, Integer.toString(what));
     }
 
+    private static IDnsResolver getDnsResolver() {
+        return IDnsResolver.Stub
+                .asInterface(ServiceManager.getService("dnsresolver"));
+    }
+
     /** Handler thread used for both of the handlers below. */
     @VisibleForTesting
     protected final HandlerThread mHandlerThread;
@@ -810,13 +818,14 @@
 
     public ConnectivityService(Context context, INetworkManagementService netManager,
             INetworkStatsService statsService, INetworkPolicyManager policyManager) {
-        this(context, netManager, statsService, policyManager, new IpConnectivityLog());
+        this(context, netManager, statsService, policyManager,
+            getDnsResolver(), new IpConnectivityLog());
     }
 
     @VisibleForTesting
     protected ConnectivityService(Context context, INetworkManagementService netManager,
             INetworkStatsService statsService, INetworkPolicyManager policyManager,
-            IpConnectivityLog logger) {
+            IDnsResolver dnsresolver, IpConnectivityLog logger) {
         if (DBG) log("ConnectivityService starting up");
 
         mSystemProperties = getSystemProperties();
@@ -853,6 +862,7 @@
         mPolicyManagerInternal = checkNotNull(
                 LocalServices.getService(NetworkPolicyManagerInternal.class),
                 "missing NetworkPolicyManagerInternal");
+        mDnsResolver = checkNotNull(dnsresolver, "missing IDnsResolver");
         mProxyTracker = makeProxyTracker();
 
         mNetd = NetdService.getInstance();
@@ -1006,7 +1016,7 @@
 
         mMultipathPolicyTracker = new MultipathPolicyTracker(mContext, mHandler);
 
-        mDnsManager = new DnsManager(mContext, mNMS, mSystemProperties);
+        mDnsManager = new DnsManager(mContext, mDnsResolver, mSystemProperties);
         registerPrivateDnsSettingsCallbacks();
     }
 
@@ -3021,9 +3031,9 @@
             // NetworkFactories, so network traffic isn't interrupted for an unnecessarily
             // long time.
             try {
-                mNMS.removeNetwork(nai.network.netId);
-            } catch (Exception e) {
-                loge("Exception removing network: " + e);
+                mNetd.networkDestroy(nai.network.netId);
+            } catch (RemoteException | ServiceSpecificException e) {
+                loge("Exception destroying network: " + e);
             }
             mDnsManager.removeNetwork(nai.network);
         }
@@ -5372,8 +5382,8 @@
         final NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);
         final NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(),
                 new Network(reserveNetId()), new NetworkInfo(networkInfo), lp, nc, currentScore,
-                mContext, mTrackerHandler, new NetworkMisc(networkMisc), this, mNetd, mNMS,
-                factorySerialNumber);
+                mContext, mTrackerHandler, new NetworkMisc(networkMisc), this, mNetd, mDnsResolver,
+                mNMS, factorySerialNumber);
         // Make sure the network capabilities reflect what the agent info says.
         nai.networkCapabilities = mixInCapabilities(nai, nc);
         final String extraInfo = networkInfo.getExtraInfo();
diff --git a/services/core/java/com/android/server/DropBoxManagerService.java b/services/core/java/com/android/server/DropBoxManagerService.java
index f0f8adbb..33b846f 100644
--- a/services/core/java/com/android/server/DropBoxManagerService.java
+++ b/services/core/java/com/android/server/DropBoxManagerService.java
@@ -23,6 +23,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.res.Resources;
 import android.database.ContentObserver;
 import android.net.Uri;
 import android.os.Binder;
@@ -32,6 +33,9 @@
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
+import android.os.ResultReceiver;
+import android.os.ShellCallback;
+import android.os.ShellCommand;
 import android.os.StatFs;
 import android.os.SystemClock;
 import android.os.UserHandle;
@@ -39,8 +43,11 @@
 import android.text.TextUtils;
 import android.text.format.Time;
 import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.Slog;
 
+import com.android.internal.R;
+import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.os.IDropBoxManagerService;
 import com.android.internal.util.DumpUtils;
@@ -76,9 +83,6 @@
     private static final int DEFAULT_RESERVE_PERCENT = 10;
     private static final int QUOTA_RESCAN_MILLIS = 5000;
 
-    // mHandler 'what' value.
-    private static final int MSG_SEND_BROADCAST = 1;
-
     private static final boolean PROFILE_DUMP = false;
 
     // TODO: This implementation currently uses one file per entry, which is
@@ -95,6 +99,9 @@
     private FileList mAllFiles = null;
     private ArrayMap<String, FileList> mFilesByTag = null;
 
+    private long mLowPriorityRateLimitPeriod = 0;
+    private ArraySet<String> mLowPriorityTags = null;
+
     // Various bits of disk information
 
     private StatFs mStatFs = null;
@@ -105,7 +112,7 @@
     private volatile boolean mBooted = false;
 
     // Provide a way to perform sendBroadcast asynchronously to avoid deadlocks.
-    private final Handler mHandler;
+    private final DropBoxManagerBroadcastHandler mHandler;
 
     private int mMaxFiles = -1; // -1 means uninitialized.
 
@@ -152,8 +159,142 @@
         public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
             DropBoxManagerService.this.dump(fd, pw, args);
         }
+
+        @Override
+        public void onShellCommand(FileDescriptor in, FileDescriptor out,
+                                   FileDescriptor err, String[] args, ShellCallback callback,
+                                   ResultReceiver resultReceiver) {
+            (new ShellCmd()).exec(this, in, out, err, args, callback, resultReceiver);
+        }
     };
 
+    private class ShellCmd extends ShellCommand {
+        @Override
+        public int onCommand(String cmd) {
+            if (cmd == null) {
+                return handleDefaultCommands(cmd);
+            }
+            final PrintWriter pw = getOutPrintWriter();
+            try {
+                switch (cmd) {
+                    case "set-rate-limit":
+                        final long period = Long.parseLong(getNextArgRequired());
+                        DropBoxManagerService.this.setLowPriorityRateLimit(period);
+                        break;
+                    case "add-low-priority":
+                        final String addedTag = getNextArgRequired();
+                        DropBoxManagerService.this.addLowPriorityTag(addedTag);
+                        break;
+                    case "remove-low-priority":
+                        final String removeTag = getNextArgRequired();
+                        DropBoxManagerService.this.removeLowPriorityTag(removeTag);
+                        break;
+                    case "restore-defaults":
+                        DropBoxManagerService.this.restoreDefaults();
+                        break;
+                    default:
+                        return handleDefaultCommands(cmd);
+                }
+            } catch (Exception e) {
+                pw.println(e);
+            }
+            return 0;
+        }
+
+        @Override
+        public void onHelp() {
+            PrintWriter pw = getOutPrintWriter();
+            pw.println("Dropbox manager service commands:");
+            pw.println("  help");
+            pw.println("    Print this help text.");
+            pw.println("  set-rate-limit PERIOD");
+            pw.println("    Sets low priority broadcast rate limit period to PERIOD ms");
+            pw.println("  add-low-priority TAG");
+            pw.println("    Add TAG to dropbox low priority list");
+            pw.println("  remove-low-priority TAG");
+            pw.println("    Remove TAG from dropbox low priority list");
+            pw.println("  restore-defaults");
+            pw.println("    restore dropbox settings to defaults");
+        }
+    }
+
+    private class DropBoxManagerBroadcastHandler extends Handler {
+        private final Object mLock = new Object();
+
+        static final int MSG_SEND_BROADCAST = 1;
+        static final int MSG_SEND_DEFERRED_BROADCAST = 2;
+
+        @GuardedBy("mLock")
+        private final ArrayMap<String, Intent> mDeferredMap = new ArrayMap();
+
+        DropBoxManagerBroadcastHandler(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_SEND_BROADCAST:
+                    prepareAndSendBroadcast((Intent) msg.obj);
+                    break;
+                case MSG_SEND_DEFERRED_BROADCAST:
+                    Intent deferredIntent;
+                    synchronized (mLock) {
+                        deferredIntent = mDeferredMap.remove((String) msg.obj);
+                    }
+                    if (deferredIntent != null) {
+                        prepareAndSendBroadcast(deferredIntent);
+                    }
+                    break;
+            }
+        }
+
+        private void prepareAndSendBroadcast(Intent intent) {
+            if (!DropBoxManagerService.this.mBooted) {
+                intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
+            }
+            getContext().sendBroadcastAsUser(intent, UserHandle.SYSTEM,
+                    android.Manifest.permission.READ_LOGS);
+        }
+
+        private Intent createIntent(String tag, long time) {
+            final Intent dropboxIntent = new Intent(DropBoxManager.ACTION_DROPBOX_ENTRY_ADDED);
+            dropboxIntent.putExtra(DropBoxManager.EXTRA_TAG, tag);
+            dropboxIntent.putExtra(DropBoxManager.EXTRA_TIME, time);
+            return dropboxIntent;
+        }
+
+        /**
+         * Schedule a dropbox broadcast to be sent asynchronously.
+         */
+        public void sendBroadcast(String tag, long time) {
+            sendMessage(obtainMessage(MSG_SEND_BROADCAST, createIntent(tag, time)));
+        }
+
+        /**
+         * Possibly schedule a delayed dropbox broadcast. The broadcast will only be scheduled if
+         * no broadcast is currently scheduled. Otherwise updated the scheduled broadcast with the
+         * new intent information, effectively dropping the previous broadcast.
+         */
+        public void maybeDeferBroadcast(String tag, long time) {
+            synchronized (mLock) {
+                final Intent intent = mDeferredMap.get(tag);
+                if (intent == null) {
+                    // Schedule new delayed broadcast.
+                    mDeferredMap.put(tag, createIntent(tag, time));
+                    sendMessageDelayed(obtainMessage(MSG_SEND_DEFERRED_BROADCAST, tag),
+                            mLowPriorityRateLimitPeriod);
+                } else {
+                    // Broadcast is already scheduled. Update intent with new data.
+                    intent.putExtra(DropBoxManager.EXTRA_TIME, time);
+                    final int dropped = intent.getIntExtra(DropBoxManager.EXTRA_DROPPED_COUNT, 0);
+                    intent.putExtra(DropBoxManager.EXTRA_DROPPED_COUNT, dropped + 1);
+                    return;
+                }
+            }
+        }
+    }
+
     /**
      * Creates an instance of managed drop box storage using the default dropbox
      * directory.
@@ -176,15 +317,7 @@
         super(context);
         mDropBoxDir = path;
         mContentResolver = getContext().getContentResolver();
-        mHandler = new Handler(looper) {
-            @Override
-            public void handleMessage(Message msg) {
-                if (msg.what == MSG_SEND_BROADCAST) {
-                    getContext().sendBroadcastAsUser((Intent)msg.obj, UserHandle.SYSTEM,
-                            android.Manifest.permission.READ_LOGS);
-                }
-            }
-        };
+        mHandler = new DropBoxManagerBroadcastHandler(looper);
     }
 
     @Override
@@ -211,6 +344,8 @@
                             mReceiver.onReceive(getContext(), (Intent) null);
                         }
                     });
+
+                getLowPriorityResourceConfigs();
                 break;
 
             case PHASE_BOOT_COMPLETED:
@@ -298,17 +433,16 @@
             long time = createEntry(temp, tag, flags);
             temp = null;
 
-            final Intent dropboxIntent = new Intent(DropBoxManager.ACTION_DROPBOX_ENTRY_ADDED);
-            dropboxIntent.putExtra(DropBoxManager.EXTRA_TAG, tag);
-            dropboxIntent.putExtra(DropBoxManager.EXTRA_TIME, time);
-            if (!mBooted) {
-                dropboxIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
-            }
             // Call sendBroadcast after returning from this call to avoid deadlock. In particular
             // the caller may be holding the WindowManagerService lock but sendBroadcast requires a
             // lock in ActivityManagerService. ActivityManagerService has been caught holding that
             // very lock while waiting for the WindowManagerService lock.
-            mHandler.sendMessage(mHandler.obtainMessage(MSG_SEND_BROADCAST, dropboxIntent));
+            if (mLowPriorityTags != null && mLowPriorityTags.contains(tag)) {
+                // Rate limit low priority Dropbox entries
+                mHandler.maybeDeferBroadcast(tag, time);
+            } else {
+                mHandler.sendBroadcast(tag, time);
+            }
         } catch (IOException e) {
             Slog.e(TAG, "Can't write: " + tag, e);
         } finally {
@@ -382,6 +516,22 @@
         return null;
     }
 
+    private synchronized void setLowPriorityRateLimit(long period) {
+        mLowPriorityRateLimitPeriod = period;
+    }
+
+    private synchronized void addLowPriorityTag(String tag) {
+        mLowPriorityTags.add(tag);
+    }
+
+    private synchronized void removeLowPriorityTag(String tag) {
+        mLowPriorityTags.remove(tag);
+    }
+
+    private synchronized void restoreDefaults() {
+        getLowPriorityResourceConfigs();
+    }
+
     public synchronized void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         if (!DumpUtils.checkDumpAndUsageStatsPermission(getContext(), TAG, pw)) return;
 
@@ -421,6 +571,10 @@
         out.append("Drop box contents: ").append(mAllFiles.contents.size()).append(" entries\n");
         out.append("Max entries: ").append(mMaxFiles).append("\n");
 
+        out.append("Low priority rate limit period: ");
+        out.append(mLowPriorityRateLimitPeriod).append(" ms\n");
+        out.append("Low priority tags: ").append(mLowPriorityTags).append("\n");
+
         if (!searchArgs.isEmpty()) {
             out.append("Searching for:");
             for (String a : searchArgs) out.append(" ").append(a);
@@ -936,4 +1090,21 @@
 
         return mCachedQuotaBlocks * mBlockSize;
     }
+
+    private void getLowPriorityResourceConfigs() {
+        mLowPriorityRateLimitPeriod = Resources.getSystem().getInteger(
+                R.integer.config_dropboxLowPriorityBroadcastRateLimitPeriod);
+
+        final String[] lowPrioritytags = Resources.getSystem().getStringArray(
+                R.array.config_dropboxLowPriorityTags);
+        final int size = lowPrioritytags.length;
+        if (size == 0) {
+            mLowPriorityTags = null;
+            return;
+        }
+        mLowPriorityTags = new ArraySet(size);
+        for (int i = 0; i < size; i++) {
+            mLowPriorityTags.add(lowPrioritytags[i]);
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index f0244c3..2ded1e5 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -200,8 +200,8 @@
     private GnssMeasurementCorrectionsProvider mGnssMeasurementCorrectionsProvider;
     private GnssNavigationMessageProvider mGnssNavigationMessageProvider;
     @GuardedBy("mLock")
-    private String mLocationControllerExtraPackage;
-    private boolean mLocationControllerExtraPackageEnabled;
+    private String mExtraLocationControllerPackage;
+    private boolean mExtraLocationControllerPackageEnabled;
     private IGpsGeofenceHardware mGpsGeofenceProxy;
 
     // list of currently active providers
@@ -3045,35 +3045,35 @@
     }
 
     @Override
-    public void setLocationControllerExtraPackage(String packageName) {
+    public void setExtraLocationControllerPackage(String packageName) {
         mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
                 Manifest.permission.LOCATION_HARDWARE + " permission required");
         synchronized (mLock) {
-            mLocationControllerExtraPackage = packageName;
+            mExtraLocationControllerPackage = packageName;
         }
     }
 
     @Override
-    public String getLocationControllerExtraPackage() {
+    public String getExtraLocationControllerPackage() {
         synchronized (mLock) {
-            return mLocationControllerExtraPackage;
+            return mExtraLocationControllerPackage;
         }
     }
 
     @Override
-    public void setLocationControllerExtraPackageEnabled(boolean enabled) {
+    public void setExtraLocationControllerPackageEnabled(boolean enabled) {
         mContext.enforceCallingPermission(Manifest.permission.LOCATION_HARDWARE,
                 Manifest.permission.LOCATION_HARDWARE + " permission required");
         synchronized (mLock) {
-            mLocationControllerExtraPackageEnabled = enabled;
+            mExtraLocationControllerPackageEnabled = enabled;
         }
     }
 
     @Override
-    public boolean isLocationControllerExtraPackageEnabled() {
+    public boolean isExtraLocationControllerPackageEnabled() {
         synchronized (mLock) {
-            return mLocationControllerExtraPackageEnabled
-                    && (mLocationControllerExtraPackage != null);
+            return mExtraLocationControllerPackageEnabled
+                    && (mExtraLocationControllerPackage != null);
         }
     }
 
@@ -3610,9 +3610,9 @@
                 pw.println("  mBlacklist=null");
             }
 
-            if (mLocationControllerExtraPackage != null) {
-                pw.println(" Location controller extra package: " + mLocationControllerExtraPackage
-                        + " enabled: " + mLocationControllerExtraPackageEnabled);
+            if (mExtraLocationControllerPackage != null) {
+                pw.println(" Location controller extra package: " + mExtraLocationControllerPackage
+                        + " enabled: " + mExtraLocationControllerPackageEnabled);
             }
 
             if (!mBackgroundThrottlePackageWhitelist.isEmpty()) {
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 61a7182..d1ae284 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -1610,20 +1610,6 @@
     }
 
     @Override
-    public void setDnsConfigurationForNetwork(int netId, String[] servers, String[] domains,
-                    int[] params, String tlsHostname, String[] tlsServers) {
-        mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
-
-        final String[] tlsFingerprints = new String[0];
-        try {
-            mNetdService.setResolverConfiguration(
-                    netId, servers, domains, params, tlsHostname, tlsServers, tlsFingerprints);
-        } catch (RemoteException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
-    @Override
     public void addVpnUidRanges(int netId, UidRange[] ranges) {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
 
@@ -2082,21 +2068,6 @@
     }
 
     @Override
-    public void removeNetwork(int netId) {
-        mContext.enforceCallingOrSelfPermission(NETWORK_STACK, TAG);
-
-        try {
-            mNetdService.networkDestroy(netId);
-        } catch (ServiceSpecificException e) {
-            Log.w(TAG, "removeNetwork(" + netId + "): ", e);
-            throw e;
-        } catch (RemoteException e) {
-            Log.w(TAG, "removeNetwork(" + netId + "): ", e);
-            throw e.rethrowAsRuntimeException();
-        }
-    }
-
-    @Override
     public void addInterfaceToNetwork(String iface, int netId) {
         modifyInterfaceInNetwork(MODIFY_OPERATION_ADD, netId, iface);
     }
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 5b9c1f8..1a842f7 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -17,10 +17,14 @@
 package com.android.server;
 
 import static android.Manifest.permission.INSTALL_PACKAGES;
+import static android.Manifest.permission.READ_EXTERNAL_STORAGE;
+import static android.Manifest.permission.WRITE_EXTERNAL_STORAGE;
 import static android.Manifest.permission.WRITE_MEDIA_STORAGE;
 import static android.app.AppOpsManager.MODE_ALLOWED;
 import static android.app.AppOpsManager.OP_LEGACY_STORAGE;
+import static android.app.AppOpsManager.OP_READ_EXTERNAL_STORAGE;
 import static android.app.AppOpsManager.OP_REQUEST_INSTALL_PACKAGES;
+import static android.app.AppOpsManager.OP_WRITE_EXTERNAL_STORAGE;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_HIDDEN;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
 import static android.content.pm.PackageManager.GET_PERMISSIONS;
@@ -280,6 +284,7 @@
     private static final boolean EMULATE_FBE_SUPPORTED = true;
 
     private static final String TAG = "StorageManagerService";
+    private static final boolean LOCAL_LOGV = Log.isLoggable(TAG, Log.VERBOSE);
 
     private static final String TAG_STORAGE_BENCHMARK = "storage_benchmark";
     private static final String TAG_STORAGE_TRIM = "storage_trim";
@@ -3863,44 +3868,57 @@
     }
 
     private int getMountMode(int uid, String packageName) {
+        final int mode = getMountModeInternal(uid, packageName);
+        if (LOCAL_LOGV) {
+            Slog.v(TAG, "Resolved mode " + mode + " for " + packageName + "/"
+                    + UserHandle.formatUid(uid));
+        }
+        return mode;
+    }
+
+    private int getMountModeInternal(int uid, String packageName) {
         try {
+            // Get some easy cases out of the way first
             if (Process.isIsolated(uid)) {
                 return Zygote.MOUNT_EXTERNAL_NONE;
             }
-            if (mIPackageManager.checkUidPermission(WRITE_MEDIA_STORAGE, uid)
-                    == PERMISSION_GRANTED) {
-                return Zygote.MOUNT_EXTERNAL_FULL;
-            } else if (mIAppOpsService.checkOperation(OP_LEGACY_STORAGE, uid,
-                    packageName) == MODE_ALLOWED) {
-                return Zygote.MOUNT_EXTERNAL_LEGACY;
-            } else if (mIPackageManager.checkUidPermission(INSTALL_PACKAGES, uid)
-                    == PERMISSION_GRANTED || mIAppOpsService.checkOperation(
-                            OP_REQUEST_INSTALL_PACKAGES, uid, packageName) == MODE_ALLOWED) {
-                return Zygote.MOUNT_EXTERNAL_INSTALLER;
-            } else if (mPmInternal.isInstantApp(packageName, UserHandle.getUserId(uid))) {
+            if (mPmInternal.isInstantApp(packageName, UserHandle.getUserId(uid))) {
                 return Zygote.MOUNT_EXTERNAL_NONE;
+            }
+
+            // Determine if caller is holding runtime permission
+            final boolean hasRead = StorageManager.checkPermissionAndAppOp(mContext, false, 0,
+                    uid, packageName, READ_EXTERNAL_STORAGE, OP_READ_EXTERNAL_STORAGE);
+            final boolean hasWrite = StorageManager.checkPermissionAndAppOp(mContext, false, 0,
+                    uid, packageName, WRITE_EXTERNAL_STORAGE, OP_WRITE_EXTERNAL_STORAGE);
+            final boolean hasStorage = hasRead || hasWrite;
+
+            // We're only willing to give out broad access if they also hold
+            // runtime permission; this is a firm CDD requirement
+            final boolean hasFull = mIPackageManager.checkUidPermission(WRITE_MEDIA_STORAGE,
+                    uid) == PERMISSION_GRANTED;
+            if (hasFull && hasStorage) {
+                return Zygote.MOUNT_EXTERNAL_FULL;
+            }
+
+            // We're only willing to give out installer access if they also hold
+            // runtime permission; this is a firm CDD requirement
+            final boolean hasInstall = mIPackageManager.checkUidPermission(INSTALL_PACKAGES,
+                    uid) == PERMISSION_GRANTED;
+            final boolean hasInstallOp = mIAppOpsService.checkOperation(OP_REQUEST_INSTALL_PACKAGES,
+                    uid, packageName) == MODE_ALLOWED;
+            if ((hasInstall || hasInstallOp) && hasStorage) {
+                return Zygote.MOUNT_EXTERNAL_INSTALLER;
+            }
+
+            // Otherwise we're willing to give out sandboxed or non-sandboxed if
+            // they hold the runtime permission
+            final boolean hasLegacy = mIAppOpsService.checkOperation(OP_LEGACY_STORAGE,
+                    uid, packageName) == MODE_ALLOWED;
+            final boolean hasGreylist = isLegacyGreylisted(packageName);
+            if ((hasLegacy || hasGreylist) && hasStorage) {
+                return Zygote.MOUNT_EXTERNAL_LEGACY;
             } else {
-                if (ENABLE_LEGACY_GREYLIST) {
-                    // STOPSHIP: remove this temporary workaround once developers
-                    // fix bugs where they're opening _data paths in native code
-                    switch (packageName) {
-                        case "com.facebook.katana": // b/123996076
-                        case "jp.naver.line.android": // b/124767356
-                        case "com.mxtech.videoplayer.ad": // b/124531483
-                        case "com.whatsapp": // b/124766614
-                        case "com.maxmpz.audioplayer": // b/127886230
-                        case "com.estrongs.android.pop": // b/127926473
-                        case "com.roidapp.photogrid": // b/128269119
-                        case "com.cleanmaster.mguard": // b/128384413
-                        case "com.skype.raider": // b/128487044
-                        case "org.telegram.messenger": // b/128652960
-                        case "com.jrtstudio.AnotherMusicPlayer": // b/129084562
-                        case "ak.alizandro.smartaudiobookplayer": // b/129084042
-                        case "com.campmobile.snow": // b/128803870
-                        case "com.qnap.qfile": // b/126374406
-                            return Zygote.MOUNT_EXTERNAL_LEGACY;
-                    }
-                }
                 return Zygote.MOUNT_EXTERNAL_WRITE;
             }
         } catch (RemoteException e) {
@@ -3909,6 +3927,32 @@
         return Zygote.MOUNT_EXTERNAL_NONE;
     }
 
+    private boolean isLegacyGreylisted(String packageName) {
+        // TODO: decide legacy defaults at install time based on signals
+        if (ENABLE_LEGACY_GREYLIST) {
+            // STOPSHIP: remove this temporary workaround once developers
+            // fix bugs where they're opening _data paths in native code
+            switch (packageName) {
+                case "com.facebook.katana": // b/123996076
+                case "jp.naver.line.android": // b/124767356
+                case "com.mxtech.videoplayer.ad": // b/124531483
+                case "com.whatsapp": // b/124766614
+                case "com.maxmpz.audioplayer": // b/127886230
+                case "com.estrongs.android.pop": // b/127926473
+                case "com.roidapp.photogrid": // b/128269119
+                case "com.cleanmaster.mguard": // b/128384413
+                case "com.skype.raider": // b/128487044
+                case "org.telegram.messenger": // b/128652960
+                case "com.jrtstudio.AnotherMusicPlayer": // b/129084562
+                case "ak.alizandro.smartaudiobookplayer": // b/129084042
+                case "com.campmobile.snow": // b/128803870
+                case "com.qnap.qfile": // b/126374406
+                    return true;
+            }
+        }
+        return false;
+    }
+
     private static class Callbacks extends Handler {
         private static final int MSG_STORAGE_STATE_CHANGED = 1;
         private static final int MSG_VOLUME_STATE_CHANGED = 2;
diff --git a/services/core/java/com/android/server/TEST_MAPPING b/services/core/java/com/android/server/TEST_MAPPING
index 1870f8d..5522396 100644
--- a/services/core/java/com/android/server/TEST_MAPPING
+++ b/services/core/java/com/android/server/TEST_MAPPING
@@ -5,6 +5,9 @@
             "file_patterns": ["AlarmManagerService\\.java"],
             "options": [
                 {
+                  "include-filter": "com.android.server."
+                },
+                {
                   "include-annotation": "android.platform.test.annotations.Presubmit"
                 },
                 {
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 8b10267..73e0439 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -627,11 +627,6 @@
                 r.callingPackage = callingPackage;
                 r.callerUid = Binder.getCallingUid();
                 r.callerPid = Binder.getCallingPid();
-                if (r.subId != SubscriptionManager.INVALID_SUBSCRIPTION_ID && r.subId != subId) {
-                    throw new IllegalArgumentException(
-                            "PhoneStateListener cannot concurrently listen on multiple " +
-                                    "subscriptions. Previously registered on subId: " + r.subId);
-                }
                 // Legacy applications pass SubscriptionManager.DEFAULT_SUB_ID,
                 // force all illegal subId to SubscriptionManager.DEFAULT_SUB_ID
                 if (!SubscriptionManager.isValidSubscriptionId(subId)) {
diff --git a/services/core/java/com/android/server/adb/AdbDebuggingManager.java b/services/core/java/com/android/server/adb/AdbDebuggingManager.java
index 8ccb6e2..9325d25 100644
--- a/services/core/java/com/android/server/adb/AdbDebuggingManager.java
+++ b/services/core/java/com/android/server/adb/AdbDebuggingManager.java
@@ -307,7 +307,6 @@
                     }
 
                     cancelJobToUpdateAdbKeyStore();
-                    mAdbKeyStore = null;
                     mConnectedKey = null;
                     break;
 
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 1878d00..261ed4c 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -1478,7 +1478,6 @@
             if (sr.isForeground || sr.fgRequired) {
                 anyForeground = true;
                 fgServiceTypes |= sr.foregroundServiceType;
-                break;
             }
         }
         mAm.updateProcessForegroundLocked(proc, anyForeground, fgServiceTypes, oomAdj);
@@ -1525,8 +1524,9 @@
         boolean anyClientActivities = false;
         for (int i=proc.services.size()-1; i>=0 && !anyClientActivities; i--) {
             ServiceRecord sr = proc.services.valueAt(i);
-            for (int conni=sr.connections.size()-1; conni>=0 && !anyClientActivities; conni--) {
-                ArrayList<ConnectionRecord> clist = sr.connections.valueAt(conni);
+            ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections = sr.getConnections();
+            for (int conni = connections.size() - 1; conni >= 0 && !anyClientActivities; conni--) {
+                ArrayList<ConnectionRecord> clist = connections.valueAt(conni);
                 for (int cri=clist.size()-1; cri>=0; cri--) {
                     ConnectionRecord cr = clist.get(cri);
                     if (cr.binding.client == null || cr.binding.client == proc) {
@@ -1753,10 +1753,10 @@
                     callerApp.uid, callerApp.processName, callingPackage);
 
             IBinder binder = connection.asBinder();
-            ArrayList<ConnectionRecord> clist = s.connections.get(binder);
+            ArrayList<ConnectionRecord> clist = s.getConnections().get(binder);
             if (clist == null) {
                 clist = new ArrayList<ConnectionRecord>();
-                s.connections.put(binder, clist);
+                s.putConnection(binder, clist);
             }
             clist.add(c);
             b.connections.add(c);
@@ -1856,8 +1856,9 @@
                     b.binder = service;
                     b.requested = true;
                     b.received = true;
-                    for (int conni=r.connections.size()-1; conni>=0; conni--) {
-                        ArrayList<ConnectionRecord> clist = r.connections.valueAt(conni);
+                    ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections = r.getConnections();
+                    for (int conni = connections.size() - 1; conni >= 0; conni--) {
+                        ArrayList<ConnectionRecord> clist = connections.valueAt(conni);
                         for (int i=0; i<clist.size(); i++) {
                             ConnectionRecord c = clist.get(i);
                             if (!filter.equals(c.binding.intent.intent)) {
@@ -2723,6 +2724,10 @@
 
         updateServiceClientActivitiesLocked(app, null, true);
 
+        if (newService && created) {
+            app.addBoundClientUidsOfNewService(r);
+        }
+
         // If the service is in the started state, and there are no
         // pending arguments, then fake up one so its onStartCommand() will
         // be called.
@@ -2882,8 +2887,9 @@
 
         // Report to all of the connections that the service is no longer
         // available.
-        for (int conni=r.connections.size()-1; conni>=0; conni--) {
-            ArrayList<ConnectionRecord> c = r.connections.valueAt(conni);
+        ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections = r.getConnections();
+        for (int conni = connections.size() - 1; conni >= 0; conni--) {
+            ArrayList<ConnectionRecord> c = connections.valueAt(conni);
             for (int i=0; i<c.size(); i++) {
                 ConnectionRecord cr = c.get(i);
                 // There is still a connection to the service that is
@@ -3014,6 +3020,7 @@
                 r.stats.stopLaunchedLocked();
             }
             r.app.services.remove(r);
+            r.app.updateBoundClientUids();
             if (r.whitelistManager) {
                 updateWhitelistManagerLocked(r.app);
             }
@@ -3066,11 +3073,11 @@
         IBinder binder = c.conn.asBinder();
         AppBindRecord b = c.binding;
         ServiceRecord s = b.service;
-        ArrayList<ConnectionRecord> clist = s.connections.get(binder);
+        ArrayList<ConnectionRecord> clist = s.getConnections().get(binder);
         if (clist != null) {
             clist.remove(c);
             if (clist.size() == 0) {
-                s.connections.remove(binder);
+                s.removeConnection(binder);
             }
         }
         b.connections.remove(c);
@@ -3295,6 +3302,7 @@
             if (finishing) {
                 if (r.app != null && !r.app.isPersistent()) {
                     r.app.services.remove(r);
+                    r.app.updateBoundClientUids();
                     if (r.whitelistManager) {
                         updateWhitelistManagerLocked(r.app);
                     }
@@ -3390,6 +3398,7 @@
                 Slog.i(TAG, "  Force stopping service " + service);
                 if (service.app != null && !service.app.isPersistent()) {
                     service.app.services.remove(service);
+                    service.app.updateBoundClientUids();
                     if (service.whitelistManager) {
                         updateWhitelistManagerLocked(service.app);
                     }
@@ -3505,8 +3514,9 @@
                 Iterator<ServiceRecord> it = app.services.iterator();
                 while (it.hasNext()) {
                     ServiceRecord r = it.next();
-                    for (int conni=r.connections.size()-1; conni>=0; conni--) {
-                        ArrayList<ConnectionRecord> cl = r.connections.valueAt(conni);
+                    ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections = r.getConnections();
+                    for (int conni=connections.size()-1; conni>=0; conni--) {
+                        ArrayList<ConnectionRecord> cl = connections.valueAt(conni);
                         for (int i=0; i<cl.size(); i++) {
                             ConnectionRecord c = cl.get(i);
                             if (c.binding.client != app) {
@@ -3543,6 +3553,7 @@
             }
             if (sr.app != app && sr.app != null && !sr.app.isPersistent()) {
                 sr.app.services.remove(sr);
+                sr.app.updateBoundClientUids();
             }
             sr.setProcess(null);
             sr.isolatedProc = null;
@@ -3606,6 +3617,7 @@
             // so make sure the service is cleaned out of it.
             if (!app.isPersistent()) {
                 app.services.removeAt(i);
+                app.updateBoundClientUids();
             }
 
             // Sanity check: if the service listed for the app is not one
@@ -3656,6 +3668,7 @@
 
         if (!allowRestart) {
             app.services.clear();
+            app.clearBoundClientUids();
 
             // Make sure there are no more restarting services for this process.
             for (int i=mRestartingServices.size()-1; i>=0; i--) {
@@ -3702,7 +3715,7 @@
         info.foreground = r.isForeground;
         info.activeSince = r.createRealTime;
         info.started = r.startRequested;
-        info.clientCount = r.connections.size();
+        info.clientCount = r.getConnections().size();
         info.crashCount = r.crashCount;
         info.lastActivityTime = r.lastActivity;
         if (r.isForeground) {
@@ -3718,8 +3731,9 @@
             info.flags |= ActivityManager.RunningServiceInfo.FLAG_PERSISTENT_PROCESS;
         }
 
-        for (int conni=r.connections.size()-1; conni>=0; conni--) {
-            ArrayList<ConnectionRecord> connl = r.connections.valueAt(conni);
+        ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections = r.getConnections();
+        for (int conni = connections.size() - 1; conni >= 0; conni--) {
+            ArrayList<ConnectionRecord> connl = connections.valueAt(conni);
             for (int i=0; i<connl.size(); i++) {
                 ConnectionRecord conn = connl.get(i);
                 if (conn.clientLabel != 0) {
@@ -3788,9 +3802,10 @@
     public PendingIntent getRunningServiceControlPanelLocked(ComponentName name) {
         int userId = UserHandle.getUserId(Binder.getCallingUid());
         ServiceRecord r = getServiceByNameLocked(name, userId);
+        ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections = r.getConnections();
         if (r != null) {
-            for (int conni=r.connections.size()-1; conni>=0; conni--) {
-                ArrayList<ConnectionRecord> conn = r.connections.valueAt(conni);
+            for (int conni = connections.size() - 1; conni >= 0; conni--) {
+                ArrayList<ConnectionRecord> conn = connections.valueAt(conni);
                 for (int i=0; i<conn.size(); i++) {
                     if (conn.get(i).clientIntent != null) {
                         return conn.get(i).clientIntent;
@@ -4081,11 +4096,12 @@
                 pw.print(" started=");
                 pw.print(r.startRequested);
                 pw.print(" connections=");
-                pw.println(r.connections.size());
-                if (r.connections.size() > 0) {
+                ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections = r.getConnections();
+                pw.println(connections.size());
+                if (connections.size() > 0) {
                     pw.println("    Connections:");
-                    for (int conni=0; conni<r.connections.size(); conni++) {
-                        ArrayList<ConnectionRecord> clist = r.connections.valueAt(conni);
+                    for (int conni = 0; conni < connections.size(); conni++) {
+                        ArrayList<ConnectionRecord> clist = connections.valueAt(conni);
                         for (int i = 0; i < clist.size(); i++) {
                             ConnectionRecord conn = clist.get(i);
                             pw.print("      ");
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 9926de5..05ec954 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -271,6 +271,7 @@
 import android.os.WorkSource;
 import android.os.storage.IStorageManager;
 import android.os.storage.StorageManager;
+import android.provider.DeviceConfig;
 import android.provider.Settings;
 import android.sysprop.VoldProperties;
 import android.text.TextUtils;
@@ -1266,6 +1267,7 @@
     String mMemWatchDumpFile;
     int mMemWatchDumpPid;
     int mMemWatchDumpUid;
+    private boolean mMemWatchIsUserInitiated;
     String mTrackAllocationApp = null;
     String mNativeDebuggingApp = null;
 
@@ -1712,9 +1714,14 @@
                 final int uid;
                 final long memLimit;
                 final String reportPackage;
+                final boolean isUserInitiated;
                 synchronized (ActivityManagerService.this) {
-                    procName = mMemWatchDumpProcName;
                     uid = mMemWatchDumpUid;
+                    if (uid == SYSTEM_UID) {
+                        procName = mContext.getString(R.string.android_system_label);
+                    } else {
+                        procName = mMemWatchDumpProcName;
+                    }
                     Pair<Long, String> val = mMemWatchProcesses.get(procName, uid);
                     if (val == null) {
                         val = mMemWatchProcesses.get(procName, 0);
@@ -1726,6 +1733,7 @@
                         memLimit = 0;
                         reportPackage = null;
                     }
+                    isUserInitiated = mMemWatchIsUserInitiated;
                 }
                 if (procName == null) {
                     return;
@@ -1739,8 +1747,9 @@
                     return;
                 }
 
-                String text = mContext.getString(R.string.dump_heap_notification, procName);
-
+                final int titleId = isUserInitiated
+                        ? R.string.dump_heap_ready_notification : R.string.dump_heap_notification;
+                String text = mContext.getString(titleId, procName);
 
                 Intent deleteIntent = new Intent();
                 deleteIntent.setAction(DumpHeapActivity.ACTION_DELETE_DUMPHEAP);
@@ -1748,6 +1757,8 @@
                 intent.setClassName("android", DumpHeapActivity.class.getName());
                 intent.putExtra(DumpHeapActivity.KEY_PROCESS, procName);
                 intent.putExtra(DumpHeapActivity.KEY_SIZE, memLimit);
+                intent.putExtra(DumpHeapActivity.KEY_IS_USER_INITIATED, isUserInitiated);
+                intent.putExtra(DumpHeapActivity.KEY_IS_SYSTEM_PROCESS, uid == SYSTEM_UID);
                 if (reportPackage != null) {
                     intent.putExtra(DumpHeapActivity.KEY_DIRECT_LAUNCH, reportPackage);
                 }
@@ -1755,8 +1766,6 @@
                 Notification notification =
                         new Notification.Builder(mContext, SystemNotificationChannels.DEVELOPER)
                         .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
-                        .setWhen(0)
-                        .setOngoing(true)
                         .setAutoCancel(true)
                         .setTicker(text)
                         .setColor(mContext.getColor(
@@ -2143,7 +2152,8 @@
      * Encapsulates global settings related to hidden API enforcement behaviour, including tracking
      * the latest value via a content observer.
      */
-    static class HiddenApiSettings extends ContentObserver {
+    static class HiddenApiSettings extends ContentObserver
+            implements DeviceConfig.OnPropertiesChangedListener {
 
         private final Context mContext;
         private boolean mBlacklistDisabled;
@@ -2153,6 +2163,45 @@
         private int mStatslogSampleRate = -1;
         @HiddenApiEnforcementPolicy private int mPolicy = HIDDEN_API_ENFORCEMENT_DEFAULT;
 
+        /**
+         * Sampling rate for hidden API access event logs with libmetricslogger, as an integer in
+         * the range 0 to 0x10000 inclusive.
+         *
+         * @hide
+         */
+        public static final String HIDDEN_API_ACCESS_LOG_SAMPLING_RATE =
+                "hidden_api_access_log_sampling_rate";
+
+        /**
+         * Sampling rate for hidden API access event logging with statslog, as an integer in the
+         * range 0 to 0x10000 inclusive.
+         *
+         * @hide
+         */
+        public static final String HIDDEN_API_ACCESS_STATSLOG_SAMPLING_RATE =
+                "hidden_api_access_statslog_sampling_rate";
+
+        public void onPropertiesChanged(DeviceConfig.Properties properties) {
+            int logSampleRate = properties.getInt(HIDDEN_API_ACCESS_LOG_SAMPLING_RATE, 0x0);
+            if (logSampleRate < 0 || logSampleRate > 0x10000) {
+                logSampleRate = -1;
+            }
+            if (logSampleRate != -1 && logSampleRate != mLogSampleRate) {
+                mLogSampleRate = logSampleRate;
+                ZYGOTE_PROCESS.setHiddenApiAccessLogSampleRate(mLogSampleRate);
+            }
+
+            int statslogSampleRate =
+                    properties.getInt(HIDDEN_API_ACCESS_STATSLOG_SAMPLING_RATE, 0);
+            if (statslogSampleRate < 0 || statslogSampleRate > 0x10000) {
+                statslogSampleRate = -1;
+            }
+            if (statslogSampleRate != -1 && statslogSampleRate != mStatslogSampleRate) {
+                mStatslogSampleRate = statslogSampleRate;
+                ZYGOTE_PROCESS.setHiddenApiAccessStatslogSampleRate(mStatslogSampleRate);
+            }
+        }
+
         public HiddenApiSettings(Handler handler, Context context) {
             super(handler);
             mContext = context;
@@ -2164,18 +2213,11 @@
                     false,
                     this);
             mContext.getContentResolver().registerContentObserver(
-                    Settings.Global.getUriFor(Settings.Global.HIDDEN_API_ACCESS_LOG_SAMPLING_RATE),
-                    false,
-                    this);
-            mContext.getContentResolver().registerContentObserver(
-                    Settings.Global.getUriFor(
-                        Settings.Global.HIDDEN_API_ACCESS_STATSLOG_SAMPLING_RATE),
-                    false,
-                    this);
-            mContext.getContentResolver().registerContentObserver(
                     Settings.Global.getUriFor(Settings.Global.HIDDEN_API_POLICY),
                     false,
                     this);
+            DeviceConfig.addOnPropertiesChangedListener(DeviceConfig.NAMESPACE_APP_COMPAT,
+                    mContext.getMainExecutor(), this);
             update();
         }
 
@@ -2199,24 +2241,6 @@
                   mExemptions = Collections.emptyList();
                 }
             }
-            int logSampleRate = Settings.Global.getInt(mContext.getContentResolver(),
-                    Settings.Global.HIDDEN_API_ACCESS_LOG_SAMPLING_RATE, 0x200);
-            if (logSampleRate < 0 || logSampleRate > 0x10000) {
-                logSampleRate = -1;
-            }
-            if (logSampleRate != -1 && logSampleRate != mLogSampleRate) {
-                mLogSampleRate = logSampleRate;
-                ZYGOTE_PROCESS.setHiddenApiAccessLogSampleRate(mLogSampleRate);
-            }
-            int statslogSampleRate = Settings.Global.getInt(mContext.getContentResolver(),
-                    Settings.Global.HIDDEN_API_ACCESS_STATSLOG_SAMPLING_RATE, 0);
-            if (statslogSampleRate < 0 || statslogSampleRate > 0x10000) {
-                statslogSampleRate = -1;
-            }
-            if (statslogSampleRate != -1 && statslogSampleRate != mStatslogSampleRate) {
-                mStatslogSampleRate = statslogSampleRate;
-                ZYGOTE_PROCESS.setHiddenApiAccessStatslogSampleRate(mStatslogSampleRate);
-            }
             mPolicy = getValidEnforcementPolicy(Settings.Global.HIDDEN_API_POLICY);
         }
 
@@ -3104,7 +3128,7 @@
     }
 
     @GuardedBy("this")
-    ProcessChangeItem enqueueProcessChangeItemLocked(int uid, int pid) {
+    ProcessChangeItem enqueueProcessChangeItemLocked(int pid, int uid) {
         int i = mPendingProcessChanges.size()-1;
         ActivityManagerService.ProcessChangeItem item = null;
         while (i >= 0) {
@@ -5066,11 +5090,9 @@
         mContext.registerReceiver(new BroadcastReceiver() {
             @Override
             public void onReceive(Context context, Intent intent) {
-                if (intent.getBooleanExtra(DumpHeapActivity.EXTRA_DELAY_DELETE, false)) {
-                    mHandler.sendEmptyMessageDelayed(POST_DUMP_HEAP_NOTIFICATION_MSG, 5*60*1000);
-                } else {
-                    mHandler.sendEmptyMessage(POST_DUMP_HEAP_NOTIFICATION_MSG);
-                }
+                final long delay = intent.getBooleanExtra(
+                        DumpHeapActivity.EXTRA_DELAY_DELETE, false) ? 5 * 60 * 1000 : 0;
+                mHandler.sendEmptyMessageDelayed(DELETE_DUMPHEAP_MSG, delay);
             }
         }, dumpheapFilter);
 
@@ -7940,6 +7962,30 @@
         }
     }
 
+    @Override
+    public void requestSystemServerHeapDump() {
+        if (!Build.IS_DEBUGGABLE) {
+            Slog.wtf(TAG, "requestSystemServerHeapDump called on a user build");
+            return;
+        }
+        if (Binder.getCallingUid() != SYSTEM_UID) {
+            // This also intentionally excludes secondary profiles from calling this.
+            throw new SecurityException(
+                    "Only the system process is allowed to request a system heap dump");
+        }
+        ProcessRecord pr;
+        synchronized (mPidsSelfLocked) {
+            pr = mPidsSelfLocked.get(myPid());
+        }
+        if (pr == null) {
+            Slog.w(TAG, "system process not in mPidsSelfLocked: " + myPid());
+            return;
+        }
+        synchronized (this) {
+            startHeapDumpLocked(pr, true);
+        }
+    }
+
     /**
      * @deprecated This method is only used by a few internal components and it will soon be
      * replaced by a proper bug report API (which will be restricted to a few, pre-defined apps).
@@ -8789,6 +8835,7 @@
         mAtmInternal.updateTopComponentForFactoryTest();
 
         retrieveSettings();
+        final int currentUserId = mUserController.getCurrentUserId();
         mUgmInternal.onSystemReady();
 
         final PowerManagerInternal pmi = LocalServices.getService(PowerManagerInternal.class);
@@ -8802,16 +8849,6 @@
         }
 
         if (goingCallback != null) goingCallback.run();
-        // Check the current user here as a user can be started inside goingCallback.run() from
-        // other system services.
-        final int currentUserId = mUserController.getCurrentUserId();
-        Slog.i(TAG, "Current user:" + currentUserId);
-        if (currentUserId != UserHandle.USER_SYSTEM && !mUserController.isSystemUserStarted()) {
-            // User other than system user has started. Make sure that system user is already
-            // started before switching user.
-            throw new RuntimeException("System user not started while current user is:"
-                    + currentUserId);
-        }
         traceLog.traceBegin("ActivityManagerStartApps");
         mBatteryStatsService.noteEvent(BatteryStats.HistoryItem.EVENT_USER_RUNNING_START,
                 Integer.toString(currentUserId), currentUserId);
@@ -10533,8 +10570,9 @@
             }
             pw.print("  mMemWatchDumpProcName="); pw.println(mMemWatchDumpProcName);
             pw.print("  mMemWatchDumpFile="); pw.println(mMemWatchDumpFile);
-            pw.print("  mMemWatchDumpPid="); pw.print(mMemWatchDumpPid);
-                    pw.print(" mMemWatchDumpUid="); pw.println(mMemWatchDumpUid);
+            pw.print("  mMemWatchDumpPid="); pw.println(mMemWatchDumpPid);
+            pw.print("  mMemWatchDumpUid="); pw.println(mMemWatchDumpUid);
+            pw.print("  mMemWatchIsUserInitiated="); pw.println(mMemWatchIsUserInitiated);
         }
         if (mTrackAllocationApp != null) {
             if (dumpPackage == null || dumpPackage.equals(mTrackAllocationApp)) {
@@ -10832,6 +10870,9 @@
             proto.write(ActivityManagerServiceDumpProcessesProto.MemWatchProcess.Dump.FILE, mMemWatchDumpFile);
             proto.write(ActivityManagerServiceDumpProcessesProto.MemWatchProcess.Dump.PID, mMemWatchDumpPid);
             proto.write(ActivityManagerServiceDumpProcessesProto.MemWatchProcess.Dump.UID, mMemWatchDumpUid);
+            proto.write(
+                    ActivityManagerServiceDumpProcessesProto.MemWatchProcess.Dump.IS_USER_INITIATED,
+                    mMemWatchIsUserInitiated);
             proto.end(dtoken);
 
             proto.end(token);
@@ -15929,14 +15970,7 @@
                 }
                 if (isDebuggable) {
                     Slog.w(TAG, "Process " + proc + " exceeded pss limit " + check + "; reporting");
-                    final ProcessRecord myProc = proc;
-                    final File heapdumpFile = DumpHeapProvider.getJavaFile();
-                    mMemWatchDumpProcName = proc.processName;
-                    mMemWatchDumpFile = heapdumpFile.toString();
-                    mMemWatchDumpPid = proc.pid;
-                    mMemWatchDumpUid = proc.uid;
-                    BackgroundThread.getHandler().post(
-                            new RecordPssRunnable(this, myProc, DumpHeapProvider.getJavaFile()));
+                    startHeapDumpLocked(proc, false);
                 } else {
                     Slog.w(TAG, "Process " + proc + " exceeded pss limit " + check
                             + ", but debugging not enabled");
@@ -15945,6 +15979,16 @@
         }
     }
 
+    private void startHeapDumpLocked(ProcessRecord proc, boolean isUserInitiated) {
+        final File heapdumpFile = DumpHeapProvider.getJavaFile();
+        mMemWatchDumpProcName = proc.processName;
+        mMemWatchDumpFile = heapdumpFile.toString();
+        mMemWatchDumpPid = proc.pid;
+        mMemWatchDumpUid = proc.uid;
+        mMemWatchIsUserInitiated = isUserInitiated;
+        BackgroundThread.getHandler().post(new RecordPssRunnable(this, proc, heapdumpFile));
+    }
+
     /**
      * Schedule PSS collection of a process.
      */
@@ -16340,12 +16384,10 @@
     @GuardedBy("this")
     final void updateProcessForegroundLocked(ProcessRecord proc, boolean isForeground,
             int fgServiceTypes, boolean oomAdj) {
-        proc.setHasForegroundServices(isForeground, fgServiceTypes);
 
-        final boolean hasFgServiceLocationType =
-                (fgServiceTypes & ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION) != 0;
         if (isForeground != proc.hasForegroundServices()
-                || proc.hasLocationForegroundServices() != hasFgServiceLocationType) {
+                || proc.getForegroundServiceTypes() != fgServiceTypes) {
+            proc.setHasForegroundServices(isForeground, fgServiceTypes);
             ArrayList<ProcessRecord> curProcs = mForegroundPackages.get(proc.info.packageName,
                     proc.info.uid);
             if (isForeground) {
@@ -16370,17 +16412,16 @@
                     }
                 }
             }
+
+            proc.setReportedForegroundServiceTypes(fgServiceTypes);
+            ProcessChangeItem item = enqueueProcessChangeItemLocked(proc.pid, proc.info.uid);
+            item.changes = ProcessChangeItem.CHANGE_FOREGROUND_SERVICES;
+            item.foregroundServiceTypes = fgServiceTypes;
+
             if (oomAdj) {
                 updateOomAdjLocked();
             }
         }
-
-        if (proc.getForegroundServiceTypes() != fgServiceTypes) {
-            proc.setReportedForegroundServiceTypes(fgServiceTypes);
-            ProcessChangeItem item = enqueueProcessChangeItemLocked(proc.info.uid, proc.pid);
-            item.changes = ProcessChangeItem.CHANGE_FOREGROUND_SERVICES;
-            item.foregroundServiceTypes = fgServiceTypes;
-        }
     }
 
     // TODO(b/111541062): This method is only used for updating OOM adjustments. We need to update
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index ea23081..4bfbb78e 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -460,10 +460,9 @@
                 // that request - we don't want the token to be swept from under our feet...
                 mHandler.removeCallbacksAndMessages(msgToken);
                 // ...then schedule the removal of the token after the extended timeout
+                final ProcessRecord app = r.curApp;
                 mHandler.postAtTime(() -> {
-                    if (r.curApp != null) {
-                        r.curApp.removeAllowBackgroundActivityStartsToken(r);
-                    }
+                    app.removeAllowBackgroundActivityStartsToken(r);
                 }, msgToken, (r.receiverTime + mConstants.ALLOW_BG_ACTIVITY_START_TIMEOUT));
             }
         }
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index c1b9a20..924e331 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -53,12 +53,14 @@
 import android.content.Context;
 import android.os.Binder;
 import android.os.Debug;
+import android.os.IBinder;
 import android.os.PowerManagerInternal;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.Trace;
 import android.os.UserHandle;
+import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Slog;
 import android.util.proto.ProtoOutputStream;
@@ -1110,12 +1112,13 @@
                 }
             }
 
-            for (int conni = s.connections.size() - 1;
+            ArrayMap<IBinder, ArrayList<ConnectionRecord>> serviceConnections = s.getConnections();
+            for (int conni = serviceConnections.size() - 1;
                     conni >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
                             || schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
                             || procState > ActivityManager.PROCESS_STATE_TOP);
                     conni--) {
-                ArrayList<ConnectionRecord> clist = s.connections.valueAt(conni);
+                ArrayList<ConnectionRecord> clist = serviceConnections.valueAt(conni);
                 for (int i = 0;
                         i < clist.size() && (adj > ProcessList.FOREGROUND_APP_ADJ
                                 || schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 17b244c..ce13cd8 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -259,6 +259,8 @@
     // A set of tokens that currently contribute to this process being temporarily whitelisted
     // to start activities even if it's not in the foreground
     final ArraySet<Binder> mAllowBackgroundActivityStartsTokens = new ArraySet<>();
+    // a set of UIDs of all bound clients
+    private ArraySet<Integer> mBoundClientUids = new ArraySet<>();
 
     String isolatedEntryPoint;  // Class to run on start if this is a special isolated process.
     String[] isolatedEntryPointArgs; // Arguments to pass to isolatedEntryPoint's main().
@@ -561,6 +563,13 @@
                 pw.print(prefix); pw.print("  - "); pw.println(receivers.valueAt(i));
             }
         }
+        if (mAllowBackgroundActivityStartsTokens.size() > 0) {
+            pw.print(prefix); pw.println("Background activity start whitelist tokens:");
+            for (int i = 0; i < mAllowBackgroundActivityStartsTokens.size(); i++) {
+                pw.print(prefix); pw.print("  - ");
+                pw.println(mAllowBackgroundActivityStartsTokens.valueAt(i));
+            }
+        }
     }
 
     ProcessRecord(ActivityManagerService _service, ApplicationInfo _info, String _processName,
@@ -1186,6 +1195,53 @@
                 !mAllowBackgroundActivityStartsTokens.isEmpty());
     }
 
+    void addBoundClientUids(ArraySet<Integer> clientUids) {
+        mBoundClientUids.addAll(clientUids);
+        mWindowProcessController.setBoundClientUids(mBoundClientUids);
+    }
+
+    void updateBoundClientUids() {
+        if (services.isEmpty()) {
+            clearBoundClientUids();
+            return;
+        }
+        // grab a set of clientUids of all connections of all services
+        ArraySet<Integer> boundClientUids = new ArraySet<>();
+        final int K = services.size();
+        for (int j = 0; j < K; j++) {
+            ArrayMap<IBinder, ArrayList<ConnectionRecord>> conns =
+                    services.valueAt(j).getConnections();
+            final int N = conns.size();
+            for (int conni = 0; conni < N; conni++) {
+                ArrayList<ConnectionRecord> c = conns.valueAt(conni);
+                for (int i = 0; i < c.size(); i++) {
+                    boundClientUids.add(c.get(i).clientUid);
+                }
+            }
+        }
+        mBoundClientUids = boundClientUids;
+        mWindowProcessController.setBoundClientUids(mBoundClientUids);
+    }
+
+    void addBoundClientUidsOfNewService(ServiceRecord sr) {
+        if (sr == null) {
+            return;
+        }
+        ArrayMap<IBinder, ArrayList<ConnectionRecord>> conns = sr.getConnections();
+        for (int conni = conns.size() - 1; conni >= 0; conni--) {
+            ArrayList<ConnectionRecord> c = conns.valueAt(conni);
+            for (int i = 0; i < c.size(); i++) {
+                mBoundClientUids.add(c.get(i).clientUid);
+            }
+        }
+        mWindowProcessController.setBoundClientUids(mBoundClientUids);
+    }
+
+    void clearBoundClientUids() {
+        mBoundClientUids.clear();
+        mWindowProcessController.setBoundClientUids(mBoundClientUids);
+    }
+
     void setActiveInstrumentation(ActiveInstrumentation instr) {
         mInstr = instr;
         boolean isInstrumenting = instr != null;
diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java
index eeaa7de..217fd6d 100644
--- a/services/core/java/com/android/server/am/ServiceRecord.java
+++ b/services/core/java/com/android/server/am/ServiceRecord.java
@@ -38,6 +38,7 @@
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.Slog;
 import android.util.TimeUtils;
 import android.util.proto.ProtoOutputStream;
@@ -88,7 +89,7 @@
     final ArrayMap<Intent.FilterComparison, IntentBindRecord> bindings
             = new ArrayMap<Intent.FilterComparison, IntentBindRecord>();
                             // All active bindings to the service.
-    final ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections
+    private final ArrayMap<IBinder, ArrayList<ConnectionRecord>> connections
             = new ArrayMap<IBinder, ArrayList<ConnectionRecord>>();
                             // IBinder -> ConnectionRecord of all bound clients
 
@@ -542,6 +543,7 @@
             }
         } else if (app != null) {
             app.removeAllowBackgroundActivityStartsToken(this);
+            app.updateBoundClientUids();
         }
         app = _proc;
         if (pendingConnectionGroup > 0 && _proc != null) {
@@ -563,6 +565,33 @@
                 }
             }
         }
+        if (_proc != null) {
+            _proc.updateBoundClientUids();
+        }
+    }
+
+    ArrayMap<IBinder, ArrayList<ConnectionRecord>> getConnections() {
+        return connections;
+    }
+
+    void putConnection(IBinder binder, ArrayList<ConnectionRecord> clist) {
+        connections.put(binder, clist);
+        // if we have a process attached, add bound client uids of this connection to it
+        if (app != null) {
+            ArraySet<Integer> boundClientUids = new ArraySet<>();
+            for (int i = 0; i < clist.size(); i++) {
+                boundClientUids.add(clist.get(i).clientUid);
+            }
+            app.addBoundClientUids(boundClientUids);
+        }
+    }
+
+    void removeConnection(IBinder binder) {
+        connections.remove(binder);
+        // if we have a process attached, tell it to update the state of bound clients
+        if (app != null) {
+            app.updateBoundClientUids();
+        }
     }
 
     void updateHasBindingWhitelistingBgActivityStarts() {
diff --git a/services/core/java/com/android/server/am/TEST_MAPPING b/services/core/java/com/android/server/am/TEST_MAPPING
index 117174a..f198464 100644
--- a/services/core/java/com/android/server/am/TEST_MAPPING
+++ b/services/core/java/com/android/server/am/TEST_MAPPING
@@ -27,6 +27,21 @@
           "exclude-annotation": "androidx.test.filters.FlakyTest"
         }
       ]
+    },
+    {
+      "name": "FrameworksMockingServicesTests",
+      "file_patterns": ["AppCompactor\\.java"],
+      "options": [
+        {
+          "include-filter": "com.android.server.am."
+        },
+        {
+          "include-annotation": "android.platform.test.annotations.Presubmit"
+        },
+        {
+          "exclude-annotation": "androidx.test.filters.FlakyTest"
+        }
+      ]
     }
   ],
   "postsubmit": [
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 688020f..07c9cca 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -1743,24 +1743,6 @@
         return state.state != UserState.STATE_STOPPING && state.state != UserState.STATE_SHUTDOWN;
     }
 
-    /**
-     * Check if system user is already started. Unlike other user, system user is in STATE_BOOTING
-     * even if it is not explicitly started. So isUserRunning cannot give the right state
-     * to check if system user is started or not.
-     * @return true if system user is started.
-     */
-    boolean isSystemUserStarted() {
-        synchronized (mLock) {
-            UserState uss = mStartedUsers.get(UserHandle.USER_SYSTEM);
-            if (uss == null) {
-                return false;
-            }
-            return uss.state == UserState.STATE_RUNNING_LOCKED
-                || uss.state == UserState.STATE_RUNNING_UNLOCKING
-                || uss.state == UserState.STATE_RUNNING_UNLOCKED;
-        }
-    }
-
     UserInfo getCurrentUser() {
         if ((mInjector.checkCallingPermission(INTERACT_ACROSS_USERS)
                 != PackageManager.PERMISSION_GRANTED) && (
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 93f7831..32781a9 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -640,6 +640,26 @@
         sAudioVolumeGroups = new AudioVolumeGroups();
 
         // Initialize volume
+        // Priority 1 - Android Property
+        // Priority 2 - Audio Policy Service
+        // Priority 3 - Default Value
+        if (sAudioProductStrategies.size() > 0) {
+            int numStreamTypes = AudioSystem.getNumStreamTypes();
+
+            for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
+                AudioAttributes attr =
+                        sAudioProductStrategies.getAudioAttributesForLegacyStreamType(streamType);
+                int maxVolume = AudioSystem.getMaxVolumeIndexForAttributes(attr);
+                if (maxVolume != -1) {
+                    MAX_STREAM_VOLUME[streamType] = maxVolume;
+                }
+                int minVolume = AudioSystem.getMinVolumeIndexForAttributes(attr);
+                if (minVolume != -1) {
+                    MIN_STREAM_VOLUME[streamType] = minVolume;
+                }
+            }
+        }
+
         int maxCallVolume = SystemProperties.getInt("ro.config.vc_call_vol_steps", -1);
         if (maxCallVolume != -1) {
             MAX_STREAM_VOLUME[AudioSystem.STREAM_VOICE_CALL] = maxCallVolume;
@@ -1468,6 +1488,11 @@
     }
 
     private int rescaleIndex(int index, int srcStream, int dstStream) {
+        int max = mStreamStates[srcStream].getMaxIndex();
+        if (max == 0) {
+            Log.e(TAG, "rescaleIndex : Max index should not be zero");
+            return mStreamStates[srcStream].getMinIndex();
+        }
         final int rescaled =
                 (index * mStreamStates[dstStream].getMaxIndex()
                         + mStreamStates[srcStream].getMaxIndex() / 2)
@@ -6360,9 +6385,20 @@
         boolean isLoopbackRenderPolicy = policyConfig.getMixes().stream().allMatch(
                 mix -> mix.getRouteFlags() == (mix.ROUTE_FLAG_RENDER | mix.ROUTE_FLAG_LOOP_BACK));
 
-        // Policy that do not modify the audio routing only need an audio projection
-        if (isLoopbackRenderPolicy && canProjectAudio(projection)) {
-            return true;
+        if (isLoopbackRenderPolicy) {
+            boolean allowPrivilegedPlaybackCapture = policyConfig.getMixes().stream().anyMatch(
+                    mix -> mix.getRule().allowPrivilegedPlaybackCapture());
+            if (allowPrivilegedPlaybackCapture
+                    && !(hasPermission(android.Manifest.permission.CAPTURE_AUDIO_OUTPUT)
+                    || hasPermission(android.Manifest.permission.CAPTURE_MEDIA_OUTPUT))) {
+                // Opt-out can not be bypassed without a system permission
+                return false;
+            }
+
+            if (canProjectAudio(projection)) {
+                // Policy that do not modify the audio routing only need an audio projection
+                return true;
+            }
         }
 
         boolean hasPermissionModifyAudioRouting =
@@ -6373,6 +6409,9 @@
         }
         return false;
     }
+    private boolean hasPermission(String permission) {
+        return PackageManager.PERMISSION_GRANTED == mContext.checkCallingPermission(permission);
+    }
 
     /** @return true if projection is a valid MediaProjection that can project audio. */
     private boolean canProjectAudio(IMediaProjection projection) {
diff --git a/services/core/java/com/android/server/audio/RecordingActivityMonitor.java b/services/core/java/com/android/server/audio/RecordingActivityMonitor.java
index b2c7ff3..87b272b 100644
--- a/services/core/java/com/android/server/audio/RecordingActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/RecordingActivityMonitor.java
@@ -69,6 +69,9 @@
                                                 AudioEffect.Descriptor[] effects,
                                                 int activeSource, String packName) {
         if (MediaRecorder.isSystemOnlyAudioSource(source)) {
+            // still want to log event, it just won't appear in recording configurations
+            sEventLogger.log(new RecordingEvent(event, uid, session, source, packName)
+                    .printLog(TAG));
             return;
         }
         String clientEffectName =  clientEffects.length == 0 ? "None" : clientEffects[0].name;
diff --git a/services/core/java/com/android/server/connectivity/DnsManager.java b/services/core/java/com/android/server/connectivity/DnsManager.java
index d8bb635..1913635 100644
--- a/services/core/java/com/android/server/connectivity/DnsManager.java
+++ b/services/core/java/com/android/server/connectivity/DnsManager.java
@@ -30,13 +30,15 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
+import android.net.IDnsResolver;
 import android.net.LinkProperties;
 import android.net.Network;
 import android.net.NetworkUtils;
 import android.net.Uri;
 import android.net.shared.PrivateDnsConfig;
 import android.os.Binder;
-import android.os.INetworkManagementService;
+import android.os.RemoteException;
+import android.os.ServiceSpecificException;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.text.TextUtils;
@@ -229,7 +231,7 @@
 
     private final Context mContext;
     private final ContentResolver mContentResolver;
-    private final INetworkManagementService mNMS;
+    private final IDnsResolver mDnsResolver;
     private final MockableSystemProperties mSystemProperties;
     // TODO: Replace these Maps with SparseArrays.
     private final Map<Integer, PrivateDnsConfig> mPrivateDnsMap;
@@ -243,10 +245,10 @@
     private String mPrivateDnsMode;
     private String mPrivateDnsSpecifier;
 
-    public DnsManager(Context ctx, INetworkManagementService nms, MockableSystemProperties sp) {
+    public DnsManager(Context ctx, IDnsResolver dnsResolver, MockableSystemProperties sp) {
         mContext = ctx;
         mContentResolver = mContext.getContentResolver();
-        mNMS = nms;
+        mDnsResolver = dnsResolver;
         mSystemProperties = sp;
         mPrivateDnsMap = new HashMap<>();
         mPrivateDnsValidationMap = new HashMap<>();
@@ -260,6 +262,12 @@
     }
 
     public void removeNetwork(Network network) {
+        try {
+            mDnsResolver.clearResolverConfiguration(network.netId);
+        } catch (RemoteException | ServiceSpecificException e) {
+            Slog.e(TAG, "Error clearing DNS configuration: " + e);
+            return;
+        }
         mPrivateDnsMap.remove(network.netId);
         mPrivateDnsValidationMap.remove(network.netId);
     }
@@ -344,10 +352,12 @@
         Slog.d(TAG, String.format("setDnsConfigurationForNetwork(%d, %s, %s, %s, %s, %s)",
                 netId, Arrays.toString(assignedServers), Arrays.toString(domainStrs),
                 Arrays.toString(params), tlsHostname, Arrays.toString(tlsServers)));
+        final String[] tlsFingerprints = new String[0];
         try {
-            mNMS.setDnsConfigurationForNetwork(
-                    netId, assignedServers, domainStrs, params, tlsHostname, tlsServers);
-        } catch (Exception e) {
+            mDnsResolver.setResolverConfiguration(
+                    netId, assignedServers, domainStrs, params,
+                    tlsHostname, tlsServers, tlsFingerprints);
+        } catch (RemoteException | ServiceSpecificException e) {
             Slog.e(TAG, "Error setting DNS configuration: " + e);
             return;
         }
diff --git a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
index ce887eb..d7a57b9 100644
--- a/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
+++ b/services/core/java/com/android/server/connectivity/KeepaliveTracker.java
@@ -154,12 +154,19 @@
             // keepalives are sent cannot be reused by another app even if the fd gets closed by
             // the user. A null is acceptable here for backward compatibility of PacketKeepalive
             // API.
-            // TODO: don't accept null fd after legacy packetKeepalive API is removed.
             try {
                 if (fd != null) {
                     mFd = Os.dup(fd);
                 }  else {
-                    Log.d(TAG, "uid/pid " + mUid + "/" + mPid + " calls with null fd");
+                    Log.d(TAG, toString() + " calls with null fd");
+                    if (!mPrivileged) {
+                        throw new SecurityException(
+                                "null fd is not allowed for unprivileged access.");
+                    }
+                    if (mType == TYPE_TCP) {
+                        throw new IllegalArgumentException(
+                                "null fd is not allowed for tcp socket keepalives.");
+                    }
                     mFd = null;
                 }
             } catch (ErrnoException e) {
@@ -480,7 +487,6 @@
             }
         } else {
             // Keepalive successfully stopped, or error.
-            ki.mStartedState = KeepaliveInfo.NOT_STARTED;
             if (reason == SUCCESS) {
                 // The message indicated success stopping : don't call handleStopKeepalive.
                 if (DBG) Log.d(TAG, "Successfully stopped keepalive " + slot + " on " + nai.name());
@@ -490,6 +496,7 @@
                 handleStopKeepalive(nai, slot, reason);
                 if (DBG) Log.d(TAG, "Keepalive " + slot + " on " + nai.name() + " error " + reason);
             }
+            ki.mStartedState = KeepaliveInfo.NOT_STARTED;
         }
     }
 
@@ -531,7 +538,8 @@
         try {
             ki = new KeepaliveInfo(cb, nai, packet, intervalSeconds,
                     KeepaliveInfo.TYPE_NATT, fd);
-        } catch (InvalidSocketException e) {
+        } catch (InvalidSocketException | IllegalArgumentException | SecurityException e) {
+            Log.e(TAG, "Fail to construct keepalive", e);
             notifyErrorCallback(cb, ERROR_INVALID_SOCKET);
             return;
         }
@@ -570,7 +578,8 @@
         try {
             ki = new KeepaliveInfo(cb, nai, packet, intervalSeconds,
                     KeepaliveInfo.TYPE_TCP, fd);
-        } catch (InvalidSocketException e) {
+        } catch (InvalidSocketException | IllegalArgumentException | SecurityException e) {
+            Log.e(TAG, "Fail to construct keepalive e=" + e);
             notifyErrorCallback(cb, ERROR_INVALID_SOCKET);
             return;
         }
diff --git a/services/core/java/com/android/server/connectivity/Nat464Xlat.java b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
index 262ba7a..66bd27c 100644
--- a/services/core/java/com/android/server/connectivity/Nat464Xlat.java
+++ b/services/core/java/com/android/server/connectivity/Nat464Xlat.java
@@ -17,6 +17,7 @@
 package com.android.server.connectivity;
 
 import android.net.ConnectivityManager;
+import android.net.IDnsResolver;
 import android.net.INetd;
 import android.net.InetAddresses;
 import android.net.InterfaceConfiguration;
@@ -65,6 +66,7 @@
         NetworkInfo.State.SUSPENDED,
     };
 
+    private final IDnsResolver mDnsResolver;
     private final INetd mNetd;
     private final INetworkManagementService mNMService;
 
@@ -84,7 +86,9 @@
     private Inet6Address mIPv6Address;
     private State mState = State.IDLE;
 
-    public Nat464Xlat(NetworkAgentInfo nai, INetd netd, INetworkManagementService nmService) {
+    public Nat464Xlat(NetworkAgentInfo nai, INetd netd, IDnsResolver dnsResolver,
+            INetworkManagementService nmService) {
+        mDnsResolver = dnsResolver;
         mNetd = netd;
         mNMService = nmService;
         mNetwork = nai;
@@ -269,7 +273,7 @@
 
     private void startPrefixDiscovery() {
         try {
-            mNetd.resolverStartPrefix64Discovery(getNetId());
+            mDnsResolver.startPrefix64Discovery(getNetId());
             mState = State.DISCOVERING;
         } catch (RemoteException | ServiceSpecificException e) {
             Slog.e(TAG, "Error starting prefix discovery on netId " + getNetId() + ": " + e);
@@ -278,7 +282,7 @@
 
     private void stopPrefixDiscovery() {
         try {
-            mNetd.resolverStopPrefix64Discovery(getNetId());
+            mDnsResolver.stopPrefix64Discovery(getNetId());
         } catch (RemoteException | ServiceSpecificException e) {
             Slog.e(TAG, "Error stopping prefix discovery on netId " + getNetId() + ": " + e);
         }
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index 8f2825c..e3fdbe8 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -17,6 +17,7 @@
 package com.android.server.connectivity;
 
 import android.content.Context;
+import android.net.IDnsResolver;
 import android.net.INetd;
 import android.net.INetworkMonitor;
 import android.net.LinkProperties;
@@ -255,7 +256,7 @@
     public NetworkAgentInfo(Messenger messenger, AsyncChannel ac, Network net, NetworkInfo info,
             LinkProperties lp, NetworkCapabilities nc, int score, Context context, Handler handler,
             NetworkMisc misc, ConnectivityService connService, INetd netd,
-            INetworkManagementService nms, int factorySerialNumber) {
+            IDnsResolver dnsResolver, INetworkManagementService nms, int factorySerialNumber) {
         this.messenger = messenger;
         asyncChannel = ac;
         network = net;
@@ -263,7 +264,7 @@
         linkProperties = lp;
         networkCapabilities = nc;
         currentScore = score;
-        clatd = new Nat464Xlat(this, netd, nms);
+        clatd = new Nat464Xlat(this, netd, dnsResolver, nms);
         mConnService = connService;
         mContext = context;
         mHandler = handler;
diff --git a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
index 828a1e5..ac3d6de 100644
--- a/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
+++ b/services/core/java/com/android/server/connectivity/NetworkNotificationManager.java
@@ -19,6 +19,7 @@
 import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
+import static android.telephony.SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;
 
 import android.app.Notification;
 import android.app.NotificationManager;
@@ -26,9 +27,12 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.res.Resources;
+import android.net.NetworkSpecifier;
+import android.net.StringNetworkSpecifier;
 import android.net.wifi.WifiInfo;
 import android.os.UserHandle;
 import android.telephony.AccessNetworkConstants.TransportType;
+import android.telephony.SubscriptionManager;
 import android.telephony.TelephonyManager;
 import android.text.TextUtils;
 import android.util.Slog;
@@ -195,7 +199,20 @@
                     title = r.getString(R.string.network_available_sign_in, 0);
                     // TODO: Change this to pull from NetworkInfo once a printable
                     // name has been added to it
-                    details = mTelephonyManager.getNetworkOperatorName();
+                    NetworkSpecifier specifier = nai.networkCapabilities.getNetworkSpecifier();
+                    int subId = SubscriptionManager.DEFAULT_SUBSCRIPTION_ID;
+                    if (specifier instanceof StringNetworkSpecifier) {
+                        try {
+                            subId = Integer.parseInt(
+                                    ((StringNetworkSpecifier) specifier).specifier);
+                        } catch (NumberFormatException e) {
+                            Slog.e(TAG, "NumberFormatException on "
+                                    + ((StringNetworkSpecifier) specifier).specifier);
+                        }
+                    }
+
+                    details = mTelephonyManager.createForSubscriptionId(subId)
+                            .getNetworkOperatorName();
                     break;
                 default:
                     title = r.getString(R.string.network_available_sign_in, 0);
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 37fe3d0..9986809 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -82,7 +82,6 @@
 import android.os.INetworkManagementService;
 import android.os.Looper;
 import android.os.Message;
-import android.os.Parcel;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
@@ -230,8 +229,15 @@
 
         IntentFilter filter = new IntentFilter();
         filter.addAction(ACTION_CARRIER_CONFIG_CHANGED);
-        mEntitlementMgr = mDeps.getEntitlementManager(mContext, mTetherMasterSM,
-                mLog, systemProperties);
+        // EntitlementManager will send EVENT_UPSTREAM_PERMISSION_CHANGED when cellular upstream
+        // permission is changed according to entitlement check result.
+        mEntitlementMgr = mDeps.getEntitlementManager(mContext, mTetherMasterSM, mLog,
+                TetherMasterSM.EVENT_UPSTREAM_PERMISSION_CHANGED, systemProperties);
+        mEntitlementMgr.setOnUiEntitlementFailedListener((int downstream) -> {
+            mLog.log("OBSERVED UiEnitlementFailed");
+            stopTethering(downstream);
+        });
+
         mCarrierConfigChange = new VersionedBroadcastListener(
                 "CarrierConfigChangeListener", mContext, mHandler, filter,
                 (Intent ignored) -> {
@@ -363,55 +369,28 @@
     }
 
     public void startTethering(int type, ResultReceiver receiver, boolean showProvisioningUi) {
-        mEntitlementMgr.startTethering(type);
-        if (!mEntitlementMgr.isTetherProvisioningRequired()) {
-            enableTetheringInternal(type, true, receiver);
-            return;
-        }
-
-        final ResultReceiver proxyReceiver = getProxyReceiver(type, receiver);
-        if (showProvisioningUi) {
-            mEntitlementMgr.runUiTetherProvisioningAndEnable(type, proxyReceiver);
-        } else {
-            mEntitlementMgr.runSilentTetherProvisioningAndEnable(type, proxyReceiver);
-        }
+        mEntitlementMgr.startProvisioningIfNeeded(type, showProvisioningUi);
+        enableTetheringInternal(type, true /* enabled */, receiver);
     }
 
     public void stopTethering(int type) {
-        enableTetheringInternal(type, false, null);
-        mEntitlementMgr.stopTethering(type);
-        if (mEntitlementMgr.isTetherProvisioningRequired()) {
-            // There are lurking bugs where the notion of "provisioning required" or
-            // "tethering supported" may change without notifying tethering properly, then
-            // tethering can't shutdown correctly.
-            // TODO: cancel re-check all the time
-            if (mDeps.isTetheringSupported()) {
-                mEntitlementMgr.cancelTetherProvisioningRechecks(type);
-            }
-        }
+        enableTetheringInternal(type, false /* disabled */, null);
+        mEntitlementMgr.stopProvisioningIfNeeded(type);
     }
 
     /**
-     * Enables or disables tethering for the given type. This should only be called once
-     * provisioning has succeeded or is not necessary. It will also schedule provisioning rechecks
-     * for the specified interface.
+     * Enables or disables tethering for the given type. If provisioning is required, it will
+     * schedule provisioning rechecks for the specified interface.
      */
     private void enableTetheringInternal(int type, boolean enable, ResultReceiver receiver) {
-        boolean isProvisioningRequired = enable && mEntitlementMgr.isTetherProvisioningRequired();
         int result;
         switch (type) {
             case TETHERING_WIFI:
                 result = setWifiTethering(enable);
-                if (isProvisioningRequired && result == TETHER_ERROR_NO_ERROR) {
-                    mEntitlementMgr.scheduleProvisioningRechecks(type);
-                }
                 sendTetherResult(receiver, result);
                 break;
             case TETHERING_USB:
                 result = setUsbTethering(enable);
-                if (isProvisioningRequired && result == TETHER_ERROR_NO_ERROR) {
-                    mEntitlementMgr.scheduleProvisioningRechecks(type);
-                }
                 sendTetherResult(receiver, result);
                 break;
             case TETHERING_BLUETOOTH:
@@ -469,46 +448,11 @@
                         ? TETHER_ERROR_NO_ERROR
                         : TETHER_ERROR_MASTER_ERROR;
                 sendTetherResult(receiver, result);
-                if (enable && mEntitlementMgr.isTetherProvisioningRequired()) {
-                    mEntitlementMgr.scheduleProvisioningRechecks(TETHERING_BLUETOOTH);
-                }
                 adapter.closeProfileProxy(BluetoothProfile.PAN, proxy);
             }
         }, BluetoothProfile.PAN);
     }
 
-    /**
-     * Creates a proxy {@link ResultReceiver} which enables tethering if the provisioning result
-     * is successful before firing back up to the wrapped receiver.
-     *
-     * @param type The type of tethering being enabled.
-     * @param receiver A ResultReceiver which will be called back with an int resultCode.
-     * @return The proxy receiver.
-     */
-    private ResultReceiver getProxyReceiver(final int type, final ResultReceiver receiver) {
-        ResultReceiver rr = new ResultReceiver(null) {
-            @Override
-            protected void onReceiveResult(int resultCode, Bundle resultData) {
-                // If provisioning is successful, enable tethering, otherwise just send the error.
-                if (resultCode == TETHER_ERROR_NO_ERROR) {
-                    enableTetheringInternal(type, true, receiver);
-                } else {
-                    sendTetherResult(receiver, resultCode);
-                }
-                mEntitlementMgr.updateEntitlementCacheValue(type, resultCode);
-            }
-        };
-
-        // The following is necessary to avoid unmarshalling issues when sending the receiver
-        // across processes.
-        Parcel parcel = Parcel.obtain();
-        rr.writeToParcel(parcel,0);
-        parcel.setDataPosition(0);
-        ResultReceiver receiverForSending = ResultReceiver.CREATOR.createFromParcel(parcel);
-        parcel.recycle();
-        return receiverForSending;
-    }
-
     public int tether(String iface) {
         return tether(iface, IpServer.STATE_TETHERED);
     }
@@ -787,6 +731,7 @@
                 if (!usbConnected && mRndisEnabled) {
                     // Turn off tethering if it was enabled and there is a disconnect.
                     tetherMatchingInterfaces(IpServer.STATE_AVAILABLE, TETHERING_USB);
+                    mEntitlementMgr.stopProvisioningIfNeeded(TETHERING_USB);
                 } else if (usbConfigured && rndisEnabled) {
                     // Tether if rndis is enabled and usb is configured.
                     tetherMatchingInterfaces(IpServer.STATE_TETHERED, TETHERING_USB);
@@ -813,6 +758,7 @@
                     case WifiManager.WIFI_AP_STATE_FAILED:
                     default:
                         disableWifiIpServingLocked(ifname, curState);
+                        mEntitlementMgr.stopProvisioningIfNeeded(TETHERING_WIFI);
                         break;
                 }
             }
@@ -1090,6 +1036,8 @@
         // we treated the error and want now to clear it
         static final int CMD_CLEAR_ERROR                        = BASE_MASTER + 6;
         static final int EVENT_IFACE_UPDATE_LINKPROPERTIES      = BASE_MASTER + 7;
+        // Events from EntitlementManager to choose upstream again.
+        static final int EVENT_UPSTREAM_PERMISSION_CHANGED      = BASE_MASTER + 8;
 
         private final State mInitialState;
         private final State mTetherModeAliveState;
@@ -1504,6 +1452,7 @@
                         }
                         break;
                     }
+                    case EVENT_UPSTREAM_PERMISSION_CHANGED:
                     case CMD_UPSTREAM_CHANGED:
                         updateUpstreamWanted();
                         if (!mUpstreamWanted) break;
@@ -1694,7 +1643,8 @@
     }
 
     public void systemReady() {
-        mUpstreamNetworkMonitor.startTrackDefaultNetwork(mDeps.getDefaultNetworkRequest());
+        mUpstreamNetworkMonitor.startTrackDefaultNetwork(mDeps.getDefaultNetworkRequest(),
+                mEntitlementMgr);
     }
 
     /** Get the latest value of the tethering entitlement check. */
@@ -1755,6 +1705,11 @@
         cfg.dump(pw);
         pw.decreaseIndent();
 
+        pw.println("Entitlement:");
+        pw.increaseIndent();
+        mEntitlementMgr.dump(pw);
+        pw.decreaseIndent();
+
         synchronized (mPublicSync) {
             pw.println("Tether state:");
             pw.increaseIndent();
diff --git a/services/core/java/com/android/server/connectivity/tethering/EntitlementManager.java b/services/core/java/com/android/server/connectivity/tethering/EntitlementManager.java
index 70ab389..764a6eb 100644
--- a/services/core/java/com/android/server/connectivity/tethering/EntitlementManager.java
+++ b/services/core/java/com/android/server/connectivity/tethering/EntitlementManager.java
@@ -18,9 +18,11 @@
 
 import static android.net.ConnectivityManager.EXTRA_ADD_TETHER_TYPE;
 import static android.net.ConnectivityManager.EXTRA_PROVISION_CALLBACK;
-import static android.net.ConnectivityManager.EXTRA_REM_TETHER_TYPE;
 import static android.net.ConnectivityManager.EXTRA_RUN_PROVISION;
-import static android.net.ConnectivityManager.EXTRA_SET_ALARM;
+import static android.net.ConnectivityManager.TETHERING_BLUETOOTH;
+import static android.net.ConnectivityManager.TETHERING_INVALID;
+import static android.net.ConnectivityManager.TETHERING_USB;
+import static android.net.ConnectivityManager.TETHERING_WIFI;
 import static android.net.ConnectivityManager.TETHER_ERROR_ENTITLEMENT_UNKONWN;
 import static android.net.ConnectivityManager.TETHER_ERROR_NO_ERROR;
 import static android.net.ConnectivityManager.TETHER_ERROR_PROVISION_FAILED;
@@ -28,17 +30,24 @@
 import static com.android.internal.R.string.config_wifi_tether_enable;
 
 import android.annotation.Nullable;
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.res.Resources;
 import android.net.util.SharedLog;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
 import android.os.Parcel;
 import android.os.PersistableBundle;
 import android.os.ResultReceiver;
+import android.os.SystemClock;
 import android.os.UserHandle;
 import android.provider.Settings;
 import android.telephony.CarrierConfigManager;
@@ -46,48 +55,93 @@
 import android.util.Log;
 import android.util.SparseIntArray;
 
-import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.StateMachine;
 import com.android.server.connectivity.MockableSystemProperties;
 
+import java.io.PrintWriter;
+
 /**
- * This class encapsulates entitlement/provisioning mechanics
- * provisioning check only applies to the use of the mobile network as an upstream
+ * Re-check tethering provisioning for enabled downstream tether types.
+ * Reference ConnectivityManager.TETHERING_{@code *} for each tether type.
  *
+ * All methods of this class must be accessed from the thread of tethering
+ * state machine.
  * @hide
  */
 public class EntitlementManager {
     private static final String TAG = EntitlementManager.class.getSimpleName();
     private static final boolean DBG = false;
 
+    @VisibleForTesting
+    protected static final String DISABLE_PROVISIONING_SYSPROP_KEY = "net.tethering.noprovisioning";
+    private static final String ACTION_PROVISIONING_ALARM =
+            "com.android.server.connectivity.tethering.PROVISIONING_RECHECK_ALARM";
+
     // {@link ComponentName} of the Service used to run tether provisioning.
     private static final ComponentName TETHER_SERVICE = ComponentName.unflattenFromString(
             Resources.getSystem().getString(config_wifi_tether_enable));
-    protected static final String DISABLE_PROVISIONING_SYSPROP_KEY = "net.tethering.noprovisioning";
+    private static final int MS_PER_HOUR = 60 * 60 * 1000;
+    private static final int EVENT_START_PROVISIONING = 0;
+    private static final int EVENT_STOP_PROVISIONING = 1;
+    private static final int EVENT_UPSTREAM_CHANGED = 2;
+    private static final int EVENT_MAYBE_RUN_PROVISIONING = 3;
+    private static final int EVENT_GET_ENTITLEMENT_VALUE = 4;
+
 
     // The ArraySet contains enabled downstream types, ex:
     // {@link ConnectivityManager.TETHERING_WIFI}
     // {@link ConnectivityManager.TETHERING_USB}
     // {@link ConnectivityManager.TETHERING_BLUETOOTH}
-    @GuardedBy("mCurrentTethers")
     private final ArraySet<Integer> mCurrentTethers;
     private final Context mContext;
+    private final int mPermissionChangeMessageCode;
     private final MockableSystemProperties mSystemProperties;
     private final SharedLog mLog;
-    private final Handler mMasterHandler;
     private final SparseIntArray mEntitlementCacheValue;
-    @Nullable
-    private TetheringConfiguration mConfig;
+    private final EntitlementHandler mHandler;
+    private @Nullable TetheringConfiguration mConfig;
+    private final StateMachine mTetherMasterSM;
+    // Key: ConnectivityManager.TETHERING_*(downstream).
+    // Value: ConnectivityManager.TETHER_ERROR_{NO_ERROR or PROVISION_FAILED}(provisioning result).
+    private final SparseIntArray mCellularPermitted;
+    private PendingIntent mProvisioningRecheckAlarm;
+    private boolean mCellularUpstreamPermitted = true;
+    private boolean mUsingCellularAsUpstream = false;
+    private boolean mNeedReRunProvisioningUi = false;
+    private OnUiEntitlementFailedListener mListener;
 
     public EntitlementManager(Context ctx, StateMachine tetherMasterSM, SharedLog log,
-            MockableSystemProperties systemProperties) {
+            int permissionChangeMessageCode, MockableSystemProperties systemProperties) {
+
         mContext = ctx;
         mLog = log.forSubComponent(TAG);
         mCurrentTethers = new ArraySet<Integer>();
+        mCellularPermitted = new SparseIntArray();
         mSystemProperties = systemProperties;
         mEntitlementCacheValue = new SparseIntArray();
-        mMasterHandler = tetherMasterSM.getHandler();
+        mTetherMasterSM = tetherMasterSM;
+        mPermissionChangeMessageCode = permissionChangeMessageCode;
+        final Handler masterHandler = tetherMasterSM.getHandler();
+        // Create entitlement's own handler which is associated with TetherMaster thread
+        // let all entitlement processes run in the same thread.
+        mHandler = new EntitlementHandler(masterHandler.getLooper());
+        mContext.registerReceiver(mReceiver, new IntentFilter(ACTION_PROVISIONING_ALARM),
+                null, mHandler);
+    }
+
+    public void setOnUiEntitlementFailedListener(final OnUiEntitlementFailedListener listener) {
+        mListener = listener;
+    }
+
+    /** Callback fired when UI entitlement failed. */
+    public interface OnUiEntitlementFailedListener {
+        /**
+         * Ui entitlement check fails in |downstream|.
+         *
+         * @param downstream  tethering type from ConnectivityManager.TETHERING_{@code *}.
+         */
+        void onUiEntitlementFailed(int downstream);
     }
 
     /**
@@ -99,24 +153,118 @@
     }
 
     /**
-     * Tell EntitlementManager that a given type of tethering has been enabled
-     *
-     * @param type Tethering type
+     * Check if cellular upstream is permitted.
      */
-    public void startTethering(int type) {
-        synchronized (mCurrentTethers) {
-            mCurrentTethers.add(type);
+    public boolean isCellularUpstreamPermitted() {
+        return mCellularUpstreamPermitted;
+    }
+
+    /**
+     * This is called when tethering starts.
+     * Launch provisioning app if upstream is cellular.
+     *
+     * @param downstreamType tethering type from ConnectivityManager.TETHERING_{@code *}
+     * @param showProvisioningUi a boolean indicating whether to show the
+     *        provisioning app UI if there is one.
+     */
+    public void startProvisioningIfNeeded(int downstreamType, boolean showProvisioningUi) {
+        mHandler.sendMessage(mHandler.obtainMessage(EVENT_START_PROVISIONING,
+                downstreamType, encodeBool(showProvisioningUi)));
+    }
+
+    private void handleStartProvisioningIfNeeded(int type, boolean showProvisioningUi) {
+        if (!isValidDownstreamType(type)) return;
+
+        if (!mCurrentTethers.contains(type)) mCurrentTethers.add(type);
+
+        if (isTetherProvisioningRequired()) {
+            // If provisioning is required and the result is not available yet,
+            // cellular upstream should not be allowed.
+            if (mCellularPermitted.size() == 0) {
+                mCellularUpstreamPermitted = false;
+            }
+            // If upstream is not cellular, provisioning app would not be launched
+            // till upstream change to cellular.
+            if (mUsingCellularAsUpstream) {
+                if (showProvisioningUi) {
+                    runUiTetherProvisioning(type);
+                } else {
+                    runSilentTetherProvisioning(type);
+                }
+                mNeedReRunProvisioningUi = false;
+            } else {
+                mNeedReRunProvisioningUi |= showProvisioningUi;
+            }
+        } else {
+            mCellularUpstreamPermitted = true;
         }
     }
 
     /**
      * Tell EntitlementManager that a given type of tethering has been disabled
      *
-     * @param type Tethering type
+     * @param type tethering type from ConnectivityManager.TETHERING_{@code *}
      */
-    public void stopTethering(int type) {
-        synchronized (mCurrentTethers) {
-            mCurrentTethers.remove(type);
+    public void stopProvisioningIfNeeded(int type) {
+        mHandler.sendMessage(mHandler.obtainMessage(EVENT_STOP_PROVISIONING, type, 0));
+    }
+
+    private void handleStopProvisioningIfNeeded(int type) {
+        if (!isValidDownstreamType(type)) return;
+
+        mCurrentTethers.remove(type);
+        // There are lurking bugs where the notion of "provisioning required" or
+        // "tethering supported" may change without without tethering being notified properly.
+        // Remove the mapping all the time no matter provisioning is required or not.
+        removeDownstreamMapping(type);
+    }
+
+    /**
+     * Notify EntitlementManager if upstream is cellular or not.
+     *
+     * @param isCellular whether tethering upstream is cellular.
+     */
+    public void notifyUpstream(boolean isCellular) {
+        mHandler.sendMessage(mHandler.obtainMessage(
+                EVENT_UPSTREAM_CHANGED, encodeBool(isCellular), 0));
+    }
+
+    private void handleNotifyUpstream(boolean isCellular) {
+        if (DBG) {
+            Log.d(TAG, "notifyUpstream: " + isCellular
+                    + ", mCellularUpstreamPermitted: " + mCellularUpstreamPermitted
+                    + ", mNeedReRunProvisioningUi: " + mNeedReRunProvisioningUi);
+        }
+        mUsingCellularAsUpstream = isCellular;
+
+        if (mUsingCellularAsUpstream) {
+            handleMaybeRunProvisioning();
+        }
+    }
+
+    /** Run provisioning if needed */
+    public void maybeRunProvisioning() {
+        mHandler.sendMessage(mHandler.obtainMessage(EVENT_MAYBE_RUN_PROVISIONING));
+    }
+
+    private void handleMaybeRunProvisioning() {
+        if (mCurrentTethers.size() == 0 || !isTetherProvisioningRequired()) {
+            return;
+        }
+
+        // Whenever any entitlement value changes, all downstreams will re-evaluate whether they
+        // are allowed. Therefore even if the silent check here ends in a failure and the UI later
+        // yields success, then the downstream that got a failure will re-evaluate as a result of
+        // the change and get the new correct value.
+        for (Integer downstream : mCurrentTethers) {
+            if (mCellularPermitted.indexOfKey(downstream) < 0) {
+                if (mNeedReRunProvisioningUi) {
+                    mNeedReRunProvisioningUi = false;
+                    runUiTetherProvisioning(downstream);
+                } else {
+                    runSilentTetherProvisioning(downstream);
+                }
+            }
         }
     }
 
@@ -138,23 +286,32 @@
     }
 
     /**
-     * Re-check tethering provisioning for enabled downstream tether types.
+     * Re-check tethering provisioning for all enabled tether types.
      * Reference ConnectivityManager.TETHERING_{@code *} for each tether type.
+     *
+     * Note: this method is only called from TetherMaster on the handler thread.
+     * If there are new callers from different threads, the logic should move to
+     * masterHandler to avoid race conditions.
      */
     public void reevaluateSimCardProvisioning() {
-        synchronized (mEntitlementCacheValue) {
-            mEntitlementCacheValue.clear();
+        if (DBG) Log.d(TAG, "reevaluateSimCardProvisioning");
+
+        if (!mHandler.getLooper().isCurrentThread()) {
+            // Except for test, this log should not appear in normal flow.
+            mLog.log("reevaluateSimCardProvisioning() don't run in TetherMaster thread");
+        }
+        mEntitlementCacheValue.clear();
+        mCellularPermitted.clear();
+
+        // TODO: refine provisioning check to isTetherProvisioningRequired() ??
+        if (!mConfig.hasMobileHotspotProvisionApp()
+                || carrierConfigAffirmsEntitlementCheckNotRequired()) {
+            evaluateCellularPermission();
+            return;
         }
 
-        if (!mConfig.hasMobileHotspotProvisionApp()) return;
-        if (carrierConfigAffirmsEntitlementCheckNotRequired()) return;
-
-        final ArraySet<Integer> reevaluateType;
-        synchronized (mCurrentTethers) {
-            reevaluateType = new ArraySet<Integer>(mCurrentTethers);
-        }
-        for (Integer type : reevaluateType) {
-            startProvisionIntent(type);
+        if (mUsingCellularAsUpstream) {
+            handleMaybeRunProvisioning();
         }
     }
 
@@ -189,7 +346,16 @@
         return !isEntitlementCheckRequired;
     }
 
-    public void runSilentTetherProvisioningAndEnable(int type, ResultReceiver receiver) {
+    /**
+     * Run no UI tethering provisioning check.
+     * @param type tethering type from ConnectivityManager.TETHERING_{@code *}
+     */
+    protected void runSilentTetherProvisioning(int type) {
+        if (DBG) Log.d(TAG, "runSilentTetherProvisioning: " + type);
+        // For silent provisioning, settings would stop tethering when entitlement fail.
+        ResultReceiver receiver = buildProxyReceiver(type,
+                false/* notifyFail */, null);
+
         Intent intent = new Intent();
         intent.putExtra(EXTRA_ADD_TETHER_TYPE, type);
         intent.putExtra(EXTRA_RUN_PROVISION, true);
@@ -203,12 +369,21 @@
         }
     }
 
-    public void runUiTetherProvisioningAndEnable(int type, ResultReceiver receiver) {
+    /**
+     * Run the UI-enabled tethering provisioning check.
+     * @param type tethering type from ConnectivityManager.TETHERING_{@code *}
+     */
+    @VisibleForTesting
+    protected void runUiTetherProvisioning(int type) {
+        ResultReceiver receiver = buildProxyReceiver(type,
+                true/* notifyFail */, null);
         runUiTetherProvisioning(type, receiver);
     }
 
     @VisibleForTesting
     protected void runUiTetherProvisioning(int type, ResultReceiver receiver) {
+        if (DBG) Log.d(TAG, "runUiTetherProvisioning: " + type);
+
         Intent intent = new Intent(Settings.ACTION_TETHER_PROVISIONING);
         intent.putExtra(EXTRA_ADD_TETHER_TYPE, type);
         intent.putExtra(EXTRA_PROVISION_CALLBACK, receiver);
@@ -221,56 +396,210 @@
         }
     }
 
-    // Used by the SIM card change observation code.
-    // TODO: De-duplicate with above code, where possible.
-    private void startProvisionIntent(int tetherType) {
-        final Intent startProvIntent = new Intent();
-        startProvIntent.putExtra(EXTRA_ADD_TETHER_TYPE, tetherType);
-        startProvIntent.putExtra(EXTRA_RUN_PROVISION, true);
-        startProvIntent.setComponent(TETHER_SERVICE);
-        mContext.startServiceAsUser(startProvIntent, UserHandle.CURRENT);
-    }
+    // Not needed to check if this don't run on the handler thread because it's private.
+    private void scheduleProvisioningRechecks() {
+        if (mProvisioningRecheckAlarm == null) {
+            final int period = mConfig.provisioningCheckPeriod;
+            if (period <= 0) return;
 
-    public void scheduleProvisioningRechecks(int type) {
-        Intent intent = new Intent();
-        intent.putExtra(EXTRA_ADD_TETHER_TYPE, type);
-        intent.putExtra(EXTRA_SET_ALARM, true);
-        intent.setComponent(TETHER_SERVICE);
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            mContext.startServiceAsUser(intent, UserHandle.CURRENT);
-        } finally {
-            Binder.restoreCallingIdentity(ident);
+            Intent intent = new Intent(ACTION_PROVISIONING_ALARM);
+            mProvisioningRecheckAlarm = PendingIntent.getBroadcast(mContext, 0, intent, 0);
+            AlarmManager alarmManager = (AlarmManager) mContext.getSystemService(
+                    Context.ALARM_SERVICE);
+            long periodMs = period * MS_PER_HOUR;
+            long firstAlarmTime = SystemClock.elapsedRealtime() + periodMs;
+            alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME, firstAlarmTime, periodMs,
+                    mProvisioningRecheckAlarm);
         }
     }
 
-    public void cancelTetherProvisioningRechecks(int type) {
-        Intent intent = new Intent();
-        intent.putExtra(EXTRA_REM_TETHER_TYPE, type);
-        intent.setComponent(TETHER_SERVICE);
-        final long ident = Binder.clearCallingIdentity();
-        try {
-            mContext.startServiceAsUser(intent, UserHandle.CURRENT);
-        } finally {
-            Binder.restoreCallingIdentity(ident);
+    private void cancelTetherProvisioningRechecks() {
+        if (mProvisioningRecheckAlarm != null) {
+            AlarmManager alarmManager = (AlarmManager) mContext.getSystemService(
+                    Context.ALARM_SERVICE);
+            alarmManager.cancel(mProvisioningRecheckAlarm);
+            mProvisioningRecheckAlarm = null;
         }
     }
 
-    private ResultReceiver buildProxyReceiver(int type, final ResultReceiver receiver) {
-        ResultReceiver rr = new ResultReceiver(mMasterHandler) {
+    private void evaluateCellularPermission() {
+        final boolean oldPermitted = mCellularUpstreamPermitted;
+        mCellularUpstreamPermitted = (!isTetherProvisioningRequired()
+                || mCellularPermitted.indexOfValue(TETHER_ERROR_NO_ERROR) > -1);
+
+        if (DBG) {
+            Log.d(TAG, "Cellular permission change from " + oldPermitted
+                    + " to " + mCellularUpstreamPermitted);
+        }
+
+        if (mCellularUpstreamPermitted != oldPermitted) {
+            mLog.log("Cellular permission change: " + mCellularUpstreamPermitted);
+            mTetherMasterSM.sendMessage(mPermissionChangeMessageCode);
+        }
+        // Only schedule periodic re-check when tether is provisioned
+        // and the result is ok.
+        if (mCellularUpstreamPermitted && mCellularPermitted.size() > 0) {
+            scheduleProvisioningRechecks();
+        } else {
+            cancelTetherProvisioningRechecks();
+        }
+    }
+
+    /**
+     * Add the mapping between provisioning result and tethering type.
+     * Notify UpstreamNetworkMonitor if Cellular permission changes.
+     *
+     * @param type tethering type from ConnectivityManager.TETHERING_{@code *}
+     * @param resultCode Provisioning result
+     */
+    protected void addDownstreamMapping(int type, int resultCode) {
+        if (DBG) {
+            Log.d(TAG, "addDownstreamMapping: " + type + ", result: " + resultCode
+                    + " ,TetherTypeRequested: " + mCurrentTethers.contains(type));
+        }
+        if (!mCurrentTethers.contains(type)) return;
+
+        mCellularPermitted.put(type, resultCode);
+        evaluateCellularPermission();
+    }
+
+    /**
+     * Remove the mapping for input tethering type.
+     * @param type tethering type from ConnectivityManager.TETHERING_{@code *}
+     */
+    protected void removeDownstreamMapping(int type) {
+        if (DBG) Log.d(TAG, "removeDownstreamMapping: " + type);
+        mCellularPermitted.delete(type);
+        evaluateCellularPermission();
+    }
+
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (ACTION_PROVISIONING_ALARM.equals(intent.getAction())) {
+                mLog.log("Received provisioning alarm");
+                reevaluateSimCardProvisioning();
+            }
+        }
+    };
+
+    private class EntitlementHandler extends Handler {
+        EntitlementHandler(Looper looper) {
+            super(looper);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case EVENT_START_PROVISIONING:
+                    handleStartProvisioningIfNeeded(msg.arg1, toBool(msg.arg2));
+                    break;
+                case EVENT_STOP_PROVISIONING:
+                    handleStopProvisioningIfNeeded(msg.arg1);
+                    break;
+                case EVENT_UPSTREAM_CHANGED:
+                    handleNotifyUpstream(toBool(msg.arg1));
+                    break;
+                case EVENT_MAYBE_RUN_PROVISIONING:
+                    handleMaybeRunProvisioning();
+                    break;
+                case EVENT_GET_ENTITLEMENT_VALUE:
+                    handleGetLatestTetheringEntitlementValue(msg.arg1, (ResultReceiver) msg.obj,
+                            toBool(msg.arg2));
+                    break;
+                default:
+                    mLog.log("Unknown event: " + msg.what);
+                    break;
+            }
+        }
+    }
+
+    private static boolean toBool(int encodedBoolean) {
+        return encodedBoolean != 0;
+    }
+
+    private static int encodeBool(boolean b) {
+        return b ? 1 : 0;
+    }
+
+    private static boolean isValidDownstreamType(int type) {
+        switch (type) {
+            case TETHERING_BLUETOOTH:
+            case TETHERING_USB:
+            case TETHERING_WIFI:
+                return true;
+            default:
+                return false;
+        }
+    }
+
+    /**
+     * Dump the infromation of EntitlementManager.
+     * @param pw {@link PrintWriter} is used to print formatted
+     */
+    public void dump(PrintWriter pw) {
+        pw.print("mCellularUpstreamPermitted: ");
+        pw.println(mCellularUpstreamPermitted);
+        for (Integer type : mCurrentTethers) {
+            pw.print("Type: ");
+            pw.print(typeString(type));
+            if (mCellularPermitted.indexOfKey(type) > -1) {
+                pw.print(", Value: ");
+                pw.println(errorString(mCellularPermitted.get(type)));
+            } else {
+                pw.println(", Value: empty");
+            }
+        }
+    }
+
+    private static String typeString(int type) {
+        switch (type) {
+            case TETHERING_BLUETOOTH: return "TETHERING_BLUETOOTH";
+            case TETHERING_INVALID: return "TETHERING_INVALID";
+            case TETHERING_USB: return "TETHERING_USB";
+            case TETHERING_WIFI: return "TETHERING_WIFI";
+            default:
+                return String.format("TETHERING UNKNOWN TYPE (%d)", type);
+        }
+    }
+
+    private static String errorString(int value) {
+        switch (value) {
+            case TETHER_ERROR_ENTITLEMENT_UNKONWN: return "TETHER_ERROR_ENTITLEMENT_UNKONWN";
+            case TETHER_ERROR_NO_ERROR: return "TETHER_ERROR_NO_ERROR";
+            case TETHER_ERROR_PROVISION_FAILED: return "TETHER_ERROR_PROVISION_FAILED";
+            default:
+                return String.format("UNKNOWN ERROR (%d)", value);
+        }
+    }
+
+    private ResultReceiver buildProxyReceiver(int type, boolean notifyFail,
+            final ResultReceiver receiver) {
+        ResultReceiver rr = new ResultReceiver(mHandler) {
             @Override
             protected void onReceiveResult(int resultCode, Bundle resultData) {
                 int updatedCacheValue = updateEntitlementCacheValue(type, resultCode);
-                receiver.send(updatedCacheValue, null);
+                addDownstreamMapping(type, updatedCacheValue);
+                if (updatedCacheValue == TETHER_ERROR_PROVISION_FAILED && notifyFail) {
+                    mListener.onUiEntitlementFailed(type);
+                }
+                if (receiver != null) receiver.send(updatedCacheValue, null);
             }
         };
 
         return writeToParcel(rr);
     }
 
+    // Instances of ResultReceiver need to be public classes for remote processes to be able
+    // to load them (otherwise, ClassNotFoundException). For private classes, this method
+    // performs a trick : round-trip parceling any instance of ResultReceiver will return a
+    // vanilla instance of ResultReceiver sharing the binder token with the original receiver.
+    // The binder token has a reference to the original instance of the private class and will
+    // still call its methods, and can be sent over. However it cannot be used for anything
+    // else than sending over a Binder call.
+    // While round-trip parceling is not great, there is currently no other way of generating
+    // a vanilla instance of ResultReceiver because all its fields are private.
     private ResultReceiver writeToParcel(final ResultReceiver receiver) {
-        // This is necessary to avoid unmarshalling issues when sending the receiver
-        // across processes.
         Parcel parcel = Parcel.obtain();
         receiver.writeToParcel(parcel, 0);
         parcel.setDataPosition(0);
@@ -286,38 +615,41 @@
      * @param resultCode last entitlement value
      * @return the last updated entitlement value
      */
-    public int updateEntitlementCacheValue(int type, int resultCode) {
+    private int updateEntitlementCacheValue(int type, int resultCode) {
         if (DBG) {
             Log.d(TAG, "updateEntitlementCacheValue: " + type + ", result: " + resultCode);
         }
-        synchronized (mEntitlementCacheValue) {
-            if (resultCode == TETHER_ERROR_NO_ERROR) {
-                mEntitlementCacheValue.put(type, resultCode);
-                return resultCode;
-            } else {
-                mEntitlementCacheValue.put(type, TETHER_ERROR_PROVISION_FAILED);
-                return TETHER_ERROR_PROVISION_FAILED;
-            }
+        if (resultCode == TETHER_ERROR_NO_ERROR) {
+            mEntitlementCacheValue.put(type, resultCode);
+            return resultCode;
+        } else {
+            mEntitlementCacheValue.put(type, TETHER_ERROR_PROVISION_FAILED);
+            return TETHER_ERROR_PROVISION_FAILED;
         }
     }
 
     /** Get the last value of the tethering entitlement check. */
     public void getLatestTetheringEntitlementResult(int downstream, ResultReceiver receiver,
             boolean showEntitlementUi) {
+        mHandler.sendMessage(mHandler.obtainMessage(EVENT_GET_ENTITLEMENT_VALUE,
+                downstream, encodeBool(showEntitlementUi), receiver));
+
+    }
+
+    private void handleGetLatestTetheringEntitlementValue(int downstream, ResultReceiver receiver,
+            boolean showEntitlementUi) {
+
         if (!isTetherProvisioningRequired()) {
             receiver.send(TETHER_ERROR_NO_ERROR, null);
             return;
         }
 
-        final int cacheValue;
-        synchronized (mEntitlementCacheValue) {
-            cacheValue = mEntitlementCacheValue.get(
+        final int cacheValue = mEntitlementCacheValue.get(
                 downstream, TETHER_ERROR_ENTITLEMENT_UNKONWN);
-        }
         if (cacheValue == TETHER_ERROR_NO_ERROR || !showEntitlementUi) {
             receiver.send(cacheValue, null);
         } else {
-            ResultReceiver proxy = buildProxyReceiver(downstream, receiver);
+            ResultReceiver proxy = buildProxyReceiver(downstream, false/* notifyFail */, receiver);
             runUiTetherProvisioning(downstream, proxy);
         }
     }
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java b/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
index 935b795..8427b6e 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetheringConfiguration.java
@@ -30,6 +30,7 @@
 import static com.android.internal.R.array.config_tether_usb_regexs;
 import static com.android.internal.R.array.config_tether_wifi_regexs;
 import static com.android.internal.R.bool.config_tether_upstream_automatic;
+import static com.android.internal.R.integer.config_mobile_hotspot_provision_check_period;
 import static com.android.internal.R.string.config_mobile_hotspot_provision_app_no_ui;
 
 import android.content.ContentResolver;
@@ -94,6 +95,7 @@
 
     public final String[] provisioningApp;
     public final String provisioningAppNoUi;
+    public final int provisioningCheckPeriod;
 
     public final int subId;
 
@@ -121,6 +123,9 @@
 
         provisioningApp = getResourceStringArray(res, config_mobile_hotspot_provision_app);
         provisioningAppNoUi = getProvisioningAppNoUi(res);
+        provisioningCheckPeriod = getResourceInteger(res,
+                config_mobile_hotspot_provision_check_period,
+                0 /* No periodic re-check */);
 
         configLog.log(toString());
     }
@@ -311,6 +316,14 @@
         }
     }
 
+    private static int getResourceInteger(Resources res, int resId, int defaultValue) {
+        try {
+            return res.getInteger(resId);
+        } catch (Resources.NotFoundException e404) {
+            return defaultValue;
+        }
+    }
+
     private static boolean getEnableLegacyDhcpServer(Context ctx) {
         final ContentResolver cr = ctx.getContentResolver();
         final int intVal = Settings.Global.getInt(cr, TETHER_ENABLE_LEGACY_DHCP_SERVER, 0);
diff --git a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
index 173d786..a0aad7c 100644
--- a/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
+++ b/services/core/java/com/android/server/connectivity/tethering/TetheringDependencies.java
@@ -83,8 +83,8 @@
      * Get a reference to the EntitlementManager to be used by tethering.
      */
     public EntitlementManager getEntitlementManager(Context ctx, StateMachine target,
-            SharedLog log, MockableSystemProperties systemProperties) {
-        return new EntitlementManager(ctx, target, log, systemProperties);
+            SharedLog log, int what, MockableSystemProperties systemProperties) {
+        return new EntitlementManager(ctx, target, log, what, systemProperties);
     }
 
     /**
diff --git a/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java b/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
index 3ac311b..3a9e21f 100644
--- a/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitor.java
@@ -16,36 +16,32 @@
 
 package com.android.server.connectivity.tethering;
 
-import static android.net.ConnectivityManager.getNetworkTypeName;
-import static android.net.ConnectivityManager.TYPE_NONE;
 import static android.net.ConnectivityManager.TYPE_MOBILE_DUN;
 import static android.net.ConnectivityManager.TYPE_MOBILE_HIPRI;
+import static android.net.ConnectivityManager.TYPE_NONE;
+import static android.net.ConnectivityManager.getNetworkTypeName;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_DUN;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_VPN;
 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
 
 import android.content.Context;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.Process;
 import android.net.ConnectivityManager;
 import android.net.ConnectivityManager.NetworkCallback;
 import android.net.IpPrefix;
-import android.net.LinkAddress;
 import android.net.LinkProperties;
 import android.net.Network;
 import android.net.NetworkCapabilities;
 import android.net.NetworkRequest;
 import android.net.NetworkState;
-import android.net.util.NetworkConstants;
 import android.net.util.PrefixUtils;
 import android.net.util.SharedLog;
+import android.os.Handler;
+import android.os.Process;
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.StateMachine;
 
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Set;
@@ -97,10 +93,13 @@
     private final HashMap<Network, NetworkState> mNetworkMap = new HashMap<>();
     private HashSet<IpPrefix> mLocalPrefixes;
     private ConnectivityManager mCM;
+    private EntitlementManager mEntitlementMgr;
     private NetworkCallback mListenAllCallback;
     private NetworkCallback mDefaultNetworkCallback;
     private NetworkCallback mMobileNetworkCallback;
     private boolean mDunRequired;
+    // Whether the current default upstream is mobile or not.
+    private boolean mIsDefaultCellularUpstream;
     // The current system default network (not really used yet).
     private Network mDefaultInternetNetwork;
     // The current upstream network used for tethering.
@@ -113,6 +112,7 @@
         mLog = log.forSubComponent(TAG);
         mWhat = what;
         mLocalPrefixes = new HashSet<>();
+        mIsDefaultCellularUpstream = false;
     }
 
     @VisibleForTesting
@@ -122,7 +122,15 @@
         mCM = cm;
     }
 
-    public void startTrackDefaultNetwork(NetworkRequest defaultNetworkRequest) {
+    /**
+     * Tracking the system default network. This method should be called when system is ready.
+     *
+     * @param defaultNetworkRequest should be the same as ConnectivityService default request
+     * @param entitle a EntitlementManager object to communicate between EntitlementManager and
+     * UpstreamNetworkMonitor
+     */
+    public void startTrackDefaultNetwork(NetworkRequest defaultNetworkRequest,
+            EntitlementManager entitle) {
         // This is not really a "request", just a way of tracking the system default network.
         // It's guaranteed not to actually bring up any networks because it's the same request
         // as the ConnectivityService default request, and thus shares fate with it. We can't
@@ -133,6 +141,9 @@
             mDefaultNetworkCallback = new UpstreamNetworkCallback(CALLBACK_DEFAULT_INTERNET);
             cm().requestNetwork(trackDefaultRequest, mDefaultNetworkCallback, mHandler);
         }
+        if (mEntitlementMgr == null) {
+            mEntitlementMgr = entitle;
+        }
     }
 
     public void startObserveAllNetworks() {
@@ -168,11 +179,15 @@
     }
 
     public void registerMobileNetworkRequest() {
+        if (!isCellularUpstreamPermitted()) {
+            mLog.i("registerMobileNetworkRequest() is not permitted");
+            releaseMobileNetworkRequest();
+            return;
+        }
         if (mMobileNetworkCallback != null) {
             mLog.e("registerMobileNetworkRequest() already registered");
             return;
         }
-
         // The following use of the legacy type system cannot be removed until
         // after upstream selection no longer finds networks by legacy type.
         // See also http://b/34364553 .
@@ -206,29 +221,32 @@
     // becomes available and useful we (a) file a request to keep it up as
     // necessary and (b) change all upstream tracking state accordingly (by
     // passing LinkProperties up to Tethering).
-    //
-    // Next TODO: return NetworkState instead of just the type.
     public NetworkState selectPreferredUpstreamType(Iterable<Integer> preferredTypes) {
         final TypeStatePair typeStatePair = findFirstAvailableUpstreamByType(
-                mNetworkMap.values(), preferredTypes);
+                mNetworkMap.values(), preferredTypes, isCellularUpstreamPermitted());
 
         mLog.log("preferred upstream type: " + getNetworkTypeName(typeStatePair.type));
 
         switch (typeStatePair.type) {
             case TYPE_MOBILE_DUN:
             case TYPE_MOBILE_HIPRI:
+                // Tethering just selected mobile upstream in spite of the default network being
+                // not mobile. This can happen because of the priority list.
+                // Notify EntitlementManager to check permission for using mobile upstream.
+                if (!mIsDefaultCellularUpstream) {
+                    mEntitlementMgr.maybeRunProvisioning();
+                }
                 // If we're on DUN, put our own grab on it.
                 registerMobileNetworkRequest();
                 break;
             case TYPE_NONE:
+                // If we found NONE and mobile upstream is permitted we don't want to do this
+                // as we want any previous requests to keep trying to bring up something we can use.
+                if (!isCellularUpstreamPermitted()) releaseMobileNetworkRequest();
                 break;
             default:
-                /* If we've found an active upstream connection that's not DUN/HIPRI
-                 * we should stop any outstanding DUN/HIPRI requests.
-                 *
-                 * If we found NONE we don't want to do this as we want any previous
-                 * requests to keep trying to bring up something we can use.
-                 */
+                // If we've found an active upstream connection that's not DUN/HIPRI
+                // we should stop any outstanding DUN/HIPRI requests.
                 releaseMobileNetworkRequest();
                 break;
         }
@@ -241,10 +259,12 @@
         final NetworkState dfltState = (mDefaultInternetNetwork != null)
                 ? mNetworkMap.get(mDefaultInternetNetwork)
                 : null;
-        if (!mDunRequired) return dfltState;
-
         if (isNetworkUsableAndNotCellular(dfltState)) return dfltState;
 
+        if (!isCellularUpstreamPermitted()) return null;
+
+        if (!mDunRequired) return dfltState;
+
         // Find a DUN network. Note that code in Tethering causes a DUN request
         // to be filed, but this might be moved into this class in future.
         return findFirstDunNetwork(mNetworkMap.values());
@@ -258,6 +278,15 @@
         return (Set<IpPrefix>) mLocalPrefixes.clone();
     }
 
+    private boolean isCellularUpstreamPermitted() {
+        if (mEntitlementMgr != null) {
+            return mEntitlementMgr.isCellularUpstreamPermitted();
+        } else {
+            // This flow should only happens in testing.
+            return true;
+        }
+    }
+
     private void handleAvailable(Network network) {
         if (mNetworkMap.containsKey(network)) return;
 
@@ -388,8 +417,14 @@
         public void onCapabilitiesChanged(Network network, NetworkCapabilities newNc) {
             if (mCallbackType == CALLBACK_DEFAULT_INTERNET) {
                 mDefaultInternetNetwork = network;
+                final boolean newIsCellular = isCellular(newNc);
+                if (mIsDefaultCellularUpstream != newIsCellular) {
+                    mIsDefaultCellularUpstream = newIsCellular;
+                    mEntitlementMgr.notifyUpstream(newIsCellular);
+                }
                 return;
             }
+
             handleNetCap(network, newNc);
         }
 
@@ -424,8 +459,11 @@
         public void onLost(Network network) {
             if (mCallbackType == CALLBACK_DEFAULT_INTERNET) {
                 mDefaultInternetNetwork = null;
+                mIsDefaultCellularUpstream = false;
+                mEntitlementMgr.notifyUpstream(false);
                 return;
             }
+
             handleLost(network);
             // Any non-LISTEN_ALL callback will necessarily concern a network that will
             // also match the LISTEN_ALL callback by construction of the LISTEN_ALL callback.
@@ -454,7 +492,8 @@
     }
 
     private static TypeStatePair findFirstAvailableUpstreamByType(
-            Iterable<NetworkState> netStates, Iterable<Integer> preferredTypes) {
+            Iterable<NetworkState> netStates, Iterable<Integer> preferredTypes,
+            boolean isCellularUpstreamPermitted) {
         final TypeStatePair result = new TypeStatePair();
 
         for (int type : preferredTypes) {
@@ -466,6 +505,10 @@
                        ConnectivityManager.getNetworkTypeName(type));
                 continue;
             }
+            if (!isCellularUpstreamPermitted && isCellular(nc)) {
+                continue;
+            }
+
             nc.setSingleUid(Process.myUid());
 
             for (NetworkState value : netStates) {
diff --git a/services/core/java/com/android/server/contentcapture/ContentCaptureManagerInternal.java b/services/core/java/com/android/server/contentcapture/ContentCaptureManagerInternal.java
index fa7d3fca..ad04b7d 100644
--- a/services/core/java/com/android/server/contentcapture/ContentCaptureManagerInternal.java
+++ b/services/core/java/com/android/server/contentcapture/ContentCaptureManagerInternal.java
@@ -49,6 +49,9 @@
     /**
      * Gets the content capture options for the given user and package, or {@code null} if the
      * package is not whitelisted by the service.
+     *
+     * <p><b>NOTE: </b>this method is called by the {@code ActivityManager} service and hence cannot
+     * hold the main service lock.
      */
     @Nullable
     public abstract ContentCaptureOptions getOptionsForPackage(@UserIdInt int userId,
diff --git a/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java b/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java
index df0dc77..b4c7dd3 100755
--- a/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java
+++ b/services/core/java/com/android/server/hdmi/DeviceDiscoveryAction.java
@@ -335,7 +335,6 @@
         current.mDeviceType = params[2] & 0xFF;
         current.mDisplayName = HdmiUtils.getDefaultDeviceName(current.mDeviceType);
 
-        // TODO(amyjojo): check if non-TV device needs to update cec switch info.
         // This is to manager CEC device separately in case they don't have address.
         if (mIsTvDevice) {
             tv().updateCecSwitchInfo(current.mLogicalAddress, current.mDeviceType,
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
index 2026957..a2882de 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceAudioSystem.java
@@ -314,7 +314,7 @@
         super.disableDevice(initiatedByCec, callback);
         assertRunOnServiceThread();
         mService.unregisterTvInputCallback(mTvInputCallback);
-        // TODO(amyjojo): check disableDevice and onStandby behaviors per spec
+        // TODO(b/129088603): check disableDevice and onStandby behaviors per spec
     }
 
     @Override
@@ -465,15 +465,6 @@
 
     @Override
     @ServiceThreadOnly
-    protected boolean handleReportAudioStatus(HdmiCecMessage message) {
-        assertRunOnServiceThread();
-        // TODO(amyjojo): implement report audio status handler
-        HdmiLogger.debug(TAG + "Stub handleReportAudioStatus");
-        return true;
-    }
-
-    @Override
-    @ServiceThreadOnly
     protected boolean handleInitiateArc(HdmiCecMessage message) {
         assertRunOnServiceThread();
         // TODO(amyjojo): implement initiate arc handler
@@ -970,7 +961,10 @@
     @ServiceThreadOnly
     void doManualPortSwitching(int portId, IHdmiControlCallback callback) {
         assertRunOnServiceThread();
-        // TODO: validate port ID
+        if (!mService.isValidPortId(portId)) {
+            invokeCallback(callback, HdmiControlManager.RESULT_TARGET_NOT_AVAILABLE);
+            return;
+        }
         if (portId == getLocalActivePort()) {
             invokeCallback(callback, HdmiControlManager.RESULT_SUCCESS);
             return;
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index f5adb01..3398d36 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -1764,7 +1764,7 @@
         }
 
         @Override
-        // TODO(AMYJOJO): add a result callback
+        // TODO(b/128427908): add a result callback
         public void askRemoteDeviceToBecomeActiveSource(int physicalAddress) {
             enforceAccessPermission();
             runOnServiceThread(new Runnable() {
diff --git a/services/core/java/com/android/server/incident/IncidentCompanionService.java b/services/core/java/com/android/server/incident/IncidentCompanionService.java
index 55e054b..5c69c1d 100644
--- a/services/core/java/com/android/server/incident/IncidentCompanionService.java
+++ b/services/core/java/com/android/server/incident/IncidentCompanionService.java
@@ -300,7 +300,7 @@
                         android.Manifest.permission.DUMP, null);
                 getContext().enforceCallingOrSelfPermission(
                         android.Manifest.permission.PACKAGE_USAGE_STATS, null);
-                if (pkg == null) {
+                if (pkg != null) {
                     enforceCallerIsSameApp(pkg);
                 }
             }
diff --git a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
index ed894ee..098b0e9 100644
--- a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
+++ b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
@@ -181,9 +181,8 @@
 
         mServiceNameResolver = serviceNameResolver;
         if (mServiceNameResolver != null) {
-            mServiceNameResolver
-                    .setOnTemporaryServiceNameChangedCallback(
-                            (u, s) -> updateCachedServiceLocked(u));
+            mServiceNameResolver.setOnTemporaryServiceNameChangedCallback(
+                    (u, s, t) -> onServiceNameChanged(u, s, t));
 
         }
         if (disallowProperty == null) {
@@ -582,6 +581,23 @@
     }
 
     /**
+     * Called when the service name changed (typically when using temporary services).
+     *
+     * <p>By default, it calls {@link #updateCachedServiceLocked(int)}; subclasses must either call
+     * that same method, or {@code super.onServiceNameChanged()}.
+     *
+     * @param userId user handle.
+     * @param serviceName the new service name.
+     * @param isTemporary whether the new service is temporary.
+     */
+    protected void onServiceNameChanged(@UserIdInt int userId, @Nullable String serviceName,
+            boolean isTemporary) {
+        synchronized (mLock) {
+            updateCachedServiceLocked(userId);
+        }
+    }
+
+    /**
      * Visits all services in the cache.
      */
     @GuardedBy("mLock")
@@ -600,6 +616,23 @@
         mServicesCache.clear();
     }
 
+    /**
+     * Asserts that the given package name is owned by the UID making this call.
+     *
+     * @throws SecurityException when it's not...
+     */
+    protected final void assertCalledByPackageOwner(@NonNull String packageName) {
+        Preconditions.checkNotNull(packageName);
+        final int uid = Binder.getCallingUid();
+        final String[] packages = getContext().getPackageManager().getPackagesForUid(uid);
+        if (packages != null) {
+            for (String candidate : packages) {
+                if (packageName.equals(candidate)) return; // Found it
+            }
+        }
+        throw new SecurityException("UID " + uid + " does not own " + packageName);
+    }
+
     // TODO(b/117779333): support proto
     protected void dumpLocked(@NonNull String prefix, @NonNull PrintWriter pw) {
         boolean realDebug = debug;
diff --git a/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java b/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java
index d204813..35d5956 100644
--- a/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java
+++ b/services/core/java/com/android/server/infra/FrameworkResourcesServiceNameResolver.java
@@ -155,7 +155,8 @@
             }
             mTemporaryServiceExpiration = SystemClock.elapsedRealtime() + durationMs;
             mTemporaryHandler.sendEmptyMessageDelayed(MSG_RESET_TEMPORARY_SERVICE, durationMs);
-            notifyTemporaryServiceNameChangedLocked(userId, componentName);
+            notifyTemporaryServiceNameChangedLocked(userId, componentName,
+                    /* isTemporary= */ true);
         }
     }
 
@@ -169,7 +170,8 @@
                 mTemporaryHandler.removeMessages(MSG_RESET_TEMPORARY_SERVICE);
                 mTemporaryHandler = null;
             }
-            notifyTemporaryServiceNameChangedLocked(userId, /* newTemporaryName= */ null);
+            notifyTemporaryServiceNameChangedLocked(userId, /* newTemporaryName= */ null,
+                    /* isTemporary= */ false);
         }
     }
 
@@ -235,9 +237,9 @@
     }
 
     private void notifyTemporaryServiceNameChangedLocked(@UserIdInt int userId,
-            @Nullable String newTemporaryName) {
+            @Nullable String newTemporaryName, boolean isTemporary) {
         if (mOnSetCallback != null) {
-            mOnSetCallback.onNameResolved(userId, newTemporaryName);
+            mOnSetCallback.onNameResolved(userId, newTemporaryName, isTemporary);
         }
     }
 }
diff --git a/services/core/java/com/android/server/infra/ServiceNameResolver.java b/services/core/java/com/android/server/infra/ServiceNameResolver.java
index 8c348ebb..e20c459 100644
--- a/services/core/java/com/android/server/infra/ServiceNameResolver.java
+++ b/services/core/java/com/android/server/infra/ServiceNameResolver.java
@@ -39,7 +39,8 @@
         /**
          * The name change callback.
          */
-        void onNameResolved(@UserIdInt int userId, @Nullable String serviceName);
+        void onNameResolved(@UserIdInt int userId, @Nullable String serviceName,
+                boolean isTemporary);
     }
 
     /**
diff --git a/services/core/java/com/android/server/job/controllers/QuotaController.java b/services/core/java/com/android/server/job/controllers/QuotaController.java
index 5a0b991..1820acf 100644
--- a/services/core/java/com/android/server/job/controllers/QuotaController.java
+++ b/services/core/java/com/android/server/job/controllers/QuotaController.java
@@ -769,6 +769,91 @@
                 mMaxExecutionTimeMs - stats.executionTimeInMaxPeriodMs);
     }
 
+    /**
+     * Returns the amount of time, in milliseconds, until the package would have reached its
+     * duration quota, assuming it has a job counting towards its quota the entire time. This takes
+     * into account any {@link TimingSession}s that may roll out of the window as the job is
+     * running.
+     */
+    @VisibleForTesting
+    long getTimeUntilQuotaConsumedLocked(final int userId, @NonNull final String packageName) {
+        final long nowElapsed = sElapsedRealtimeClock.millis();
+        final int standbyBucket = JobSchedulerService.standbyBucketForPackage(
+                packageName, userId, nowElapsed);
+        if (standbyBucket == NEVER_INDEX) {
+            return 0;
+        }
+        List<TimingSession> sessions = mTimingSessions.get(userId, packageName);
+        if (sessions == null || sessions.size() == 0) {
+            return mAllowedTimePerPeriodMs;
+        }
+
+        final ExecutionStats stats = getExecutionStatsLocked(userId, packageName, standbyBucket);
+        final long startWindowElapsed = nowElapsed - stats.windowSizeMs;
+        final long startMaxElapsed = nowElapsed - MAX_PERIOD_MS;
+        final long allowedTimeRemainingMs = mAllowedTimePerPeriodMs - stats.executionTimeInWindowMs;
+        final long maxExecutionTimeRemainingMs =
+                mMaxExecutionTimeMs - stats.executionTimeInMaxPeriodMs;
+
+        // Regular ACTIVE case. Since the bucket size equals the allowed time, the app jobs can
+        // essentially run until they reach the maximum limit.
+        if (stats.windowSizeMs == mAllowedTimePerPeriodMs) {
+            return calculateTimeUntilQuotaConsumedLocked(
+                    sessions, startMaxElapsed, maxExecutionTimeRemainingMs);
+        }
+
+        // Need to check both max time and period time in case one is less than the other.
+        // For example, max time remaining could be less than bucket time remaining, but sessions
+        // contributing to the max time remaining could phase out enough that we'd want to use the
+        // bucket value.
+        return Math.min(
+                calculateTimeUntilQuotaConsumedLocked(
+                        sessions, startMaxElapsed, maxExecutionTimeRemainingMs),
+                calculateTimeUntilQuotaConsumedLocked(
+                        sessions, startWindowElapsed, allowedTimeRemainingMs));
+    }
+
+    /**
+     * Calculates how much time it will take, in milliseconds, until the quota is fully consumed.
+     *
+     * @param windowStartElapsed The start of the window, in the elapsed realtime timebase.
+     * @param deadSpaceMs        How much time can be allowed to count towards the quota
+     */
+    private long calculateTimeUntilQuotaConsumedLocked(@NonNull List<TimingSession> sessions,
+            final long windowStartElapsed, long deadSpaceMs) {
+        long timeUntilQuotaConsumedMs = 0;
+        long start = windowStartElapsed;
+        for (int i = 0; i < sessions.size(); ++i) {
+            TimingSession session = sessions.get(i);
+
+            if (session.endTimeElapsed < windowStartElapsed) {
+                // Outside of window. Ignore.
+                continue;
+            } else if (session.startTimeElapsed <= windowStartElapsed) {
+                // Overlapping session. Can extend time by portion of session in window.
+                timeUntilQuotaConsumedMs += session.endTimeElapsed - windowStartElapsed;
+                start = session.endTimeElapsed;
+            } else {
+                // Completely within the window. Can only consider if there's enough dead space
+                // to get to the start of the session.
+                long diff = session.startTimeElapsed - start;
+                if (diff > deadSpaceMs) {
+                    break;
+                }
+                timeUntilQuotaConsumedMs += diff
+                        + (session.endTimeElapsed - session.startTimeElapsed);
+                deadSpaceMs -= diff;
+                start = session.endTimeElapsed;
+            }
+        }
+        // Will be non-zero if the loop didn't look at any sessions.
+        timeUntilQuotaConsumedMs += deadSpaceMs;
+        if (timeUntilQuotaConsumedMs > mMaxExecutionTimeMs) {
+            Slog.wtf(TAG, "Calculated quota consumed time too high: " + timeUntilQuotaConsumedMs);
+        }
+        return timeUntilQuotaConsumedMs;
+    }
+
     /** Returns the execution stats of the app in the most recent window. */
     @VisibleForTesting
     @NonNull
@@ -1483,7 +1568,7 @@
                     return;
                 }
                 Message msg = mHandler.obtainMessage(MSG_REACHED_QUOTA, mPkg);
-                final long timeRemainingMs = getRemainingExecutionTimeLocked(mPkg.userId,
+                final long timeRemainingMs = getTimeUntilQuotaConsumedLocked(mPkg.userId,
                         mPkg.packageName);
                 if (DEBUG) {
                     Slog.i(TAG, "Job for " + mPkg + " has " + timeRemainingMs + "ms left.");
@@ -1642,6 +1727,8 @@
                             // job is currently running.
                             // Reschedule message
                             Message rescheduleMsg = obtainMessage(MSG_REACHED_QUOTA, pkg);
+                            timeRemainingMs = getTimeUntilQuotaConsumedLocked(pkg.userId,
+                                    pkg.packageName);
                             if (DEBUG) {
                                 Slog.d(TAG, pkg + " has " + timeRemainingMs + "ms left.");
                             }
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index dddb7ef..54ec4f2 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -84,6 +84,7 @@
 
 import android.Manifest;
 import android.Manifest.permission;
+import android.annotation.CallbackExecutor;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
@@ -107,6 +108,8 @@
 import android.app.admin.DeviceAdminInfo;
 import android.app.admin.DevicePolicyManagerInternal;
 import android.app.backup.BackupManager;
+import android.app.role.OnRoleHoldersChangedListener;
+import android.app.role.RoleManager;
 import android.app.usage.UsageEvents;
 import android.app.usage.UsageStatsManagerInternal;
 import android.companion.ICompanionDeviceManager;
@@ -151,6 +154,7 @@
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.os.VibrationEffect;
 import android.os.Vibrator;
 import android.provider.DeviceConfig;
@@ -216,7 +220,6 @@
 import com.android.server.notification.ManagedServices.ManagedServiceInfo;
 import com.android.server.notification.ManagedServices.UserProfiles;
 import com.android.server.pm.PackageManagerService;
-import com.android.server.pm.UserManagerService;
 import com.android.server.policy.PhoneWindowManager;
 import com.android.server.statusbar.StatusBarManagerInternal;
 import com.android.server.uri.UriGrantsManagerInternal;
@@ -249,6 +252,7 @@
 import java.util.Map.Entry;
 import java.util.Objects;
 import java.util.Set;
+import java.util.concurrent.Executor;
 import java.util.concurrent.TimeUnit;
 import java.util.function.BiConsumer;
 
@@ -300,6 +304,12 @@
             Adjustment.KEY_TEXT_REPLIES,
             Adjustment.KEY_USER_SENTIMENT};
 
+    static final String[] NON_BLOCKABLE_DEFAULT_ROLES = new String[] {
+            RoleManager.ROLE_DIALER,
+            RoleManager.ROLE_SMS,
+            RoleManager.ROLE_EMERGENCY
+    };
+
     // When #matchesCallFilter is called from the ringer, wait at most
     // 3s to resolve the contacts. This timeout is required since
     // ContactsProvider might take a long time to start up.
@@ -343,6 +353,8 @@
     private IDeviceIdleController mDeviceIdleController;
     private IUriGrantsManager mUgm;
     private UriGrantsManagerInternal mUgmInternal;
+    private RoleObserver mRoleObserver;
+    private UserManager mUm;
 
     final IBinder mForegroundToken = new Binder();
     private WorkerHandler mHandler;
@@ -553,18 +565,13 @@
         }
     }
 
-    UserManagerService getUserManagerService() {
-        return UserManagerService.getInstance();
-    }
-
     void readPolicyXml(InputStream stream, boolean forRestore, int userId)
             throws XmlPullParserException, NumberFormatException, IOException {
         final XmlPullParser parser = Xml.newPullParser();
         parser.setInput(stream, StandardCharsets.UTF_8.name());
         XmlUtils.beginDocument(parser, TAG_NOTIFICATION_POLICY);
         boolean migratedManagedServices = false;
-        boolean ineligibleForManagedServices = forRestore
-                && getUserManagerService().isManagedProfile(userId);
+        boolean ineligibleForManagedServices = forRestore && mUm.isManagedProfile(userId);
         int outerDepth = parser.getDepth();
         while (XmlUtils.nextElementWithin(parser, outerDepth)) {
             if (ZenModeConfig.ZEN_TAG.equals(parser.getName())) {
@@ -612,7 +619,8 @@
         mAssistants.resetDefaultAssistantsIfNecessary();
     }
 
-    private void loadPolicyFile() {
+    @VisibleForTesting
+    protected void loadPolicyFile() {
         if (DBG) Slog.d(TAG, "loadPolicyFile");
         synchronized (mPolicyFile) {
             InputStream infile = null;
@@ -1530,7 +1538,8 @@
             NotificationUsageStats usageStats, AtomicFile policyFile,
             ActivityManager activityManager, GroupHelper groupHelper, IActivityManager am,
             UsageStatsManagerInternal appUsageStats, DevicePolicyManagerInternal dpm,
-            IUriGrantsManager ugm, UriGrantsManagerInternal ugmInternal, AppOpsManager appOps) {
+            IUriGrantsManager ugm, UriGrantsManagerInternal ugmInternal, AppOpsManager appOps,
+            UserManager userManager) {
         Resources resources = getContext().getResources();
         mMaxPackageEnqueueRate = Settings.Global.getFloat(getContext().getContentResolver(),
                 Settings.Global.MAX_NOTIFICATION_ENQUEUE_RATE,
@@ -1552,6 +1561,7 @@
         mDeviceIdleController = IDeviceIdleController.Stub.asInterface(
                 ServiceManager.getService(Context.DEVICE_IDLE_CONTROLLER));
         mDpm = dpm;
+        mUm = userManager;
 
         mHandler = new WorkerHandler(looper);
         mRankingThread.start();
@@ -1697,14 +1707,16 @@
                         AppGlobals.getPackageManager()),
                 new ConditionProviders(getContext(), mUserProfiles, AppGlobals.getPackageManager()),
                 null, snoozeHelper, new NotificationUsageStats(getContext()),
-                new AtomicFile(new File(systemDir, "notification_policy.xml"), "notification-policy"),
+                new AtomicFile(new File(
+                        systemDir, "notification_policy.xml"), "notification-policy"),
                 (ActivityManager) getContext().getSystemService(Context.ACTIVITY_SERVICE),
                 getGroupHelper(), ActivityManager.getService(),
                 LocalServices.getService(UsageStatsManagerInternal.class),
                 LocalServices.getService(DevicePolicyManagerInternal.class),
                 UriGrantsManager.getService(),
                 LocalServices.getService(UriGrantsManagerInternal.class),
-                (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE));
+                (AppOpsManager) getContext().getSystemService(Context.APP_OPS_SERVICE),
+                getContext().getSystemService(UserManager.class));
 
         // register for various Intents
         IntentFilter filter = new IntentFilter();
@@ -1827,6 +1839,9 @@
             mAudioManagerInternal = getLocalService(AudioManagerInternal.class);
             mWindowManagerInternal = LocalServices.getService(WindowManagerInternal.class);
             mZenModeHelper.onSystemReady();
+            mRoleObserver = new RoleObserver(getContext().getSystemService(RoleManager.class),
+                    getContext().getMainExecutor());
+            mRoleObserver.init();
         } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
             // This observer will force an update when observe is called, causing us to
             // bind to listener services.
@@ -2406,6 +2421,11 @@
         @Override
         public boolean areNotificationsEnabledForPackage(String pkg, int uid) {
             checkCallerIsSystemOrSameApp(pkg);
+            if (UserHandle.getCallingUserId() != UserHandle.getUserId(uid)) {
+                getContext().enforceCallingPermission(
+                        android.Manifest.permission.INTERACT_ACROSS_USERS,
+                        "canNotifyAsPackage for uid " + uid);
+            }
 
             return mPreferencesHelper.getImportance(pkg, uid) != IMPORTANCE_NONE;
         }
@@ -2419,6 +2439,13 @@
         public boolean areBubblesAllowedForPackage(String pkg, int uid) {
             enforceSystemOrSystemUIOrSamePackage(pkg,
                     "Caller not system or systemui or same package");
+
+            if (UserHandle.getCallingUserId() != UserHandle.getUserId(uid)) {
+                getContext().enforceCallingPermission(
+                        android.Manifest.permission.INTERACT_ACROSS_USERS,
+                        "canNotifyAsPackage for uid " + uid);
+            }
+
             return mPreferencesHelper.areBubblesAllowed(pkg, uid);
         }
 
@@ -4728,6 +4755,20 @@
         }
     }
 
+    /**
+     * Updates the flags for this notification to reflect whether it is a bubble or not.
+     */
+    private void flagNotificationForBubbles(NotificationRecord r, String pkg, int userId) {
+        Notification notification = r.getNotification();
+        boolean canBubble = mPreferencesHelper.areBubblesAllowed(pkg, userId)
+                && r.getChannel().canBubble();
+        if (notification.getBubbleMetadata() != null && canBubble) {
+            notification.flags |= Notification.FLAG_BUBBLE;
+        } else {
+            notification.flags &= ~Notification.FLAG_BUBBLE;
+        }
+    }
+
     private void doChannelWarningToast(CharSequence toastText) {
         Binder.withCleanCallingIdentity(() -> {
             final int defaultWarningEnabled = Build.IS_DEBUGGABLE ? 1 : 0;
@@ -5083,6 +5124,9 @@
                 final int id = n.getId();
                 final String tag = n.getTag();
 
+                // We need to fix the notification up a little for bubbles
+                flagNotificationForBubbles(r, pkg, callingUid);
+
                 // Handle grouped notifications and bail out early if we
                 // can to avoid extracting signals.
                 handleGroupedNotificationLocked(r, old, callingUid, callingPid);
@@ -8062,6 +8106,98 @@
         }
     }
 
+    class RoleObserver implements OnRoleHoldersChangedListener {
+        // Role name : user id : list of approved packages
+        private ArrayMap<String, ArrayMap<Integer, ArraySet<String>>> mNonBlockableDefaultApps;
+
+        private final RoleManager mRm;
+        private final Executor mExecutor;
+
+        RoleObserver(@NonNull RoleManager roleManager,
+                @NonNull @CallbackExecutor Executor executor) {
+            mRm = roleManager;
+            mExecutor = executor;
+        }
+
+        public void init() {
+            List<UserInfo> users = mUm.getUsers();
+            mNonBlockableDefaultApps = new ArrayMap<>();
+            for (int i = 0; i < NON_BLOCKABLE_DEFAULT_ROLES.length; i++) {
+                final ArrayMap<Integer, ArraySet<String>> userToApprovedList = new ArrayMap<>();
+                mNonBlockableDefaultApps.put(NON_BLOCKABLE_DEFAULT_ROLES[i], userToApprovedList);
+                for (int j = 0; j < users.size(); j++) {
+                    Integer userId = users.get(j).getUserHandle().getIdentifier();
+                    ArraySet<String> approvedForUserId = new ArraySet<>(mRm.getRoleHoldersAsUser(
+                            NON_BLOCKABLE_DEFAULT_ROLES[i], UserHandle.of(userId)));
+                    userToApprovedList.put(userId, approvedForUserId);
+                    mPreferencesHelper.updateDefaultApps(userId, null, approvedForUserId);
+                }
+            }
+
+            mRm.addOnRoleHoldersChangedListenerAsUser(mExecutor, this, UserHandle.ALL);
+        }
+
+        @VisibleForTesting
+        public boolean isApprovedPackageForRoleForUser(String role, String pkg, int userId) {
+            return mNonBlockableDefaultApps.get(role).get(userId).contains(pkg);
+        }
+
+        /**
+         * Convert the assistant-role holder into settings. The rest of the system uses the
+         * settings.
+         *
+         * @param roleName the name of the role whose holders are changed
+         * @param user the user for this role holder change
+         */
+        @Override
+        public void onRoleHoldersChanged(@NonNull String roleName, @NonNull UserHandle user) {
+            // we only care about a couple of the roles they'll tell us about
+            boolean relevantChange = false;
+            for (int i = 0; i < NON_BLOCKABLE_DEFAULT_ROLES.length; i++) {
+                if (NON_BLOCKABLE_DEFAULT_ROLES[i].equals(roleName)) {
+                    relevantChange = true;
+                    break;
+                }
+            }
+
+            if (!relevantChange) {
+                return;
+            }
+
+            ArraySet<String> roleHolders = new ArraySet<>(mRm.getRoleHoldersAsUser(roleName, user));
+
+            // find the diff
+            ArrayMap<Integer, ArraySet<String>> prevApprovedForRole =
+                    mNonBlockableDefaultApps.getOrDefault(roleName, new ArrayMap<>());
+            ArraySet<String> previouslyApproved =
+                    prevApprovedForRole.getOrDefault(user.getIdentifier(), new ArraySet<>());
+
+            ArraySet<String> toRemove = new ArraySet<>();
+            ArraySet<String> toAdd = new ArraySet<>();
+
+            for (String previous : previouslyApproved) {
+                if (!roleHolders.contains(previous)) {
+                    toRemove.add(previous);
+                }
+            }
+            for (String nowApproved : roleHolders) {
+                if (!previouslyApproved.contains(nowApproved)) {
+                    toAdd.add(nowApproved);
+                }
+            }
+
+            // store newly approved apps
+            prevApprovedForRole.put(user.getIdentifier(), roleHolders);
+            mNonBlockableDefaultApps.put(roleName, prevApprovedForRole);
+
+            // update what apps can be blocked
+            mPreferencesHelper.updateDefaultApps(user.getIdentifier(), toRemove, toAdd);
+
+            // RoleManager is the source of truth for this data so we don't need to trigger a
+            // write of the notification policy xml for this change
+        }
+    }
+
     public static final class DumpFilter {
         public boolean filtered = false;
         public String pkgFilter;
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index de93120..4cc08d8 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -783,7 +783,8 @@
         // Consider Notification Assistant and system overrides to importance. If both, system wins.
         if (!getChannel().hasUserSetImportance()
                 && mAssistantImportance != IMPORTANCE_UNSPECIFIED
-                && !getChannel().isImportanceLockedByOEM()) {
+                && !getChannel().isImportanceLockedByOEM()
+                && !getChannel().isImportanceLockedByCriticalDeviceFunction()) {
             mImportance = mAssistantImportance;
             mImportanceExplanationCode = MetricsEvent.IMPORTANCE_EXPLANATION_ASST;
         }
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 660309c..a3e90dc 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -37,6 +37,8 @@
 import android.service.notification.RankingHelperProto;
 import android.text.TextUtils;
 import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Pair;
 import android.util.Slog;
 import android.util.SparseBooleanArray;
 import android.util.proto.ProtoOutputStream;
@@ -100,6 +102,7 @@
     private static final boolean DEFAULT_SHOW_BADGE = true;
     private static final boolean DEFAULT_ALLOW_BUBBLE = true;
     private static final boolean DEFAULT_OEM_LOCKED_IMPORTANCE  = false;
+    private static final boolean DEFAULT_APP_LOCKED_IMPORTANCE  = false;
 
     /**
      * Default value for what fields are user locked. See {@link LockableAppFields} for all lockable
@@ -659,6 +662,7 @@
                 channel.setImportanceLockedByOEM(true);
             }
         }
+        channel.setImportanceLockedByCriticalDeviceFunction(r.defaultAppLockedImportance);
         if (channel.getLockscreenVisibility() == Notification.VISIBILITY_PUBLIC) {
             channel.setLockscreenVisibility(
                     NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE);
@@ -707,6 +711,10 @@
         if (updatedChannel.isImportanceLockedByOEM()) {
             updatedChannel.setImportance(channel.getImportance());
         }
+        updatedChannel.setImportanceLockedByCriticalDeviceFunction(r.defaultAppLockedImportance);
+        if (updatedChannel.isImportanceLockedByCriticalDeviceFunction()) {
+            updatedChannel.setImportance(channel.getImportance());
+        }
 
         r.channels.put(updatedChannel.getId(), updatedChannel);
 
@@ -844,6 +852,26 @@
         }
     }
 
+    public void updateDefaultApps(int userId, ArraySet<String> toRemove, ArraySet<String> toAdd) {
+        synchronized (mPackagePreferences) {
+            for (PackagePreferences p : mPackagePreferences.values()) {
+                if (userId == UserHandle.getUserId(p.uid)) {
+                    if (toRemove != null && toRemove.contains(p.pkg)) {
+                        p.defaultAppLockedImportance = false;
+                        for (NotificationChannel channel : p.channels.values()) {
+                            channel.setImportanceLockedByCriticalDeviceFunction(false);
+                        }
+                    } else if (toAdd != null && toAdd.contains(p.pkg)) {
+                        p.defaultAppLockedImportance = true;
+                        for (NotificationChannel channel : p.channels.values()) {
+                            channel.setImportanceLockedByCriticalDeviceFunction(true);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
     public NotificationChannelGroup getNotificationChannelGroupWithChannels(String pkg,
             int uid, String groupId, boolean includeDeleted) {
         Preconditions.checkNotNull(pkg);
@@ -1729,8 +1757,11 @@
         boolean showBadge = DEFAULT_SHOW_BADGE;
         boolean allowBubble = DEFAULT_ALLOW_BUBBLE;
         int lockedAppFields = DEFAULT_LOCKED_APP_FIELDS;
+        // these fields are loaded on boot from a different source of truth and so are not
+        // written to notification policy xml
         boolean oemLockedImportance = DEFAULT_OEM_LOCKED_IMPORTANCE;
         List<String> futureOemLockedChannels = new ArrayList<>();
+        boolean defaultAppLockedImportance = DEFAULT_APP_LOCKED_IMPORTANCE;
 
         Delegate delegate = null;
         ArrayMap<String, NotificationChannel> channels = new ArrayMap<>();
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index ad17549..afa5ae9 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -808,7 +808,7 @@
 
         final PackageDeleteObserverAdapter adapter = new PackageDeleteObserverAdapter(mContext,
                 statusReceiver, versionedPackage.getPackageName(),
-                canSilentlyInstallPackage, userId);
+                !canSilentlyInstallPackage, userId);
         if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DELETE_PACKAGES)
                     == PackageManager.PERMISSION_GRANTED) {
             // Sweet, call straight through!
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 81448b7..3833afc 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1315,8 +1315,11 @@
 
     static final int WRITE_SETTINGS_DELAY = 10*1000;  // 10 seconds
 
-    // Delay time in millisecs
-    static final int BROADCAST_DELAY = 10 * 1000;
+    private static final long BROADCAST_DELAY_DURING_STARTUP = 10 * 1000L; // 10 seconds (in millis)
+    private static final long BROADCAST_DELAY = 1 * 1000L; // 1 second (in millis)
+
+    // When the service constructor finished plus a delay (used for broadcast delay computation)
+    private long mServiceStartWithDelay;
 
     private static final long DEFAULT_UNUSED_STATIC_SHARED_LIB_MIN_CACHE_PERIOD =
             2 * 60 * 60 * 1000L; /* two hours */
@@ -1938,8 +1941,13 @@
                 // Send broadcast package appeared if external for all users
                 if (isExternal(res.pkg)) {
                     if (!update) {
+                        final StorageManager storage =
+                                mContext.getSystemService(StorageManager.class);
+                        VolumeInfo volume =
+                                storage.findVolumeByUuid(
+                                        res.pkg.applicationInfo.storageUuid.toString());
                         int packageExternalStorageType =
-                                getPackageExternalStorageType(res.pkg);
+                                getPackageExternalStorageType(volume, isExternal(res.pkg));
                         // If the package was installed externally, log it.
                         if (packageExternalStorageType != StorageEnums.UNKNOWN) {
                             StatsLog.write(StatsLog.APP_INSTALL_ON_EXTERNAL_STORAGE_REPORTED,
@@ -2036,15 +2044,16 @@
 
     /**
      * Gets the type of the external storage a package is installed on.
-     * @param pkg The package for which to get the external storage type.
-     * @return {@link StorageEnum#TYPE_UNKNOWN} if it is not stored externally or the corresponding
-     * {@link StorageEnum} storage type value if it is.
+     * @param packageVolume The storage volume of the package.
+     * @param packageIsExternal true if the package is currently installed on
+     * external/removable/unprotected storage.
+     * @return {@link StorageEnum#TYPE_UNKNOWN} if the package is not stored externally or the
+     * corresponding {@link StorageEnum} storage type value if it is.
      */
-    private int getPackageExternalStorageType(PackageParser.Package pkg) {
-        final StorageManager storage = mContext.getSystemService(StorageManager.class);
-        VolumeInfo volume = storage.findVolumeByUuid(pkg.applicationInfo.storageUuid.toString());
-        if (volume != null) {
-            DiskInfo disk = volume.getDisk();
+    private static int getPackageExternalStorageType(VolumeInfo packageVolume,
+            boolean packageIsExternal) {
+        if (packageVolume != null) {
+            DiskInfo disk = packageVolume.getDisk();
             if (disk != null) {
                 if (disk.isSd()) {
                     return StorageEnums.SD_CARD;
@@ -2052,7 +2061,7 @@
                 if (disk.isUsb()) {
                     return StorageEnums.USB;
                 }
-                if (isExternal(pkg)) {
+                if (packageIsExternal) {
                     return StorageEnums.OTHER;
                 }
             }
@@ -2962,7 +2971,7 @@
 
             // Now that we know all of the shared libraries, update all clients to have
             // the correct library paths.
-            updateAllSharedLibrariesLPw(null);
+            updateAllSharedLibrariesLocked(null, Collections.unmodifiableMap(mPackages));
 
             for (SharedUserSetting setting : mSettings.getAllSharedUsersLPw()) {
                 // NOTE: We ignore potential failures here during a system scan (like
@@ -3217,6 +3226,8 @@
         // once we have a booted system.
         mInstaller.setWarnIfHeld(mPackages);
 
+        mServiceStartWithDelay = SystemClock.uptimeMillis() + (60 * 1000L);
+
         Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
     }
 
@@ -10011,11 +10022,11 @@
     }
 
     @GuardedBy("mPackages")
-    private void updateSharedLibrariesLPr(PackageParser.Package pkg,
-            PackageParser.Package changingLib) throws PackageManagerException {
+    private void updateSharedLibrariesLocked(PackageParser.Package pkg,
+            PackageParser.Package changingLib, Map<String, PackageParser.Package> availablePackages)
+                    throws PackageManagerException {
         final ArrayList<SharedLibraryInfo> sharedLibraryInfos =
-                collectSharedLibraryInfos(pkg, Collections.unmodifiableMap(mPackages),
-                        mSharedLibraries, null);
+                collectSharedLibraryInfos(pkg, availablePackages, mSharedLibraries, null);
         executeSharedLibrariesUpdateLPr(pkg, changingLib, sharedLibraryInfos);
     }
 
@@ -10107,7 +10118,6 @@
                                     + " library " + libName + " version "
                                     + libraryInfo.getLongVersion() + "; failing!");
                     }
-
                     PackageParser.Package libPkg =
                             availablePackages.get(libraryInfo.getPackageName());
                     if (libPkg == null) {
@@ -10115,12 +10125,8 @@
                                 "Package " + packageName + " requires unavailable static shared"
                                         + " library; failing!");
                     }
-
                     final String[] expectedCertDigests = requiredCertDigests[i];
-
-
                     if (expectedCertDigests.length > 1) {
-
                         // For apps targeting O MR1 we require explicit enumeration of all certs.
                         final String[] libCertDigests = (targetSdk >= Build.VERSION_CODES.O_MR1)
                                 ? PackageUtils.computeSignaturesSha256Digests(
@@ -10152,7 +10158,6 @@
                             }
                         }
                     } else {
-
                         // lib signing cert could have rotated beyond the one expected, check to see
                         // if the new one has been blessed by the old
                         if (!libPkg.mSigningDetails.hasSha256Certificate(
@@ -10164,7 +10169,6 @@
                         }
                     }
                 }
-
                 if (outUsedLibraries == null) {
                     outUsedLibraries = new ArrayList<>();
                 }
@@ -10175,7 +10179,7 @@
     }
 
     private static boolean hasString(List<String> list, List<String> which) {
-        if (list == null) {
+        if (list == null || which == null) {
             return false;
         }
         for (int i=list.size()-1; i>=0; i--) {
@@ -10189,39 +10193,63 @@
     }
 
     @GuardedBy("mPackages")
-    private ArrayList<PackageParser.Package> updateAllSharedLibrariesLPw(
-            PackageParser.Package changingPkg) {
-        ArrayList<PackageParser.Package> res = null;
-        for (PackageParser.Package pkg : mPackages.values()) {
-            if (changingPkg != null
-                    && !hasString(pkg.usesLibraries, changingPkg.libraryNames)
-                    && !hasString(pkg.usesOptionalLibraries, changingPkg.libraryNames)
-                    && !ArrayUtils.contains(pkg.usesStaticLibraries,
-                            changingPkg.staticSharedLibName)) {
-                return null;
-            }
-            if (res == null) {
-                res = new ArrayList<>();
-            }
-            res.add(pkg);
-            try {
-                updateSharedLibrariesLPr(pkg, changingPkg);
-            } catch (PackageManagerException e) {
-                // If a system app update or an app and a required lib missing we
-                // delete the package and for updated system apps keep the data as
-                // it is better for the user to reinstall than to be in an limbo
-                // state. Also libs disappearing under an app should never happen
-                // - just in case.
-                if (!pkg.isSystem() || pkg.isUpdatedSystemApp()) {
-                    final int flags = pkg.isUpdatedSystemApp()
-                            ? PackageManager.DELETE_KEEP_DATA : 0;
-                    deletePackageLIF(pkg.packageName, null, true, sUserManager.getUserIds(),
-                            flags , null, true, null);
-                }
-                Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage());
-            }
+    private ArrayList<PackageParser.Package> updateAllSharedLibrariesLocked(
+            PackageParser.Package updatedPkg,
+            Map<String, PackageParser.Package> availablePackages) {
+        ArrayList<PackageParser.Package> resultList = null;
+        // Set of all descendants of a library; used to eliminate cycles
+        ArraySet<String> descendants = null;
+        // The current list of packages that need updating
+        ArrayList<PackageParser.Package> needsUpdating = null;
+        if (updatedPkg != null) {
+            needsUpdating = new ArrayList<>(1);
+            needsUpdating.add(updatedPkg);
         }
-        return res;
+        do {
+            final PackageParser.Package changingPkg =
+                    (needsUpdating == null) ? null : needsUpdating.remove(0);
+            for (int i = mPackages.size() - 1; i >= 0; --i) {
+                final PackageParser.Package pkg = mPackages.valueAt(i);
+                if (changingPkg != null
+                        && !hasString(pkg.usesLibraries, changingPkg.libraryNames)
+                        && !hasString(pkg.usesOptionalLibraries, changingPkg.libraryNames)
+                        && !ArrayUtils.contains(pkg.usesStaticLibraries,
+                                changingPkg.staticSharedLibName)) {
+                    continue;
+                }
+                if (resultList == null) {
+                    resultList = new ArrayList<>();
+                }
+                resultList.add(pkg);
+                // if we're updating a shared library, all of its descendants must be updated
+                if (changingPkg != null) {
+                    if (descendants == null) {
+                        descendants = new ArraySet<>();
+                    }
+                    if (!descendants.contains(pkg.packageName)) {
+                        descendants.add(pkg.packageName);
+                        needsUpdating.add(pkg);
+                    }
+                }
+                try {
+                    updateSharedLibrariesLocked(pkg, changingPkg, availablePackages);
+                } catch (PackageManagerException e) {
+                    // If a system app update or an app and a required lib missing we
+                    // delete the package and for updated system apps keep the data as
+                    // it is better for the user to reinstall than to be in an limbo
+                    // state. Also libs disappearing under an app should never happen
+                    // - just in case.
+                    if (!pkg.isSystem() || pkg.isUpdatedSystemApp()) {
+                        final int flags = pkg.isUpdatedSystemApp()
+                                ? PackageManager.DELETE_KEEP_DATA : 0;
+                        deletePackageLIF(pkg.packageName, null, true, sUserManager.getUserIds(),
+                                flags , null, true, null);
+                    }
+                    Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage());
+                }
+            }
+        } while (needsUpdating != null && needsUpdating.size() > 0);
+        return resultList;
     }
 
     @GuardedBy({"mInstallLock", "mPackages"})
@@ -11643,19 +11671,19 @@
                 for (SharedLibraryInfo info : reconciledPkg.allowedSharedLibraryInfos) {
                     commitSharedLibraryInfoLocked(info);
                 }
+                final Map<String, PackageParser.Package> combinedPackages =
+                        reconciledPkg.getCombinedPackages();
                 try {
                     // Shared libraries for the package need to be updated.
-                    updateSharedLibrariesLPr(pkg, null);
+                    updateSharedLibrariesLocked(pkg, null, combinedPackages);
                 } catch (PackageManagerException e) {
                     Slog.e(TAG, "updateSharedLibrariesLPr failed: ", e);
                 }
-            }
-
-            if (reconciledPkg.hasDynamicSharedLibraries() && (scanFlags & SCAN_BOOTING) == 0) {
-                // If we are not booting, we need to update any applications
-                // that are clients of our shared library.  If we are booting,
-                // this will all be done once the scan is complete.
-                clientLibPkgs = updateAllSharedLibrariesLPw(pkg);
+                // Update all applications that use this library. Skip when booting
+                // since this will be done after all packages are scaned.
+                if ((scanFlags & SCAN_BOOTING) == 0) {
+                    clientLibPkgs = updateAllSharedLibrariesLocked(pkg, combinedPackages);
+                }
             }
         }
 
@@ -15744,6 +15772,7 @@
      * TODO: move most of the data contained her into a PackageSetting for commit.
      */
     private static class ReconciledPackage {
+        public final ReconcileRequest request;
         public final PackageSetting pkgSetting;
         public final ScanResult scanResult;
         // TODO: Remove install-specific details from the reconcile result
@@ -15757,14 +15786,18 @@
         public ArrayList<SharedLibraryInfo> collectedSharedLibraryInfos;
         public final boolean removeAppKeySetData;
 
-        private ReconciledPackage(InstallArgs installArgs, PackageSetting pkgSetting,
+        private ReconciledPackage(ReconcileRequest request,
+                InstallArgs installArgs,
+                PackageSetting pkgSetting,
                 PackageInstalledInfo installResult,
-                PrepareResult prepareResult, ScanResult scanResult,
+                PrepareResult prepareResult,
+                ScanResult scanResult,
                 DeletePackageAction deletePackageAction,
                 List<SharedLibraryInfo> allowedSharedLibraryInfos,
                 SigningDetails signingDetails,
                 boolean sharedUserSignaturesChanged,
                 boolean removeAppKeySetData) {
+            this.request = request;
             this.installArgs = installArgs;
             this.pkgSetting = pkgSetting;
             this.installResult = installResult;
@@ -15777,9 +15810,20 @@
             this.removeAppKeySetData = removeAppKeySetData;
         }
 
-        public boolean hasDynamicSharedLibraries() {
-            return !ArrayUtils.isEmpty(allowedSharedLibraryInfos)
-                    && allowedSharedLibraryInfos.get(0).getType() != SharedLibraryInfo.TYPE_STATIC;
+        /**
+         * Returns a combined set of packages containing the packages already installed combined
+         * with the package(s) currently being installed. The to-be installed packages take
+         * precedence and may shadow already installed packages.
+         */
+        private Map<String, PackageParser.Package> getCombinedPackages() {
+            final ArrayMap<String, PackageParser.Package> combinedPackages =
+                    new ArrayMap<>(request.allPackages.size() + request.scannedPackages.size());
+
+            combinedPackages.putAll(request.allPackages);
+            for (ScanResult scanResult : request.scannedPackages.values()) {
+                combinedPackages.put(scanResult.pkgSetting.name, scanResult.request.pkg);
+            }
+            return combinedPackages;
         }
     }
 
@@ -15969,7 +16013,7 @@
             }
 
             result.put(installPackageName,
-                    new ReconciledPackage(installArgs, scanResult.pkgSetting,
+                    new ReconciledPackage(request, installArgs, scanResult.pkgSetting,
                             res, request.preparedPackages.get(installPackageName), scanResult,
                             deletePackageAction, allowedSharedLibInfos, signingDetails,
                             sharedUserSignaturesChanged, removeAppKeySetData));
@@ -18404,7 +18448,7 @@
 
         try {
             // update shared libraries for the newly re-installed system package
-            updateSharedLibrariesLPr(pkg, null);
+            updateSharedLibrariesLocked(pkg, null, Collections.unmodifiableMap(mPackages));
         } catch (PackageManagerException e) {
             Slog.e(TAG, "updateAllSharedLibrariesLPw failed: " + e.getMessage());
         }
@@ -20478,7 +20522,7 @@
                         prepareAppDataAfterInstallLIF(pkg);
                         synchronized (mPackages) {
                             try {
-                                updateSharedLibrariesLPr(pkg, null);
+                                updateSharedLibrariesLocked(pkg, null, mPackages);
                             } catch (PackageManagerException e) {
                                 Slog.e(TAG, "updateAllSharedLibrariesLPw failed: ", e);
                             }
@@ -20603,8 +20647,14 @@
                     mPendingBroadcasts.put(userId, packageName, components);
                 }
                 if (!mHandler.hasMessages(SEND_PENDING_BROADCAST)) {
-                    // Schedule a message
-                    mHandler.sendEmptyMessageDelayed(SEND_PENDING_BROADCAST, BROADCAST_DELAY);
+                    // Schedule a message - if it has been a "reasonably long time" since the
+                    // service started, send the broadcast with a delay of one second to avoid
+                    // delayed reactions from the receiver, else keep the default ten second delay
+                    // to avoid extreme thrashing on service startup.
+                    final long broadcastDelay = SystemClock.uptimeMillis() > mServiceStartWithDelay
+                                                ? BROADCAST_DELAY
+                                                : BROADCAST_DELAY_DURING_STARTUP;
+                    mHandler.sendEmptyMessageDelayed(SEND_PENDING_BROADCAST, broadcastDelay);
                 }
             }
         }
@@ -22483,6 +22533,7 @@
         final int targetSdkVersion;
         final PackageFreezer freezer;
         final int[] installedUserIds;
+        final boolean isCurrentLocationExternal;
 
         // reader
         synchronized (mPackages) {
@@ -22529,6 +22580,7 @@
                         "Failed to move already frozen package");
             }
 
+            isCurrentLocationExternal = isExternal(pkg);
             codeFile = new File(pkg.codePath);
             installerPackageName = ps.installerPackageName;
             packageAbiOverride = ps.cpuAbiOverrideString;
@@ -22631,6 +22683,7 @@
                     case PackageInstaller.STATUS_SUCCESS:
                         mMoveCallbacks.notifyStatusChanged(moveId,
                                 PackageManager.MOVE_SUCCEEDED);
+                        logAppMovedStorage(packageName, isCurrentLocationExternal);
                         break;
                     case PackageInstaller.STATUS_FAILURE_STORAGE:
                         mMoveCallbacks.notifyStatusChanged(moveId,
@@ -22689,6 +22742,36 @@
         mHandler.sendMessage(msg);
     }
 
+    /**
+     * Logs that an app has been moved from internal to external storage and vice versa.
+     * @param packageName The package that was moved.
+     */
+    private void logAppMovedStorage(String packageName, boolean isPreviousLocationExternal) {
+        final PackageParser.Package pkg;
+        synchronized (mPackages) {
+            pkg = mPackages.get(packageName);
+        }
+        if (pkg == null) {
+            return;
+        }
+
+        final StorageManager storage = mContext.getSystemService(StorageManager.class);
+        VolumeInfo volume = storage.findVolumeByUuid(pkg.applicationInfo.storageUuid.toString());
+        int packageExternalStorageType = getPackageExternalStorageType(volume, isExternal(pkg));
+
+        if (!isPreviousLocationExternal && isExternal(pkg)) {
+            // Move from internal to external storage.
+            StatsLog.write(StatsLog.APP_MOVED_STORAGE_REPORTED, packageExternalStorageType,
+                    StatsLog.APP_MOVED_STORAGE_REPORTED__MOVE_TYPE__TO_EXTERNAL,
+                    packageName);
+        } else if (isPreviousLocationExternal && !isExternal(pkg)) {
+            // Move from external to internal storage.
+            StatsLog.write(StatsLog.APP_MOVED_STORAGE_REPORTED, packageExternalStorageType,
+                    StatsLog.APP_MOVED_STORAGE_REPORTED__MOVE_TYPE__TO_INTERNAL,
+                    packageName);
+        }
+    }
+
     @Override
     public int movePrimaryStorage(String volumeUuid) throws RemoteException {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MOVE_PACKAGE, null);
@@ -23283,6 +23366,23 @@
             }
             return results;
         }
+
+        @Override
+        public int getLocationFlags(String packageName) throws RemoteException {
+            int callingUser = UserHandle.getUserId(Binder.getCallingUid());
+            ApplicationInfo appInfo = getApplicationInfo(packageName,
+                    /*flags*/ 0,
+                    /*userId*/ callingUser);
+            if (appInfo == null) {
+                throw new RemoteException(
+                        "Couldn't get ApplicationInfo for package " + packageName);
+            }
+            return ((appInfo.isSystemApp() ? IPackageManagerNative.LOCATION_SYSTEM : 0)
+                    | (appInfo.isVendor() ? IPackageManagerNative.LOCATION_VENDOR : 0)
+                    | (appInfo.isProduct() ? IPackageManagerNative.LOCATION_PRODUCT : 0)
+                    | (appInfo.isProductServices()
+                            ? IPackageManagerNative.LOCATION_PRODUCT_SERVICES : 0));
+        }
     }
 
     private class PackageManagerInternalImpl extends PackageManagerInternal {
diff --git a/services/core/java/com/android/server/pm/StagingManager.java b/services/core/java/com/android/server/pm/StagingManager.java
index 39c731c..190610c 100644
--- a/services/core/java/com/android/server/pm/StagingManager.java
+++ b/services/core/java/com/android/server/pm/StagingManager.java
@@ -44,11 +44,13 @@
 import android.os.PowerManager;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.storage.IStorageManager;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.util.apk.ApkSignatureVerifier;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.content.PackageHelper;
 import com.android.internal.os.BackgroundThread;
 
 import java.io.File;
@@ -253,6 +255,21 @@
             }
         }
 
+        // Make sure we start a filesystem checkpoint on the next boot.
+        try {
+            IStorageManager storageManager = PackageHelper.getStorageManager();
+            if (storageManager.supportsCheckpoint()) {
+                storageManager.startCheckpoint(1 /* numRetries */);
+            }
+        } catch (RemoteException e) {
+            // While StorageManager lives in the same process, the native implementation
+            // it calls through lives in 'vold'; so, this call can fail if 'vold' isn't
+            // reachable.
+            // Since we can live without filesystem checkpointing, just warn in this case
+            // and continue.
+            Slog.w(TAG, "Could not start filesystem checkpoint.");
+        }
+
         session.setStagedSessionReady();
         if (sessionContainsApex(session)
                 && !mApexManager.markStagedSessionReady(session.sessionId)) {
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 316a9c0..204f186 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -3372,15 +3372,15 @@
     @Override
     public int getUserSerialNumber(int userHandle) {
         synchronized (mUsersLock) {
-            if (!exists(userHandle)) return -1;
-            return getUserInfoLU(userHandle).serialNumber;
+            final UserInfo userInfo = getUserInfoLU(userHandle);
+            return userInfo != null ? userInfo.serialNumber : -1;
         }
     }
 
     @Override
     public boolean isUserNameSet(int userHandle) {
         synchronized (mUsersLock) {
-            UserInfo userInfo = getUserInfoLU(userHandle);
+            final UserInfo userInfo = getUserInfoLU(userHandle);
             return userInfo != null && userInfo.name != null;
         }
     }
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 7c87462..d4d752f 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -206,7 +206,6 @@
 import com.android.internal.policy.PhoneWindow;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.util.ArrayUtils;
-import com.android.internal.util.ScreenshotHelper;
 import com.android.server.ExtconStateObserver;
 import com.android.server.ExtconUEventObserver;
 import com.android.server.GestureLauncherService;
@@ -377,7 +376,6 @@
     BurnInProtectionHelper mBurnInProtectionHelper;
     private DisplayFoldController mDisplayFoldController;
     AppOpsManager mAppOpsManager;
-    private ScreenshotHelper mScreenshotHelper;
     private boolean mHasFeatureWatch;
     private boolean mHasFeatureLeanback;
     private boolean mHasFeatureHdmiCec;
@@ -1923,7 +1921,6 @@
                         mWindowManagerFuncs.onKeyguardShowingAndNotOccludedChanged();
                     }
                 });
-        mScreenshotHelper = new ScreenshotHelper(mContext);
     }
 
     /**
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index 28a853f..15148f3 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -44,6 +44,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.IntentSender;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PermissionInfo;
@@ -149,6 +150,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.UUID;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.TimeoutException;
 
@@ -2010,6 +2012,40 @@
         }
     }
 
+    private void pullAppsOnExternalStorageInfo(int tagId, long elapsedNanos, long wallClockNanos,
+            List<StatsLogEventWrapper> pulledData) {
+        PackageManager pm = mContext.getPackageManager();
+        StorageManager storage = mContext.getSystemService(StorageManager.class);
+        List<ApplicationInfo> apps = pm.getInstalledApplications(/* flags = */ 0);
+        for (ApplicationInfo appInfo : apps) {
+            UUID storageUuid = appInfo.storageUuid;
+            if (storageUuid != null) {
+                VolumeInfo volumeInfo = storage.findVolumeByUuid(appInfo.storageUuid.toString());
+                if (volumeInfo != null) {
+                    DiskInfo diskInfo = volumeInfo.getDisk();
+                    if (diskInfo != null) {
+                        int externalStorageType = -1;
+                        if (diskInfo.isSd()) {
+                            externalStorageType = StorageEnums.SD_CARD;
+                        } else if (diskInfo.isUsb()) {
+                            externalStorageType = StorageEnums.USB;
+                        } else if (appInfo.isExternal()) {
+                            externalStorageType = StorageEnums.OTHER;
+                        }
+                        // App is installed on external storage.
+                        if (externalStorageType != -1) {
+                            StatsLogEventWrapper e =
+                                    new StatsLogEventWrapper(tagId, elapsedNanos, wallClockNanos);
+                            e.writeInt(externalStorageType);
+                            e.writeString(appInfo.packageName);
+                            pulledData.add(e);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
     /**
      * Pulls various data.
      */
@@ -2210,6 +2246,10 @@
                 pullExternalStorageInfo(tagId, elapsedNanos, wallClockNanos, ret);
                 break;
             }
+            case StatsLog.APPS_ON_EXTERNAL_STORAGE_INFO: {
+                pullAppsOnExternalStorageInfo(tagId, elapsedNanos, wallClockNanos, ret);
+                break;
+            }
             default:
                 Slog.w(TAG, "No such tagId data as " + tagId);
                 return null;
diff --git a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
index a5d291f..5f00148 100644
--- a/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
+++ b/services/core/java/com/android/server/textclassifier/TextClassificationManagerService.java
@@ -425,9 +425,12 @@
         if (packageName == null) return;
 
         try {
-            final int uid = context.getPackageManager()
+            final int packageUid = context.getPackageManager()
                     .getPackageUidAsUser(packageName, UserHandle.getCallingUserId());
-            Preconditions.checkArgument(Binder.getCallingUid() == uid);
+            final int callingUid = Binder.getCallingUid();
+            Preconditions.checkArgument(callingUid == packageUid
+                    // Trust the system process:
+                    || callingUid == android.os.Process.SYSTEM_UID);
         } catch (Exception e) {
             throw new RemoteException(
                     String.format("Invalid package: name=%s, error=%s", packageName, e));
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 5502bb9..0c9f815 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -2669,6 +2669,11 @@
                 }
                 wallpaper.connection.mReply = null;
             }
+            try {
+                wallpaper.connection.mService.detach();
+            } catch (RemoteException e) {
+                Slog.w(TAG, "Failed detaching wallpaper service ", e);
+            }
             mContext.unbindService(wallpaper.connection);
             wallpaper.connection.forEachDisplayConnector(
                     WallpaperConnection.DisplayConnector::disconnectLocked);
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index 2d89bc7..d916e39 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -85,6 +85,7 @@
 
 import android.app.WaitResult;
 import android.app.WindowConfiguration.WindowingMode;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
@@ -876,6 +877,11 @@
         builder.addTaggedData(FIELD_COMING_FROM_PENDING_INTENT, comingFromPendingIntent ? 1 : 0);
         if (intent != null) {
             builder.addTaggedData(FIELD_INTENT_ACTION, intent.getAction());
+            ComponentName component = intent.getComponent();
+            if (component != null) {
+                builder.addTaggedData(FIELD_TARGET_SHORT_COMPONENT_NAME,
+                        component.flattenToShortString());
+            }
         }
         if (callerApp != null) {
             builder.addTaggedData(FIELD_PROCESS_RECORD_PROCESS_NAME, callerApp.mName);
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index 4c9b80b..6bc9fc8 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -3059,7 +3059,11 @@
             // activity in home stack.
             // See {@link #mInResumeTopActivity}.
             mService.mH.post(
-                    () -> mRootActivityContainer.resumeHomeActivity(prev, reason, mDisplayId));
+                    () -> {
+                        synchronized (mService.mGlobalLock) {
+                            mRootActivityContainer.resumeHomeActivity(prev, reason, mDisplayId);
+                        }
+                    });
             return true;
         } else {
             return mRootActivityContainer.resumeHomeActivity(prev, reason, mDisplayId);
@@ -4111,9 +4115,16 @@
         if (DEBUG_STATES) Slog.v(TAG_STATES, "Moving to FINISHING: " + r);
 
         r.setState(FINISHING, "finishCurrentActivityLocked");
+
+        // Don't destroy activity immediately if the display contains home stack, although there is
+        // no next activity at the moment but another home activity should be started later. Keep
+        // this activity alive until next home activity is resumed then user won't see a temporary
+        // black screen.
+        final boolean noRunningStack = next == null && display.topRunningActivity() == null
+                && display.getHomeStack() == null;
+        final boolean noFocusedStack = r.getActivityStack() != display.getFocusedStack();
         final boolean finishingInNonFocusedStackOrNoRunning = mode == FINISH_AFTER_VISIBLE
-                && prevState == PAUSED && (r.getActivityStack() != display.getFocusedStack()
-                        || (next == null && display.topRunningActivity() == null));
+                && prevState == PAUSED && (noFocusedStack || noRunningStack);
 
         if (mode == FINISH_IMMEDIATELY
                 || (prevState == PAUSED
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 3acd4e7..20586db 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -114,6 +114,7 @@
 import android.os.UserManager;
 import android.service.voice.IVoiceInteractionSession;
 import android.text.TextUtils;
+import android.util.ArraySet;
 import android.util.EventLog;
 import android.util.Pools.SynchronizedPool;
 import android.util.Slog;
@@ -997,6 +998,14 @@
             if (callerApp.areBackgroundActivityStartsAllowed()) {
                 return false;
             }
+            // don't abort if the caller has an activity in any foreground task
+            if (callerApp.hasActivityInVisibleTask()) {
+                return false;
+            }
+            // don't abort if the caller is bound by a UID that's currently foreground
+            if (isBoundByForegroundUid(callerApp)) {
+                return false;
+            }
         }
         // don't abort if the callingUid has START_ACTIVITIES_FROM_BACKGROUND permission
         if (mService.checkPermission(START_ACTIVITIES_FROM_BACKGROUND, callingPid, callingUid)
@@ -1011,6 +1020,11 @@
         if (mService.isDeviceOwner(callingPackage)) {
             return false;
         }
+        // don't abort if the callingPackage has companion device
+        final int callingUserId = UserHandle.getUserId(callingUid);
+        if (mService.isAssociatedCompanionApp(callingUserId, callingPackage)) {
+            return false;
+        }
         // don't abort if the callingPackage is temporarily whitelisted
         if (mService.isPackageNameWhitelistedForBgActivityStarts(callingPackage)) {
             Slog.w(TAG, "Background activity start for " + callingPackage
@@ -1041,6 +1055,18 @@
         return true;
     }
 
+    private boolean isBoundByForegroundUid(WindowProcessController callerApp) {
+        final ArraySet<Integer> boundClientUids = callerApp.getBoundClientUids();
+        for (int i = boundClientUids.size() - 1; i >= 0; --i) {
+            final int uid = boundClientUids.valueAt(i);
+            if (mService.mWindowManager.mRoot.isAnyNonToastWindowVisibleForUid(uid)
+                    || mService.getUidState(uid) == ActivityManager.PROCESS_STATE_TOP) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     /**
      * Creates a launch intent for the given auxiliary resolution data.
      */
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
index fc7646f..b2e5b6a 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java
@@ -510,4 +510,7 @@
      * Called by DevicePolicyManagerService to set the package name of the device owner.
      */
     public abstract void setDeviceOwnerPackageName(String deviceOwnerPkg);
+
+    /** Set all associated companion app that belongs to an userId. */
+    public abstract void setCompanionAppPackages(int userId, Set<String> companionAppPackages);
 }
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 7ea7cf1..9a8824f 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -191,6 +191,7 @@
 import android.os.PersistableBundle;
 import android.os.PowerManager;
 import android.os.PowerManagerInternal;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.StrictMode;
@@ -243,6 +244,7 @@
 import com.android.internal.util.Preconditions;
 import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.server.AttributeCache;
+import com.android.server.DeviceIdleController;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
 import com.android.server.SystemServiceManager;
@@ -425,6 +427,9 @@
     private static final long START_AS_CALLER_TOKEN_EXPIRED_TIMEOUT =
             START_AS_CALLER_TOKEN_TIMEOUT_IMPL + 20 * MINUTE_IN_MILLIS;
 
+    // How long to whitelist the Services for when requested.
+    private static final int SERVICE_LAUNCH_IDLE_WHITELIST_DURATION_MS = 5 * 1000;
+
     // Activity tokens of system activities that are delegating their call to
     // #startActivityByCaller, keyed by the permissionToken granted to the delegate.
     final HashMap<IBinder, IBinder> mStartActivitySources = new HashMap<>();
@@ -438,6 +443,9 @@
     // VoiceInteractionManagerService
     ComponentName mActiveVoiceInteractionServiceComponent;
 
+    // A map userId and all its companion app packages
+    private final Map<Integer, Set<String>> mCompanionAppPackageMap = new ArrayMap<>();
+
     VrController mVrController;
     KeyguardController mKeyguardController;
     private final ClientLifecycleManager mLifecycleManager;
@@ -2967,7 +2975,8 @@
             if (TextUtils.equals(pae.intent.getAction(),
                     android.service.voice.VoiceInteractionService.SERVICE_INTERFACE)) {
                 pae.intent.putExtras(pae.extras);
-                mContext.startServiceAsUser(pae.intent, new UserHandle(pae.userHandle));
+
+                startVoiceInteractionServiceAsUser(pae.intent, pae.userHandle, "AssistContext");
             } else {
                 pae.intent.replaceExtras(pae.extras);
                 pae.intent.setFlags(FLAG_ACTIVITY_NEW_TASK
@@ -2986,6 +2995,34 @@
         }
     }
 
+    /**
+     * Workaround for historical API which starts the Assist service with a non-foreground
+     * {@code startService()} call.
+     */
+    private void startVoiceInteractionServiceAsUser(
+            Intent intent, int userHandle, String reason) {
+        // Resolve the intent to find out which package we need to whitelist.
+        ResolveInfo resolveInfo =
+                mContext.getPackageManager().resolveServiceAsUser(intent, 0, userHandle);
+        if (resolveInfo == null || resolveInfo.serviceInfo == null) {
+            Slog.e(TAG, "VoiceInteractionService intent does not resolve. Not starting.");
+            return;
+        }
+        intent.setPackage(resolveInfo.serviceInfo.packageName);
+
+        // Whitelist background services temporarily.
+        LocalServices.getService(DeviceIdleController.LocalService.class)
+                .addPowerSaveTempWhitelistApp(Process.myUid(), intent.getPackage(),
+                        SERVICE_LAUNCH_IDLE_WHITELIST_DURATION_MS, userHandle, false, reason);
+
+        // Finally, try to start the service.
+        try {
+            mContext.startServiceAsUser(intent, UserHandle.of(userHandle));
+        } catch (RuntimeException e) {
+            Slog.e(TAG, "VoiceInteractionService failed to start.", e);
+        }
+    }
+
     @Override
     public int addAppTask(IBinder activityToken, Intent intent,
             ActivityManager.TaskDescription description, Bitmap thumbnail) throws RemoteException {
@@ -5875,6 +5912,14 @@
         }
     }
 
+    boolean isAssociatedCompanionApp(int userId, String packageName) {
+        final Set<String> allPackages = mCompanionAppPackageMap.get(userId);
+        if (allPackages == null) {
+            return false;
+        }
+        return allPackages.contains(packageName);
+    }
+
     final class H extends Handler {
         static final int REPORT_TIME_TRACKER_MSG = 1;
 
@@ -7248,5 +7293,17 @@
                 ActivityTaskManagerService.this.setDeviceOwnerPackageName(deviceOwnerPkg);
             }
         }
+
+        @Override
+        public void setCompanionAppPackages(int userId, Set<String> companionAppPackages) {
+            // Deep copy all content to make sure we do not rely on the source
+            final Set<String> result = new HashSet<>();
+            for (String pkg : companionAppPackages) {
+                result.add(pkg);
+            }
+            synchronized (mGlobalLock) {
+                mCompanionAppPackageMap.put(userId, result);
+            }
+        }
     }
 }
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 1e1c482..c1b9bba 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -666,7 +666,7 @@
             }
         }
 
-        if (isSelfAnimating()) {
+        if (isReallyAnimating()) {
             delayed = true;
         } else {
 
@@ -3132,8 +3132,17 @@
         }
     }
 
+    /** Gets the inner bounds of letterbox. The bounds will be empty if there is no letterbox. */
+    void getLetterboxInnerBounds(Rect outBounds) {
+        if (mLetterbox != null) {
+            outBounds.set(mLetterbox.getInnerFrame());
+        } else {
+            outBounds.setEmpty();
+        }
+    }
+
     /**
-     * @eturn true if there is a letterbox and any part of that letterbox overlaps with
+     * @return {@code true} if there is a letterbox and any part of that letterbox overlaps with
      * the given {@code rect}.
      */
     boolean isLetterboxOverlappingWith(Rect rect) {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index bec72f5..0c34e25 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1525,7 +1525,7 @@
         final int shortSizeDp = shortSize * DisplayMetrics.DENSITY_DEFAULT / mBaseDisplayDensity;
         final int longSizeDp = longSize * DisplayMetrics.DENSITY_DEFAULT / mBaseDisplayDensity;
 
-        mDisplayPolicy.configure(width, height, shortSizeDp);
+        mDisplayPolicy.updateConfigurationAndScreenSizeDependentBehaviors();
         mDisplayRotation.configure(width, height, shortSizeDp, longSizeDp);
 
         mDisplayFrames.onDisplayInfoUpdated(mDisplayInfo,
@@ -1734,7 +1734,7 @@
             mWmService.mH.sendEmptyMessage(REPORT_HARD_KEYBOARD_STATUS_CHANGE);
         }
 
-        mDisplayPolicy.updateConfigurationDependentBehaviors();
+        mDisplayPolicy.updateConfigurationAndScreenSizeDependentBehaviors();
 
         // Let the policy update hidden states.
         config.keyboardHidden = Configuration.KEYBOARDHIDDEN_NO;
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 6605f3c6..95d8944 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -415,7 +415,6 @@
         mDeskDockEnablesAccelerometer = r.getBoolean(R.bool.config_deskDockEnablesAccelerometer);
         mTranslucentDecorEnabled = r.getBoolean(R.bool.config_enableTranslucentDecor);
         mForceShowSystemBarsFromExternal = r.getBoolean(R.bool.config_forceShowSystemBars);
-        updateConfigurationDependentBehaviors();
 
         mAccessibilityManager = (AccessibilityManager) mContext.getSystemService(
                 Context.ACCESSIBILITY_SERVICE);
@@ -567,15 +566,6 @@
         return mDisplayContent.getDisplayId();
     }
 
-    void configure(int width, int height, int shortSizeDp) {
-        // Allow the navigation bar to move on non-square small devices (phones).
-        mNavigationBarCanMove = width != height && shortSizeDp < 600;
-    }
-
-    void updateConfigurationDependentBehaviors() {
-        mNavBarOpacityMode = mContext.getResources().getInteger(R.integer.config_navBarOpacityMode);
-    }
-
     public void setHdmiPlugged(boolean plugged) {
         setHdmiPlugged(plugged, false /* force */);
     }
@@ -2602,9 +2592,21 @@
                     res.getDimensionPixelSize(R.dimen.navigation_bar_width_car_mode);
         }
 
+        mNavBarOpacityMode = res.getInteger(R.integer.config_navBarOpacityMode);
+
         // EXPERIMENT TODO(b/113952590): Remove once experiment in bug is completed
         mExperiments.onConfigurationChanged(uiContext);
         // EXPERIMENT END
+
+        updateConfigurationAndScreenSizeDependentBehaviors();
+    }
+
+    void updateConfigurationAndScreenSizeDependentBehaviors() {
+        final Context uiContext = getSystemUiContext();
+        final Resources res = uiContext.getResources();
+        mNavigationBarCanMove =
+                mDisplayContent.mBaseDisplayWidth != mDisplayContent.mBaseDisplayHeight
+                        && res.getBoolean(R.bool.config_navBarCanMove);
     }
 
     @VisibleForTesting
@@ -2960,6 +2962,8 @@
         mLastDockedStackSysUiFlags = dockedVisibility;
         mLastFocusNeedsMenu = needsMenu;
         mFocusedApp = win.getAppToken();
+        mLastNonDockedStackBounds.set(mNonDockedStackBounds);
+        mLastDockedStackBounds.set(mDockedStackBounds);
         final Rect fullscreenStackBounds = new Rect(mNonDockedStackBounds);
         final Rect dockedStackBounds = new Rect(mDockedStackBounds);
         mHandler.post(() -> {
@@ -3411,6 +3415,10 @@
         }
         if (mNavigationBar != null) {
             pw.print(prefix); pw.print("mNavigationBar="); pw.println(mNavigationBar);
+            pw.print(prefix); pw.print("mNavBarOpacityMode="); pw.println(mNavBarOpacityMode);
+            pw.print(prefix); pw.print("mNavigationBarCanMove="); pw.println(mNavigationBarCanMove);
+            pw.print(prefix); pw.print("mNavigationBarPosition=");
+            pw.println(mNavigationBarPosition);
         }
         if (mFocusedWindow != null) {
             pw.print(prefix); pw.print("mFocusedWindow="); pw.println(mFocusedWindow);
diff --git a/services/core/java/com/android/server/wm/DisplayWindowSettings.java b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
index db96847..a46fa13 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowSettings.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
@@ -26,6 +26,8 @@
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 
+import android.annotation.IntDef;
+import android.annotation.Nullable;
 import android.app.WindowConfiguration;
 import android.os.Environment;
 import android.provider.Settings;
@@ -33,6 +35,7 @@
 import android.util.Slog;
 import android.util.Xml;
 import android.view.Display;
+import android.view.DisplayAddress;
 import android.view.DisplayInfo;
 import android.view.Surface;
 
@@ -47,10 +50,11 @@
 import org.xmlpull.v1.XmlSerializer;
 
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
 import java.nio.charset.StandardCharsets;
 import java.util.HashMap;
 
@@ -60,9 +64,33 @@
 class DisplayWindowSettings {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "DisplayWindowSettings" : TAG_WM;
 
+    private static final int IDENTIFIER_UNIQUE_ID = 0;
+    private static final int IDENTIFIER_PORT = 1;
+    @IntDef(prefix = { "IDENTIFIER_" }, value = {
+            IDENTIFIER_UNIQUE_ID,
+            IDENTIFIER_PORT,
+    })
+    @interface DisplayIdentifierType {}
+
     private final WindowManagerService mService;
-    private final AtomicFile mFile;
-    private final HashMap<String, Entry> mEntries = new HashMap<String, Entry>();
+    private final HashMap<String, Entry> mEntries = new HashMap<>();
+    private final SettingPersister mStorage;
+
+    /**
+     * The preferred type of a display identifier to use when storing and retrieving entries.
+     * {@link #getIdentifier(DisplayInfo)} must be used to get current preferred identifier for each
+     * display. It will fall back to using {@link #IDENTIFIER_UNIQUE_ID} if the currently selected
+     * one is not applicable to a particular display.
+     */
+    @DisplayIdentifierType
+    private int mIdentifier = IDENTIFIER_UNIQUE_ID;
+
+    /** Interface for persisting the display window settings. */
+    interface SettingPersister {
+        InputStream openRead() throws IOException;
+        OutputStream startWrite() throws IOException;
+        void finishWrite(OutputStream os, boolean success);
+    }
 
     private static class Entry {
         private final String mName;
@@ -88,6 +116,26 @@
             mName = name;
         }
 
+        private Entry(String name, Entry copyFrom) {
+            this(name);
+            mOverscanLeft = copyFrom.mOverscanLeft;
+            mOverscanTop = copyFrom.mOverscanTop;
+            mOverscanRight = copyFrom.mOverscanRight;
+            mOverscanBottom = copyFrom.mOverscanBottom;
+            mWindowingMode = copyFrom.mWindowingMode;
+            mUserRotationMode = copyFrom.mUserRotationMode;
+            mUserRotation = copyFrom.mUserRotation;
+            mForcedWidth = copyFrom.mForcedWidth;
+            mForcedHeight = copyFrom.mForcedHeight;
+            mForcedDensity = copyFrom.mForcedDensity;
+            mForcedScalingMode = copyFrom.mForcedScalingMode;
+            mRemoveContentMode = copyFrom.mRemoveContentMode;
+            mShouldShowWithInsecureKeyguard = copyFrom.mShouldShowWithInsecureKeyguard;
+            mShouldShowSystemDecors = copyFrom.mShouldShowSystemDecors;
+            mShouldShowIme = copyFrom.mShouldShowIme;
+            mFixedToUserRotation = copyFrom.mFixedToUserRotation;
+        }
+
         /** @return {@code true} if all values are default. */
         private boolean isEmpty() {
             return mOverscanLeft == 0 && mOverscanTop == 0 && mOverscanRight == 0
@@ -106,29 +154,46 @@
     }
 
     DisplayWindowSettings(WindowManagerService service) {
-        this(service, new File(Environment.getDataDirectory(), "system"));
+        this(service, new AtomicFileStorage());
     }
 
     @VisibleForTesting
-    DisplayWindowSettings(WindowManagerService service, File folder) {
+    DisplayWindowSettings(WindowManagerService service, SettingPersister storageImpl) {
         mService = service;
-        mFile = new AtomicFile(new File(folder, "display_settings.xml"), "wm-displays");
+        mStorage = storageImpl;
         readSettings();
     }
 
-    private Entry getEntry(DisplayInfo displayInfo) {
-        // Try to get the entry with the unique if possible.
-        // Else, fall back on the display name.
+    private @Nullable Entry getEntry(DisplayInfo displayInfo) {
+        final String identifier = getIdentifier(displayInfo);
         Entry entry;
-        if (displayInfo.uniqueId == null || (entry = mEntries.get(displayInfo.uniqueId)) == null) {
-            entry = mEntries.get(displayInfo.name);
+        // Try to get corresponding entry using preferred identifier for the current config.
+        if ((entry = mEntries.get(identifier)) != null) {
+            return entry;
         }
-        return entry;
+        // Else, fall back to the display name.
+        if ((entry = mEntries.get(displayInfo.name)) != null) {
+            // Found an entry stored with old identifier - upgrade to the new type now.
+            return updateIdentifierForEntry(entry, displayInfo);
+        }
+        return null;
     }
 
     private Entry getOrCreateEntry(DisplayInfo displayInfo) {
         final Entry entry = getEntry(displayInfo);
-        return entry != null ? entry : new Entry(displayInfo.uniqueId);
+        return entry != null ? entry : new Entry(getIdentifier(displayInfo));
+    }
+
+    /**
+     * Upgrades the identifier of a legacy entry. Does it by copying the data from the old record
+     * and clearing the old key in memory. The entry will be written to storage next time when a
+     * setting changes.
+     */
+    private Entry updateIdentifierForEntry(Entry entry, DisplayInfo displayInfo) {
+        final Entry newEntry = new Entry(getIdentifier(displayInfo), entry);
+        removeEntry(displayInfo);
+        mEntries.put(newEntry.mName, newEntry);
+        return newEntry;
     }
 
     void setOverscanLocked(DisplayInfo displayInfo, int left, int top, int right, int bottom) {
@@ -371,12 +436,11 @@
     }
 
     private void readSettings() {
-        FileInputStream stream;
+        InputStream stream;
         try {
-            stream = mFile.openRead();
-        } catch (FileNotFoundException e) {
-            Slog.i(TAG, "No existing display settings " + mFile.getBaseFile()
-                    + "; starting empty");
+            stream = mStorage.openRead();
+        } catch (IOException e) {
+            Slog.i(TAG, "No existing display settings, starting empty");
             return;
         }
         boolean success = false;
@@ -403,6 +467,8 @@
                 String tagName = parser.getName();
                 if (tagName.equals("display")) {
                     readDisplay(parser);
+                } else if (tagName.equals("config")) {
+                    readConfig(parser);
                 } else {
                     Slog.w(TAG, "Unknown element under <display-settings>: "
                             + parser.getName());
@@ -491,22 +557,26 @@
         XmlUtils.skipCurrentTag(parser);
     }
 
+    private void readConfig(XmlPullParser parser) throws NumberFormatException,
+            XmlPullParserException, IOException {
+        mIdentifier = getIntAttribute(parser, "identifier");
+        XmlUtils.skipCurrentTag(parser);
+    }
+
     private void writeSettingsIfNeeded(Entry changedEntry, DisplayInfo displayInfo) {
-        if (changedEntry.isEmpty()) {
-            boolean removed = mEntries.remove(displayInfo.uniqueId) != null;
-            // Legacy name might have been in used, so we need to clear it.
-            removed |= mEntries.remove(displayInfo.name) != null;
-            if (!removed) {
-                // The entry didn't exist so nothing is changed and no need to update the file.
-                return;
-            }
-        } else {
-            mEntries.put(displayInfo.uniqueId, changedEntry);
+        if (changedEntry.isEmpty() && !removeEntry(displayInfo)) {
+            // The entry didn't exist so nothing is changed and no need to update the file.
+            return;
         }
 
-        FileOutputStream stream;
+        mEntries.put(getIdentifier(displayInfo), changedEntry);
+        writeSettings();
+    }
+
+    private void writeSettings() {
+        OutputStream stream;
         try {
-            stream = mFile.startWrite();
+            stream = mStorage.startWrite();
         } catch (IOException e) {
             Slog.w(TAG, "Failed to write display settings: " + e);
             return;
@@ -516,8 +586,13 @@
             XmlSerializer out = new FastXmlSerializer();
             out.setOutput(stream, StandardCharsets.UTF_8.name());
             out.startDocument(null, true);
+
             out.startTag(null, "display-settings");
 
+            out.startTag(null, "config");
+            out.attribute(null, "identifier", Integer.toString(mIdentifier));
+            out.endTag(null, "config");
+
             for (Entry entry : mEntries.values()) {
                 out.startTag(null, "display");
                 out.attribute(null, "name", entry.mName);
@@ -578,10 +653,66 @@
 
             out.endTag(null, "display-settings");
             out.endDocument();
-            mFile.finishWrite(stream);
+            mStorage.finishWrite(stream, true /* success */);
         } catch (IOException e) {
-            Slog.w(TAG, "Failed to write display settings, restoring backup.", e);
-            mFile.failWrite(stream);
+            Slog.w(TAG, "Failed to write display window settings.", e);
+            mStorage.finishWrite(stream, false /* success */);
+        }
+    }
+
+    /**
+     * Removes an entry from {@link #mEntries} cache. Looks up by new and previously used
+     * identifiers.
+     */
+    private boolean removeEntry(DisplayInfo displayInfo) {
+        // Remove entry based on primary identifier.
+        boolean removed = mEntries.remove(getIdentifier(displayInfo)) != null;
+        // Ensure that legacy entries are cleared as well.
+        removed |= mEntries.remove(displayInfo.uniqueId) != null;
+        removed |= mEntries.remove(displayInfo.name) != null;
+        return removed;
+    }
+
+    /** Gets the identifier of choice for the current config. */
+    private String getIdentifier(DisplayInfo displayInfo) {
+        if (mIdentifier == IDENTIFIER_PORT && displayInfo.address != null) {
+            // Config suggests using port as identifier for physical displays.
+            if (displayInfo.address instanceof DisplayAddress.Physical) {
+                return "port:" + ((DisplayAddress.Physical) displayInfo.address).getPort();
+            }
+        }
+        return displayInfo.uniqueId;
+    }
+
+    private static class AtomicFileStorage implements SettingPersister {
+        private final AtomicFile mAtomicFile;
+
+        AtomicFileStorage() {
+            final File folder = new File(Environment.getDataDirectory(), "system");
+            mAtomicFile = new AtomicFile(new File(folder, "display_settings.xml"), "wm-displays");
+        }
+
+        @Override
+        public InputStream openRead() throws FileNotFoundException {
+            return mAtomicFile.openRead();
+        }
+
+        @Override
+        public OutputStream startWrite() throws IOException {
+            return mAtomicFile.startWrite();
+        }
+
+        @Override
+        public void finishWrite(OutputStream os, boolean success) {
+            if (!(os instanceof FileOutputStream)) {
+                throw new IllegalArgumentException("Unexpected OutputStream as argument: " + os);
+            }
+            FileOutputStream fos = (FileOutputStream) os;
+            if (success) {
+                mAtomicFile.finishWrite(fos);
+            } else {
+                mAtomicFile.failWrite(fos);
+            }
         }
     }
 }
diff --git a/services/core/java/com/android/server/wm/Letterbox.java b/services/core/java/com/android/server/wm/Letterbox.java
index 3110fb9..c3ea72f 100644
--- a/services/core/java/com/android/server/wm/Letterbox.java
+++ b/services/core/java/com/android/server/wm/Letterbox.java
@@ -92,6 +92,11 @@
                 mBottom.getHeight());
     }
 
+    /** @return The frame that used to place the content. */
+    Rect getInnerFrame() {
+        return mInner;
+    }
+
     /**
      * Returns true if any part of the letterbox overlaps with the given {@code rect}.
      */
@@ -162,6 +167,7 @@
         final InputWindowHandle mWindowHandle;
         final InputEventReceiver mInputEventReceiver;
         final WindowManagerService mWmService;
+        final Binder mToken = new Binder();
 
         InputInterceptor(String namePrefix, WindowState win) {
             mWmService = win.mWmService;
@@ -171,13 +177,12 @@
             mClientChannel = channels[1];
             mInputEventReceiver = new SimpleInputReceiver(mClientChannel);
 
-            final Binder token = new Binder();
-            mWmService.mInputManager.registerInputChannel(mServerChannel, token);
+            mWmService.mInputManager.registerInputChannel(mServerChannel, mToken);
 
             mWindowHandle = new InputWindowHandle(null /* inputApplicationHandle */,
                     null /* clientWindow */, win.getDisplayId());
             mWindowHandle.name = name;
-            mWindowHandle.token = token;
+            mWindowHandle.token = mToken;
             mWindowHandle.layoutParamsFlags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
                     | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
                     | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH
@@ -192,6 +197,14 @@
         }
 
         void updateTouchableRegion(Rect frame) {
+            if (frame.isEmpty()) {
+                // Use null token to indicate the surface doesn't need to receive input event (see
+                // the usage of Layer.hasInput in SurfaceFlinger), so InputDispatcher won't keep the
+                // unnecessary records.
+                mWindowHandle.token = null;
+                return;
+            }
+            mWindowHandle.token = mToken;
             mWindowHandle.touchableRegion.set(frame);
             mWindowHandle.touchableRegion.translate(-frame.left, -frame.top);
         }
@@ -289,14 +302,14 @@
                 t.setPosition(mSurface, mSurfaceFrameRelative.left, mSurfaceFrameRelative.top);
                 t.setWindowCrop(mSurface, mSurfaceFrameRelative.width(),
                         mSurfaceFrameRelative.height());
-                if (mInputInterceptor != null) {
-                    mInputInterceptor.updateTouchableRegion(mSurfaceFrameRelative);
-                    t.setInputWindowInfo(mSurface, mInputInterceptor.mWindowHandle);
-                }
                 t.show(mSurface);
             } else if (mSurface != null) {
                 t.hide(mSurface);
             }
+            if (mSurface != null && mInputInterceptor != null) {
+                mInputInterceptor.updateTouchableRegion(mSurfaceFrameRelative);
+                t.setInputWindowInfo(mSurface, mInputInterceptor.mWindowHandle);
+            }
         }
 
         public boolean needsApplySurfaceChanges() {
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index 9b634f9..22b030d 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -426,11 +426,10 @@
     }
 
     @Override
-    public void updateTapExcludeRegion(IWindow window, int regionId, int left, int top, int width,
-            int height) {
+    public void updateTapExcludeRegion(IWindow window, int regionId, Region region) {
         final long identity = Binder.clearCallingIdentity();
         try {
-            mService.updateTapExcludeRegion(window, regionId, left, top, width, height);
+            mService.updateTapExcludeRegion(window, regionId, region);
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java
index 35b8641..67686a5 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimator.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java
@@ -82,6 +82,11 @@
                     return;
                 }
                 final Runnable resetAndInvokeFinish = () -> {
+                    // We need to check again if the animation has been replaced with a new
+                    // animation because the animatable may defer to finish.
+                    if (anim != mAnimation) {
+                        return;
+                    }
                     reset(mAnimatable.getPendingTransaction(), true /* destroyLeash */);
                     if (animationFinishedCallback != null) {
                         animationFinishedCallback.run();
diff --git a/services/core/java/com/android/server/wm/TapExcludeRegionHolder.java b/services/core/java/com/android/server/wm/TapExcludeRegionHolder.java
index 0a4ab67..22f529b 100644
--- a/services/core/java/com/android/server/wm/TapExcludeRegionHolder.java
+++ b/services/core/java/com/android/server/wm/TapExcludeRegionHolder.java
@@ -21,38 +21,35 @@
 import android.util.SparseArray;
 
 /**
- * A holder that contains a collection of rectangular areas identified by int id. Each individual
- * region can be updated separately.
+ * A holder that contains a collection of regions identified by int id. Each individual region can
+ * be updated separately.
  */
 class TapExcludeRegionHolder {
-    private SparseArray<Rect> mTapExcludeRects = new SparseArray<>();
+    private SparseArray<Region> mTapExcludeRegions = new SparseArray<>();
 
     /** Update the specified region with provided position and size. */
-    void updateRegion(int regionId, int left, int top, int width, int height) {
-        if (width <= 0 || height <= 0) {
-            // A region became empty - remove it.
-            mTapExcludeRects.remove(regionId);
+    void updateRegion(int regionId, Region region) {
+        // Remove the previous one because there is a new one incoming.
+        mTapExcludeRegions.remove(regionId);
+
+        if (region == null || region.isEmpty()) {
+            // The incoming region is invalid. Don't use it.
             return;
         }
 
-        Rect region = mTapExcludeRects.get(regionId);
-        if (region == null) {
-            region = new Rect();
-        }
-        region.set(left, top, left + width, top + height);
-        mTapExcludeRects.put(regionId, region);
+        mTapExcludeRegions.put(regionId, region);
     }
 
     /**
      * Union the provided region with current region formed by this container.
      */
-    void amendRegion(Region region, Rect boundingRegion) {
-        for (int i = mTapExcludeRects.size() - 1; i>= 0 ; --i) {
-            final Rect rect = mTapExcludeRects.valueAt(i);
-            if (boundingRegion != null) {
-                rect.intersect(boundingRegion);
+    void amendRegion(Region region, Rect bounds) {
+        for (int i = mTapExcludeRegions.size() - 1; i >= 0; --i) {
+            final Region r = mTapExcludeRegions.valueAt(i);
+            if (bounds != null) {
+                r.op(bounds, Region.Op.INTERSECT);
             }
-            region.union(rect);
+            region.op(r, Region.Op.UNION);
         }
     }
 }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 4aa844f..9e421c1 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -6696,24 +6696,23 @@
     }
 
     /**
-     * Update a tap exclude region with a rectangular area in the window identified by the provided
-     * id. Touches down on this region will not:
+     * Update a tap exclude region in the window identified by the provided id. Touches down on this
+     * region will not:
      * <ol>
      * <li>Switch focus to this window.</li>
      * <li>Move the display of this window to top.</li>
      * <li>Send the touch events to this window.</li>
      * </ol>
-     * Passing an empty rect will remove the area from the exclude region of this window.
+     * Passing an invalid region will remove the area from the exclude region of this window.
      */
-    void updateTapExcludeRegion(IWindow client, int regionId, int left, int top, int width,
-            int height) {
+    void updateTapExcludeRegion(IWindow client, int regionId, Region region) {
         synchronized (mGlobalLock) {
             final WindowState callingWin = windowForClientLocked(null, client, false);
             if (callingWin == null) {
                 Slog.w(TAG_WM, "Bad requesting window " + client);
                 return;
             }
-            callingWin.updateTapExcludeRegion(regionId, left, top, width, height);
+            callingWin.updateTapExcludeRegion(regionId, region);
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index dceed28..33561d3a 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -149,6 +149,8 @@
     // Set to true if this process is currently temporarily whitelisted to start activities even if
     // it's not in the foreground
     private volatile boolean mAllowBackgroundActivityStarts;
+    // Set of UIDs of clients currently bound to this process
+    private volatile ArraySet<Integer> mBoundClientUids = new ArraySet<Integer>();
 
     // Thread currently set for VR scheduling
     int mVrThreadTid;
@@ -297,6 +299,11 @@
         return mPendingUiClean;
     }
 
+    /** @return {@code true} if the process registered to a display as a config listener. */
+    boolean registeredForDisplayConfigChanges() {
+        return mDisplayId != INVALID_DISPLAY;
+    }
+
     void postPendingUiCleanMsg(boolean pendingUiClean) {
         if (mListener == null) return;
         // Posting on handler so WM lock isn't held when we call into AM.
@@ -368,6 +375,14 @@
         return mAllowBackgroundActivityStarts;
     }
 
+    public void setBoundClientUids(ArraySet<Integer> boundClientUids) {
+        mBoundClientUids = boundClientUids;
+    }
+
+    public ArraySet<Integer> getBoundClientUids() {
+        return mBoundClientUids;
+    }
+
     public void setInstrumenting(boolean instrumenting,
             boolean hasBackgroundActivityStartPrivileges) {
         mInstrumenting = instrumenting;
@@ -471,6 +486,20 @@
         }
     }
 
+    boolean hasActivityInVisibleTask() {
+        for (int i = mActivities.size() - 1; i >= 0; --i) {
+            TaskRecord task = mActivities.get(i).getTaskRecord();
+            if (task == null) {
+                continue;
+            }
+            ActivityRecord topActivity = task.getTopActivity();
+            if (topActivity != null && topActivity.visible) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     /**
      * Update the top resuming activity in process for pre-Q apps, only the top-most visible
      * activities are allowed to be resumed per process.
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 6a21327..486b0da 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -72,6 +72,7 @@
 import static android.view.WindowManagerGlobal.RELAYOUT_RES_FIRST_TIME;
 import static android.view.WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED;
 
+import static com.android.server.am.ActivityManagerService.MY_PID;
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
 import static com.android.server.policy.WindowManagerPolicy.TRANSIT_ENTER;
 import static com.android.server.policy.WindowManagerPolicy.TRANSIT_EXIT;
@@ -2209,16 +2210,22 @@
         if (modal && mAppToken != null) {
             // Limit the outer touch to the activity stack region.
             flags |= FLAG_NOT_TOUCH_MODAL;
-            // If this is a modal window we need to dismiss it if it's not full screen and the
-            // touch happens outside of the frame that displays the content. This means we
-            // need to intercept touches outside of that window. The dim layer user
-            // associated with the window (task or stack) will give us the good bounds, as
-            // they would be used to display the dim layer.
-            final Task task = getTask();
-            if (task != null) {
-                task.getDimBounds(mTmpRect);
-            } else {
-                getStack().getDimBounds(mTmpRect);
+            // If the inner bounds of letterbox is available, then it will be used as the touchable
+            // region so it won't cover the touchable letterbox and the touch events can slip to
+            // activity from letterbox.
+            mAppToken.getLetterboxInnerBounds(mTmpRect);
+            if (mTmpRect.isEmpty()) {
+                // If this is a modal window we need to dismiss it if it's not full screen and the
+                // touch happens outside of the frame that displays the content. This means we need
+                // to intercept touches outside of that window. The dim layer user associated with
+                // the window (task or stack) will give us the good bounds, as they would be used to
+                // display the dim layer.
+                final Task task = getTask();
+                if (task != null) {
+                    task.getDimBounds(mTmpRect);
+                } else {
+                    getStack().getDimBounds(mTmpRect);
+                }
             }
             if (inFreeformWindowingMode()) {
                 // For freeform windows we the touch region to include the whole surface for the
@@ -2343,12 +2350,11 @@
     private Configuration getProcessGlobalConfiguration() {
         // For child windows we want to use the pid for the parent window in case the the child
         // window was added from another process.
-        final int pid = getParentWindow() != null ? getParentWindow().mSession.mPid : mSession.mPid;
+        final WindowState parentWindow = getParentWindow();
+        final int pid = parentWindow != null ? parentWindow.mSession.mPid : mSession.mPid;
         final Configuration processConfig =
                 mWmService.mAtmService.getGlobalConfigurationForPid(pid);
-        mTempConfiguration.setTo(processConfig == null
-                ? mWmService.mRoot.getConfiguration() : processConfig);
-        return mTempConfiguration;
+        return processConfig;
     }
 
     void getMergedConfiguration(MergedConfiguration outConfiguration) {
@@ -2983,11 +2989,29 @@
             return mAppToken.mFrozenMergedConfig.peek();
         }
 
+        // If the process has not registered to any display to listen to the configuration change,
+        // we can simply return the mFullConfiguration as default.
+        if (!registeredForDisplayConfigChanges()) {
+            return super.getConfiguration();
+        }
+
         // We use the process config this window is associated with as the based global config since
-        // the process can override it config, but isn't part of the window hierarchy.
-        final Configuration config = getProcessGlobalConfiguration();
-        config.updateFrom(getMergedOverrideConfiguration());
-        return config;
+        // the process can override its config, but isn't part of the window hierarchy.
+        mTempConfiguration.setTo(getProcessGlobalConfiguration());
+        mTempConfiguration.updateFrom(getMergedOverrideConfiguration());
+        return mTempConfiguration;
+    }
+
+    /** @return {@code true} if the process registered to a display as a config listener. */
+    private boolean registeredForDisplayConfigChanges() {
+        final WindowState parentWindow = getParentWindow();
+        final Session session = parentWindow != null ? parentWindow.mSession : mSession;
+        // System process or invalid process cannot register to display config change.
+        if (session.mPid == MY_PID || session.mPid < 0) return false;
+        WindowProcessController app =
+                mWmService.mAtmService.getProcessController(session.mPid, session.mUid);
+        if (app == null || !app.registeredForDisplayConfigChanges()) return false;
+        return true;
     }
 
     void reportResized() {
@@ -4831,10 +4855,10 @@
     }
 
     /**
-     * Update a tap exclude region with a rectangular area identified by provided id. The requested
-     * area will be clipped to the window bounds.
+     * Update a tap exclude region identified by provided id. The requested area will be clipped to
+     * the window bounds.
      */
-    void updateTapExcludeRegion(int regionId, int left, int top, int width, int height) {
+    void updateTapExcludeRegion(int regionId, Region region) {
         final DisplayContent currentDisplay = getDisplayContent();
         if (currentDisplay == null) {
             throw new IllegalStateException("Trying to update window not attached to any display.");
@@ -4848,7 +4872,7 @@
             currentDisplay.mTapExcludeProvidingWindows.add(this);
         }
 
-        mTapExcludeRegionHolder.updateRegion(regionId, left, top, width, height);
+        mTapExcludeRegionHolder.updateRegion(regionId, region);
         // Trigger touch exclude region update on current display.
         currentDisplay.updateTouchExcludeRegion();
         // Trigger touchable region update for this window.
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index 7df7ef3..0b47b29 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -1700,8 +1700,12 @@
         gnssNavigationMessageIface = gnssNavigationMessage;
     }
 
-    if (gnssHal_V2_0 != nullptr) {
-        // TODO: getExtensionGnssMeasurement_1_1 from gnssHal_V2_0
+    // Allow all causal combinations between IGnss.hal and IGnssMeasurement.hal. That means,
+    // 2.0@IGnss can be paired with {1.0, 1,1, 2.0}@IGnssMeasurement
+    // 1.1@IGnss can be paired {1.0, 1.1}@IGnssMeasurement
+    // 1.0@IGnss is paired with 1.0@IGnssMeasurement
+    gnssMeasurementIface = nullptr;
+    if (gnssHal_V2_0 != nullptr && gnssMeasurementIface == nullptr) {
         auto gnssMeasurement = gnssHal_V2_0->getExtensionGnssMeasurement_2_0();
         if (!gnssMeasurement.isOk()) {
             ALOGD("Unable to get a handle to GnssMeasurement_V2_0");
@@ -1710,13 +1714,8 @@
             gnssMeasurementIface_V1_1 = gnssMeasurementIface_V2_0;
             gnssMeasurementIface = gnssMeasurementIface_V2_0;
         }
-        auto gnssCorrections = gnssHal_V2_0->getExtensionMeasurementCorrections();
-        if (!gnssCorrections.isOk()) {
-            ALOGD("Unable to get a handle to GnssMeasurementCorrections interface");
-        } else {
-            gnssCorrectionsIface = gnssCorrections;
-        }
-    } else if (gnssHal_V1_1 != nullptr) {
+    }
+    if (gnssHal_V1_1 != nullptr && gnssMeasurementIface == nullptr) {
          auto gnssMeasurement = gnssHal_V1_1->getExtensionGnssMeasurement_1_1();
          if (!gnssMeasurement.isOk()) {
              ALOGD("Unable to get a handle to GnssMeasurement_V1_1");
@@ -1724,16 +1723,26 @@
              gnssMeasurementIface_V1_1 = gnssMeasurement;
              gnssMeasurementIface = gnssMeasurementIface_V1_1;
          }
-    } else {
-         auto gnssMeasurement_V1_0 = gnssHal->getExtensionGnssMeasurement();
-         if (!gnssMeasurement_V1_0.isOk()) {
+    }
+    if (gnssMeasurementIface == nullptr) {
+         auto gnssMeasurement = gnssHal->getExtensionGnssMeasurement();
+         if (!gnssMeasurement.isOk()) {
              ALOGD("Unable to get a handle to GnssMeasurement");
          } else {
-             gnssMeasurementIface = gnssMeasurement_V1_0;
+             gnssMeasurementIface = gnssMeasurement;
          }
     }
 
     if (gnssHal_V2_0 != nullptr) {
+        auto gnssCorrections = gnssHal_V2_0->getExtensionMeasurementCorrections();
+        if (!gnssCorrections.isOk()) {
+            ALOGD("Unable to get a handle to GnssMeasurementCorrections interface");
+        } else {
+            gnssCorrectionsIface = gnssCorrections;
+        }
+    }
+
+    if (gnssHal_V2_0 != nullptr) {
         auto gnssDebug = gnssHal_V2_0->getExtensionGnssDebug_2_0();
         if (!gnssDebug.isOk()) {
             ALOGD("Unable to get a handle to GnssDebug_V2_0");
diff --git a/services/core/xsd/Android.bp b/services/core/xsd/Android.bp
index 5e1ea89..98e4343 100644
--- a/services/core/xsd/Android.bp
+++ b/services/core/xsd/Android.bp
@@ -2,5 +2,5 @@
     name: "default-permissions",
     srcs: ["default-permissions.xsd"],
     api_dir: "schema",
-    package_name: "com.android.server.pm.permission",
+    package_name: "com.android.server.pm.permission.configfile",
 }
diff --git a/services/core/xsd/default-permissions.xsd b/services/core/xsd/default-permissions.xsd
index d800a26..2e32be0 100644
--- a/services/core/xsd/default-permissions.xsd
+++ b/services/core/xsd/default-permissions.xsd
@@ -27,7 +27,7 @@
     </xs:element>
     <xs:complexType name="exception">
         <xs:sequence>
-            <xs:element name="permission" type="permission"/>
+            <xs:element name="permission" type="permission" maxOccurs="unbounded"/>
         </xs:sequence>
         <xs:attribute name="package" type="xs:string"/>
         <xs:attribute name="sha256-cert-digest" type="xs:string"/>
diff --git a/services/core/xsd/schema/current.txt b/services/core/xsd/schema/current.txt
index 4e67e5c..a2092e3 100644
--- a/services/core/xsd/schema/current.txt
+++ b/services/core/xsd/schema/current.txt
@@ -1,21 +1,20 @@
 // Signature format: 2.0
-package com.android.server.pm.permission {
+package com.android.server.pm.permission.configfile {
 
   public class Exception {
     ctor public Exception();
     method public String getBrand();
-    method public com.android.server.pm.permission.Permission getPermission();
+    method public java.util.List<com.android.server.pm.permission.configfile.Permission> getPermission();
     method public String getSha256CertDigest();
     method public String get_package();
     method public void setBrand(String);
-    method public void setPermission(com.android.server.pm.permission.Permission);
     method public void setSha256CertDigest(String);
     method public void set_package(String);
   }
 
   public class Exceptions {
     ctor public Exceptions();
-    method public java.util.List<com.android.server.pm.permission.Exception> getException();
+    method public java.util.List<com.android.server.pm.permission.configfile.Exception> getException();
   }
 
   public class Permission {
@@ -28,7 +27,7 @@
 
   public class XmlParser {
     ctor public XmlParser();
-    method public static com.android.server.pm.permission.Exceptions read(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
+    method public static com.android.server.pm.permission.configfile.Exceptions read(java.io.InputStream) throws javax.xml.datatype.DatatypeConfigurationException, java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public static String readText(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public static void skip(org.xmlpull.v1.XmlPullParser) throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
   }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 633367a..aaa6d16 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -11180,48 +11180,51 @@
 
         @Override
         public Intent createUserRestrictionSupportIntent(int userId, String userRestriction) {
-            int source;
-            long ident = mInjector.binderClearCallingIdentity();
+            final long ident = mInjector.binderClearCallingIdentity();
             try {
-                source = mUserManager.getUserRestrictionSource(userRestriction,
-                        UserHandle.of(userId));
+                final List<UserManager.EnforcingUser> sources = mUserManager
+                        .getUserRestrictionSources(userRestriction, UserHandle.of(userId));
+                if (sources == null || sources.isEmpty()) {
+                    // The restriction is not enforced.
+                    return null;
+                } else if (sources.size() > 1) {
+                    // In this case, we'll show an admin support dialog that does not
+                    // specify the admin.
+                    // TODO(b/128928355): if this restriction is enforced by multiple DPCs, return
+                    // the admin for the calling user.
+                    return DevicePolicyManagerService.this.createShowAdminSupportIntent(
+                            null, userId);
+                }
+                final UserManager.EnforcingUser enforcingUser = sources.get(0);
+                final int sourceType = enforcingUser.getUserRestrictionSource();
+                final int enforcingUserId = enforcingUser.getUserHandle().getIdentifier();
+                if (sourceType == UserManager.RESTRICTION_SOURCE_PROFILE_OWNER) {
+                    // Restriction was enforced by PO
+                    final ComponentName profileOwner = mOwners.getProfileOwnerComponent(
+                            enforcingUserId);
+                    if (profileOwner != null) {
+                        return DevicePolicyManagerService.this.createShowAdminSupportIntent(
+                                profileOwner, enforcingUserId);
+                    }
+                } else if (sourceType == UserManager.RESTRICTION_SOURCE_DEVICE_OWNER) {
+                    // Restriction was enforced by DO
+                    final Pair<Integer, ComponentName> deviceOwner =
+                            mOwners.getDeviceOwnerUserIdAndComponent();
+                    if (deviceOwner != null) {
+                        return DevicePolicyManagerService.this.createShowAdminSupportIntent(
+                                deviceOwner.second, deviceOwner.first);
+                    }
+                } else if (sourceType == UserManager.RESTRICTION_SOURCE_SYSTEM) {
+                    /*
+                     * In this case, the user restriction is enforced by the system.
+                     * So we won't show an admin support intent, even if it is also
+                     * enforced by a profile/device owner.
+                     */
+                    return null;
+                }
             } finally {
                 mInjector.binderRestoreCallingIdentity(ident);
             }
-            if ((source & UserManager.RESTRICTION_SOURCE_SYSTEM) != 0) {
-                /*
-                 * In this case, the user restriction is enforced by the system.
-                 * So we won't show an admin support intent, even if it is also
-                 * enforced by a profile/device owner.
-                 */
-                return null;
-            }
-            boolean enforcedByDo = (source & UserManager.RESTRICTION_SOURCE_DEVICE_OWNER) != 0;
-            boolean enforcedByPo = (source & UserManager.RESTRICTION_SOURCE_PROFILE_OWNER) != 0;
-            if (enforcedByDo && enforcedByPo) {
-                // In this case, we'll show an admin support dialog that does not
-                // specify the admin.
-                return DevicePolicyManagerService.this.createShowAdminSupportIntent(null, userId);
-            } else if (enforcedByPo) {
-                final ComponentName profileOwner = mOwners.getProfileOwnerComponent(userId);
-                if (profileOwner != null) {
-                    return DevicePolicyManagerService.this
-                            .createShowAdminSupportIntent(profileOwner, userId);
-                }
-                // This could happen if another thread has changed the profile owner since we called
-                // getUserRestrictionSource
-                return null;
-            } else if (enforcedByDo) {
-                final Pair<Integer, ComponentName> deviceOwner
-                        = mOwners.getDeviceOwnerUserIdAndComponent();
-                if (deviceOwner != null) {
-                    return DevicePolicyManagerService.this
-                            .createShowAdminSupportIntent(deviceOwner.second, deviceOwner.first);
-                }
-                // This could happen if another thread has changed the device owner since we called
-                // getUserRestrictionSource
-                return null;
-            }
             return null;
         }
 
diff --git a/services/net/Android.bp b/services/net/Android.bp
index 67fbdc4..8f48f5b 100644
--- a/services/net/Android.bp
+++ b/services/net/Android.bp
@@ -58,6 +58,7 @@
     name: "services.net",
     srcs: ["java/**/*.java"],
     static_libs: [
+        "dnsresolver_aidl_interface-java",
         "netd_aidl_interface-java",
         "networkstack-aidl-interfaces-java",
     ]
@@ -69,7 +70,7 @@
     srcs: [
         ":framework-annotations",
         "java/android/net/IpMemoryStoreClient.java",
-        "java/android/net/ipmemorystore/**.java",
+        "java/android/net/ipmemorystore/**/*.java",
     ],
     static_libs: [
         "ipmemorystore-aidl-interfaces-java",
diff --git a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
index 7c91b64..7a40e44 100644
--- a/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/AlarmManagerServiceTest.java
@@ -26,6 +26,7 @@
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.doThrow;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
@@ -57,6 +58,8 @@
 import android.app.ActivityManager;
 import android.app.AlarmManager;
 import android.app.IActivityManager;
+import android.app.IAlarmCompleteListener;
+import android.app.IAlarmListener;
 import android.app.IUidObserver;
 import android.app.PendingIntent;
 import android.app.usage.UsageStatsManagerInternal;
@@ -67,6 +70,7 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.PowerManager;
+import android.os.RemoteException;
 import android.os.UserHandle;
 import android.platform.test.annotations.Presubmit;
 import android.provider.Settings;
@@ -231,7 +235,7 @@
         doReturn(Looper.getMainLooper()).when(Looper::myLooper);
 
         when(mMockContext.getContentResolver()).thenReturn(mMockResolver);
-        doReturn("min_futurity=0").when(() ->
+        doReturn("min_futurity=0,min_interval=0").when(() ->
                 Settings.Global.getString(mMockResolver, Settings.Global.ALARM_MANAGER_CONSTANTS));
         mInjector = new Injector(mMockContext);
         mService = new AlarmManagerService(mMockContext, mInjector);
@@ -249,6 +253,7 @@
         // Other boot phases don't matter
         mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
         assertEquals(0, mService.mConstants.MIN_FUTURITY);
+        assertEquals(0, mService.mConstants.MIN_INTERVAL);
         mAppStandbyWindow = mService.mConstants.APP_STANDBY_WINDOW;
         ArgumentCaptor<UsageStatsManagerInternal.AppIdleStateChangeListener> captor =
                 ArgumentCaptor.forClass(UsageStatsManagerInternal.AppIdleStateChangeListener.class);
@@ -257,15 +262,28 @@
     }
 
     private void setTestAlarm(int type, long triggerTime, PendingIntent operation) {
-        setTestAlarm(type, triggerTime, operation, TEST_CALLING_UID);
+        setTestAlarm(type, triggerTime, operation, 0, TEST_CALLING_UID);
     }
 
-    private void setTestAlarm(int type, long triggerTime, PendingIntent operation, int callingUid) {
-        mService.setImpl(type, triggerTime, AlarmManager.WINDOW_EXACT, 0,
+    private void setRepeatingTestAlarm(int type, long firstTrigger, long interval,
+            PendingIntent pi) {
+        setTestAlarm(type, firstTrigger, pi, interval, TEST_CALLING_UID);
+    }
+
+    private void setTestAlarm(int type, long triggerTime, PendingIntent operation, long interval,
+            int callingUid) {
+        mService.setImpl(type, triggerTime, AlarmManager.WINDOW_EXACT, interval,
                 operation, null, "test", AlarmManager.FLAG_STANDALONE, null, null,
                 callingUid, TEST_CALLING_PACKAGE);
     }
 
+    private void setTestAlarmWithListener(int type, long triggerTime, IAlarmListener listener) {
+        mService.setImpl(type, triggerTime, AlarmManager.WINDOW_EXACT, 0,
+                null, listener, "test", AlarmManager.FLAG_STANDALONE, null, null,
+                TEST_CALLING_UID, TEST_CALLING_PACKAGE);
+    }
+
+
     private PendingIntent getNewMockPendingIntent() {
         return getNewMockPendingIntent(TEST_CALLING_UID);
     }
@@ -738,14 +756,14 @@
     @Test
     public void alarmCountKeyedOnCallingUid() {
         final int mockCreatorUid = 431412;
-        final PendingIntent pi = getNewMockPendingIntent(mockCreatorUid);
-        setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + 5, pi);
+        setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + 5,
+                getNewMockPendingIntent(mockCreatorUid));
         assertEquals(1, mService.mAlarmsPerUid.get(TEST_CALLING_UID));
         assertEquals(-1, mService.mAlarmsPerUid.get(mockCreatorUid, -1));
     }
 
     @Test
-    public void alarmCountOnSet() {
+    public void alarmCountOnSetPi() {
         final int numAlarms = 103;
         final int[] types = {RTC_WAKEUP, RTC, ELAPSED_REALTIME_WAKEUP, ELAPSED_REALTIME};
         for (int i = 1; i <= numAlarms; i++) {
@@ -755,7 +773,21 @@
     }
 
     @Test
-    public void alarmCountOnExpiration() throws InterruptedException {
+    public void alarmCountOnSetListener() {
+        final int numAlarms = 103;
+        final int[] types = {RTC_WAKEUP, RTC, ELAPSED_REALTIME_WAKEUP, ELAPSED_REALTIME};
+        for (int i = 1; i <= numAlarms; i++) {
+            setTestAlarmWithListener(types[i % 4], mNowElapsedTest + i, new IAlarmListener.Stub() {
+                @Override
+                public void doAlarm(IAlarmCompleteListener callback) throws RemoteException {
+                }
+            });
+            assertEquals(i, mService.mAlarmsPerUid.get(TEST_CALLING_UID));
+        }
+    }
+
+    @Test
+    public void alarmCountOnExpirationPi() throws InterruptedException {
         final int numAlarms = 8; // This test is slow
         for (int i = 0; i < numAlarms; i++) {
             setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + i + 10, getNewMockPendingIntent());
@@ -770,6 +802,86 @@
     }
 
     @Test
+    public void alarmCountOnExpirationListener() throws InterruptedException {
+        final int numAlarms = 8; // This test is slow
+        for (int i = 0; i < numAlarms; i++) {
+            setTestAlarmWithListener(ELAPSED_REALTIME, mNowElapsedTest + i + 10,
+                    new IAlarmListener.Stub() {
+                        @Override
+                        public void doAlarm(IAlarmCompleteListener callback)
+                                throws RemoteException {
+                        }
+                    });
+        }
+        int expired = 0;
+        while (expired < numAlarms) {
+            mNowElapsedTest = mTestTimer.getElapsed();
+            mTestTimer.expire();
+            expired++;
+            assertEquals(numAlarms - expired, mService.mAlarmsPerUid.get(TEST_CALLING_UID, 0));
+        }
+    }
+
+    @Test
+    public void alarmCountOnExceptionWhileSendingPi() throws Exception {
+        final int numAlarms = 5; // This test is slow
+        for (int i = 0; i < numAlarms; i++) {
+            final PendingIntent pi = getNewMockPendingIntent();
+            doThrow(PendingIntent.CanceledException.class).when(pi).send(eq(mMockContext), eq(0),
+                    any(), any(), any(), any(), any());
+            setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + i + 10, pi);
+        }
+        int expired = 0;
+        while (expired < numAlarms) {
+            mNowElapsedTest = mTestTimer.getElapsed();
+            mTestTimer.expire();
+            expired++;
+            assertEquals(numAlarms - expired, mService.mAlarmsPerUid.get(TEST_CALLING_UID, 0));
+        }
+    }
+
+    @Test
+    public void alarmCountOnExceptionWhileCallingListener() throws Exception {
+        final int numAlarms = 5; // This test is slow
+        for (int i = 0; i < numAlarms; i++) {
+            final IAlarmListener listener = new IAlarmListener.Stub() {
+                @Override
+                public void doAlarm(IAlarmCompleteListener callback) throws RemoteException {
+                    throw new RemoteException("For testing behavior on exception");
+                }
+            };
+            setTestAlarmWithListener(ELAPSED_REALTIME, mNowElapsedTest + i + 10, listener);
+        }
+        int expired = 0;
+        while (expired < numAlarms) {
+            mNowElapsedTest = mTestTimer.getElapsed();
+            mTestTimer.expire();
+            expired++;
+            assertEquals(numAlarms - expired, mService.mAlarmsPerUid.get(TEST_CALLING_UID, 0));
+        }
+    }
+
+    @Test
+    public void alarmCountForRepeatingAlarms() throws Exception {
+        final long interval = 1231;
+        final long firstTrigger = mNowElapsedTest + 321;
+        final PendingIntent pi = getNewMockPendingIntent();
+        setRepeatingTestAlarm(ELAPSED_REALTIME, firstTrigger, interval, pi);
+        assertEquals(1, mService.mAlarmsPerUid.get(TEST_CALLING_UID));
+
+        for (int i = 0; i < 5; i++) {
+            mNowElapsedTest = mTestTimer.getElapsed();
+            mTestTimer.expire();
+            assertEquals(1, mService.mAlarmsPerUid.get(TEST_CALLING_UID));
+        }
+        doThrow(PendingIntent.CanceledException.class).when(pi).send(eq(mMockContext), eq(0),
+                any(), any(), any(), any(), any());
+        mNowElapsedTest = mTestTimer.getElapsed();
+        mTestTimer.expire();
+        assertEquals(-1, mService.mAlarmsPerUid.get(TEST_CALLING_UID, -1));
+    }
+
+    @Test
     public void alarmCountOnUidRemoved() {
         final int numAlarms = 10;
         for (int i = 0; i < numAlarms; i++) {
@@ -798,7 +910,7 @@
         for (int i = 0; i < numAlarms; i++) {
             int mockUid = UserHandle.getUid(mockUserId, 1234 + i);
             setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + i + 10,
-                    getNewMockPendingIntent(mockUid), mockUid);
+                    getNewMockPendingIntent(mockUid), 0, mockUid);
         }
         assertEquals(numAlarms, mService.mAlarmsPerUid.size());
         mService.removeUserLocked(mockUserId);
@@ -820,6 +932,12 @@
         }
     }
 
+    @Test
+    public void alarmCountOnInvalidSet() {
+        setTestAlarm(ELAPSED_REALTIME, mNowElapsedTest + 12345, null);
+        assertEquals(-1, mService.mAlarmsPerUid.get(TEST_CALLING_UID, -1));
+    }
+
     @After
     public void tearDown() {
         if (mMockingSession != null) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/AppCompactorTest.java b/services/tests/mockingservicestests/src/com/android/server/am/AppCompactorTest.java
index da439b8..b0c97d1 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/AppCompactorTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/AppCompactorTest.java
@@ -23,6 +23,7 @@
 
 import android.os.Handler;
 import android.os.HandlerThread;
+import android.platform.test.annotations.Presubmit;
 import android.provider.DeviceConfig;
 
 import com.android.server.appop.AppOpsService;
@@ -46,6 +47,7 @@
  * Build/Install/Run:
  * atest FrameworksMockingServicesTests:AppCompactorTest
  */
+@Presubmit
 @RunWith(MockitoJUnitRunner.class)
 public final class AppCompactorTest {
 
@@ -129,6 +131,12 @@
                 AppCompactor.KEY_COMPACT_THROTTLE_4,
                 Long.toString(AppCompactor.DEFAULT_COMPACT_THROTTLE_4 + 1), false);
         DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                AppCompactor.KEY_COMPACT_THROTTLE_5,
+                Long.toString(AppCompactor.DEFAULT_COMPACT_THROTTLE_5 + 1), false);
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                AppCompactor.KEY_COMPACT_THROTTLE_6,
+                Long.toString(AppCompactor.DEFAULT_COMPACT_THROTTLE_6 + 1), false);
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
                 AppCompactor.KEY_COMPACT_STATSD_SAMPLE_RATE,
                 Float.toString(AppCompactor.DEFAULT_STATSD_SAMPLE_RATE + 0.1f), false);
 
@@ -151,6 +159,10 @@
                 AppCompactor.DEFAULT_COMPACT_THROTTLE_4 + 1);
         assertThat(mCompactorUnderTest.mStatsdSampleRate).isEqualTo(
                 AppCompactor.DEFAULT_STATSD_SAMPLE_RATE + 0.1f);
+        assertThat(mCompactorUnderTest.mCompactThrottleBFGS).isEqualTo(
+                AppCompactor.DEFAULT_COMPACT_THROTTLE_5 + 1);
+        assertThat(mCompactorUnderTest.mCompactThrottlePersistent).isEqualTo(
+                AppCompactor.DEFAULT_COMPACT_THROTTLE_6 + 1);
     }
 
     @Test
@@ -254,7 +266,7 @@
         mCompactorUnderTest.init();
 
         // When we override new reasonable throttle values after init...
-        mCountDown = new CountDownLatch(4);
+        mCountDown = new CountDownLatch(6);
         DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
                 AppCompactor.KEY_COMPACT_THROTTLE_1,
                 Long.toString(AppCompactor.DEFAULT_COMPACT_THROTTLE_1 + 1), false);
@@ -267,6 +279,12 @@
         DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
                 AppCompactor.KEY_COMPACT_THROTTLE_4,
                 Long.toString(AppCompactor.DEFAULT_COMPACT_THROTTLE_4 + 1), false);
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                AppCompactor.KEY_COMPACT_THROTTLE_5,
+                Long.toString(AppCompactor.DEFAULT_COMPACT_THROTTLE_5 + 1), false);
+        DeviceConfig.setProperty(DeviceConfig.NAMESPACE_ACTIVITY_MANAGER,
+                AppCompactor.KEY_COMPACT_THROTTLE_6,
+                Long.toString(AppCompactor.DEFAULT_COMPACT_THROTTLE_6 + 1), false);
         assertThat(mCountDown.await(5, TimeUnit.SECONDS)).isTrue();
 
         // Then those flags values are reflected in the compactor.
@@ -278,6 +296,10 @@
                 AppCompactor.DEFAULT_COMPACT_THROTTLE_3 + 1);
         assertThat(mCompactorUnderTest.mCompactThrottleFullFull).isEqualTo(
                 AppCompactor.DEFAULT_COMPACT_THROTTLE_4 + 1);
+        assertThat(mCompactorUnderTest.mCompactThrottleBFGS).isEqualTo(
+                AppCompactor.DEFAULT_COMPACT_THROTTLE_5 + 1);
+        assertThat(mCompactorUnderTest.mCompactThrottlePersistent).isEqualTo(
+                AppCompactor.DEFAULT_COMPACT_THROTTLE_6 + 1);
     }
 
     @Test
diff --git a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
index cad71a2..08f6a37 100644
--- a/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/job/controllers/QuotaControllerTest.java
@@ -722,6 +722,147 @@
         assertEquals(expectedStats, newStatsRare);
     }
 
+    /**
+     * Test getTimeUntilQuotaConsumedLocked when the determination is based within the bucket
+     * window.
+     */
+    @Test
+    public void testGetTimeUntilQuotaConsumedLocked_BucketWindow() {
+        final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
+        // Close to RARE boundary.
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(now - (24 * HOUR_IN_MILLIS - 30 * SECOND_IN_MILLIS),
+                        30 * SECOND_IN_MILLIS, 5));
+        // Far away from FREQUENT boundary.
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(now - (7 * HOUR_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5));
+        // Overlap WORKING_SET boundary.
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(now - (2 * HOUR_IN_MILLIS + MINUTE_IN_MILLIS),
+                        3 * MINUTE_IN_MILLIS, 5));
+        // Close to ACTIVE boundary.
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(now - (9 * MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5));
+
+        setStandbyBucket(RARE_INDEX);
+        assertEquals(30 * SECOND_IN_MILLIS,
+                mQuotaController.getRemainingExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+        assertEquals(MINUTE_IN_MILLIS,
+                mQuotaController.getTimeUntilQuotaConsumedLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        setStandbyBucket(FREQUENT_INDEX);
+        assertEquals(MINUTE_IN_MILLIS,
+                mQuotaController.getRemainingExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+        assertEquals(MINUTE_IN_MILLIS,
+                mQuotaController.getTimeUntilQuotaConsumedLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        setStandbyBucket(WORKING_INDEX);
+        assertEquals(5 * MINUTE_IN_MILLIS,
+                mQuotaController.getRemainingExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+        assertEquals(7 * MINUTE_IN_MILLIS,
+                mQuotaController.getTimeUntilQuotaConsumedLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        // ACTIVE window = allowed time, so jobs can essentially run non-stop until they reach the
+        // max execution time.
+        setStandbyBucket(ACTIVE_INDEX);
+        assertEquals(7 * MINUTE_IN_MILLIS,
+                mQuotaController.getRemainingExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+        assertEquals(mConstants.QUOTA_CONTROLLER_MAX_EXECUTION_TIME_MS - 9 * MINUTE_IN_MILLIS,
+                mQuotaController.getTimeUntilQuotaConsumedLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+    }
+
+    /**
+     * Test getTimeUntilQuotaConsumedLocked when the app is close to the max execution limit.
+     */
+    @Test
+    public void testGetTimeUntilQuotaConsumedLocked_MaxExecution() {
+        final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
+        // Overlap boundary.
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(
+                        now - (24 * HOUR_IN_MILLIS + 8 * MINUTE_IN_MILLIS), 4 * HOUR_IN_MILLIS, 5));
+
+        setStandbyBucket(WORKING_INDEX);
+        assertEquals(8 * MINUTE_IN_MILLIS,
+                mQuotaController.getRemainingExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+        // Max time will phase out, so should use bucket limit.
+        assertEquals(10 * MINUTE_IN_MILLIS,
+                mQuotaController.getTimeUntilQuotaConsumedLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE).clear();
+        // Close to boundary.
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(now - (24 * HOUR_IN_MILLIS - MINUTE_IN_MILLIS),
+                        4 * HOUR_IN_MILLIS - 5 * MINUTE_IN_MILLIS, 5));
+
+        setStandbyBucket(WORKING_INDEX);
+        assertEquals(5 * MINUTE_IN_MILLIS,
+                mQuotaController.getRemainingExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+        assertEquals(10 * MINUTE_IN_MILLIS,
+                mQuotaController.getTimeUntilQuotaConsumedLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE).clear();
+        // Far from boundary.
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(
+                        now - (20 * HOUR_IN_MILLIS), 4 * HOUR_IN_MILLIS - 3 * MINUTE_IN_MILLIS, 5));
+
+        setStandbyBucket(WORKING_INDEX);
+        assertEquals(3 * MINUTE_IN_MILLIS,
+                mQuotaController.getRemainingExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+        assertEquals(3 * MINUTE_IN_MILLIS,
+                mQuotaController.getTimeUntilQuotaConsumedLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+    }
+
+    /**
+     * Test getTimeUntilQuotaConsumedLocked when the max execution time and bucket window time
+     * remaining are equal.
+     */
+    @Test
+    public void testGetTimeUntilQuotaConsumedLocked_EqualTimeRemaining() {
+        final long now = JobSchedulerService.sElapsedRealtimeClock.millis();
+        setStandbyBucket(FREQUENT_INDEX);
+
+        // Overlap boundary.
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(
+                        now - (24 * HOUR_IN_MILLIS + 11 * MINUTE_IN_MILLIS),
+                        4 * HOUR_IN_MILLIS,
+                        5));
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(
+                        now - (8 * HOUR_IN_MILLIS + MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5));
+
+        // Both max and bucket time have 8 minutes left.
+        assertEquals(8 * MINUTE_IN_MILLIS,
+                mQuotaController.getRemainingExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+        // Max time essentially free. Bucket time has 2 min phase out plus original 8 minute
+        // window time.
+        assertEquals(10 * MINUTE_IN_MILLIS,
+                mQuotaController.getTimeUntilQuotaConsumedLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+
+        mQuotaController.getTimingSessions(SOURCE_USER_ID, SOURCE_PACKAGE).clear();
+        // Overlap boundary.
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(
+                        now - (24 * HOUR_IN_MILLIS + MINUTE_IN_MILLIS), 2 * MINUTE_IN_MILLIS, 5));
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(
+                        now - (20 * HOUR_IN_MILLIS),
+                        3 * HOUR_IN_MILLIS + 48 * MINUTE_IN_MILLIS,
+                        5));
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(
+                        now - (8 * HOUR_IN_MILLIS + MINUTE_IN_MILLIS), 3 * MINUTE_IN_MILLIS, 5));
+
+        // Both max and bucket time have 8 minutes left.
+        assertEquals(8 * MINUTE_IN_MILLIS,
+                mQuotaController.getRemainingExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+        // Max time only has one minute phase out. Bucket time has 2 minute phase out.
+        assertEquals(9 * MINUTE_IN_MILLIS,
+                mQuotaController.getTimeUntilQuotaConsumedLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
+    }
+
     @Test
     public void testIsWithinQuotaLocked_NeverApp() {
         assertFalse(mQuotaController.isWithinQuotaLocked(0, "com.android.test.never", NEVER_INDEX));
@@ -1902,7 +2043,10 @@
         // window, so as the package "reaches its quota" it will have more to keep running.
         mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
                 createTimingSession(now - 2 * HOUR_IN_MILLIS,
-                        10 * MINUTE_IN_MILLIS - remainingTimeMs, 1));
+                        10 * SECOND_IN_MILLIS - remainingTimeMs, 1));
+        mQuotaController.saveTimingSession(SOURCE_USER_ID, SOURCE_PACKAGE,
+                createTimingSession(now - HOUR_IN_MILLIS,
+                        9 * MINUTE_IN_MILLIS + 50 * SECOND_IN_MILLIS, 1));
 
         assertEquals(remainingTimeMs, mQuotaController.getRemainingExecutionTimeLocked(jobStatus));
         // Start the job.
@@ -1919,6 +2063,18 @@
         // amount of remaining time left its quota.
         assertEquals(remainingTimeMs,
                 mQuotaController.getRemainingExecutionTimeLocked(SOURCE_USER_ID, SOURCE_PACKAGE));
-        verify(handler, atLeast(1)).sendMessageDelayed(any(), eq(remainingTimeMs));
+        // Handler is told to check when the quota will be consumed, not when the initial
+        // remaining time is over.
+        verify(handler, atLeast(1)).sendMessageDelayed(any(), eq(10 * SECOND_IN_MILLIS));
+        verify(handler, never()).sendMessageDelayed(any(), eq(remainingTimeMs));
+
+        // After 10 seconds, the job should finally be out of quota.
+        advanceElapsedClock(10 * SECOND_IN_MILLIS - remainingTimeMs);
+        // Wait for some extra time to allow for job processing.
+        verify(mJobSchedulerService,
+                timeout(12 * SECOND_IN_MILLIS).times(1))
+                .onControllerStateChanged();
+        assertFalse(jobStatus.isConstraintSatisfied(JobStatus.CONSTRAINT_WITHIN_QUOTA));
+        verify(handler, never()).sendMessageDelayed(any(), anyInt());
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index bd7774a..cbabb0b 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -85,10 +85,11 @@
 import android.telephony.TelephonyManager;
 import android.telephony.data.ApnSetting;
 import android.test.MoreAsserts;
-import android.test.suitebuilder.annotation.SmallTest;
 import android.util.ArraySet;
 import android.util.Pair;
 
+import androidx.test.filters.SmallTest;
+
 import com.android.internal.R;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.server.LocalServices;
@@ -99,7 +100,6 @@
 import org.hamcrest.BaseMatcher;
 import org.hamcrest.Description;
 import org.mockito.Mockito;
-import org.mockito.invocation.InvocationOnMock;
 import org.mockito.stubbing.Answer;
 
 import java.io.File;
@@ -241,29 +241,23 @@
         final Map<Pair<String, UserHandle>, Bundle> appRestrictions = new HashMap<>();
 
         // UM.setApplicationRestrictions() will save to appRestrictions.
-        doAnswer(new Answer<Void>() {
-            @Override
-            public Void answer(InvocationOnMock invocation) throws Throwable {
-                String pkg = (String) invocation.getArguments()[0];
-                Bundle bundle = (Bundle) invocation.getArguments()[1];
-                UserHandle user = (UserHandle) invocation.getArguments()[2];
+        doAnswer((Answer<Void>) invocation -> {
+            String pkg = (String) invocation.getArguments()[0];
+            Bundle bundle = (Bundle) invocation.getArguments()[1];
+            UserHandle user = (UserHandle) invocation.getArguments()[2];
 
-                appRestrictions.put(Pair.create(pkg, user), bundle);
+            appRestrictions.put(Pair.create(pkg, user), bundle);
 
-                return null;
-            }
+            return null;
         }).when(getServices().userManager).setApplicationRestrictions(
                 anyString(), nullable(Bundle.class), any(UserHandle.class));
 
         // UM.getApplicationRestrictions() will read from appRestrictions.
-        doAnswer(new Answer<Bundle>() {
-            @Override
-            public Bundle answer(InvocationOnMock invocation) throws Throwable {
-                String pkg = (String) invocation.getArguments()[0];
-                UserHandle user = (UserHandle) invocation.getArguments()[1];
+        doAnswer((Answer<Bundle>) invocation -> {
+            String pkg = (String) invocation.getArguments()[0];
+            UserHandle user = (UserHandle) invocation.getArguments()[1];
 
-                return appRestrictions.get(Pair.create(pkg, user));
-            }
+            return appRestrictions.get(Pair.create(pkg, user));
         }).when(getServices().userManager).getApplicationRestrictions(
                 anyString(), any(UserHandle.class));
 
@@ -2242,11 +2236,13 @@
         intent = dpm.createAdminSupportIntent(UserManager.DISALLOW_ADJUST_VOLUME);
         assertNull(intent);
 
-        // Permission that is set by device owner returns correct intent
-        when(getServices().userManager.getUserRestrictionSource(
+        // UM.getUserRestrictionSources() will return a list of size 1 with the caller resource.
+        doAnswer((Answer<List<UserManager.EnforcingUser>>) invocation -> Collections.singletonList(
+                new UserManager.EnforcingUser(
+                        UserHandle.myUserId(), UserManager.RESTRICTION_SOURCE_DEVICE_OWNER))
+        ).when(getServices().userManager).getUserRestrictionSources(
                 eq(UserManager.DISALLOW_ADJUST_VOLUME),
-                eq(UserHandle.getUserHandleForUid(mContext.binder.callingUid))))
-                .thenReturn(UserManager.RESTRICTION_SOURCE_DEVICE_OWNER);
+                eq(UserHandle.getUserHandleForUid(UserHandle.myUserId())));
         intent = dpm.createAdminSupportIntent(UserManager.DISALLOW_ADJUST_VOLUME);
         assertNotNull(intent);
         assertEquals(Settings.ACTION_SHOW_ADMIN_SUPPORT_DETAILS, intent.getAction());
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
index 3d02576..2fbeebd 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/BaseLockSettingsServiceTests.java
@@ -56,7 +56,7 @@
 import java.util.Arrays;
 
 
-public class BaseLockSettingsServiceTests extends AndroidTestCase {
+public abstract class BaseLockSettingsServiceTests extends AndroidTestCase {
     protected static final int PRIMARY_USER_ID = 0;
     protected static final int MANAGED_PROFILE_USER_ID = 12;
     protected static final int TURNED_OFF_PROFILE_USER_ID = 17;
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/CachedSyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/CachedSyntheticPasswordTests.java
index ca4330f..d2a9145 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/CachedSyntheticPasswordTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/CachedSyntheticPasswordTests.java
@@ -26,6 +26,9 @@
 import static org.mockito.Mockito.when;
 
 import android.os.RemoteException;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
 
 import com.android.internal.widget.LockPatternUtils;
 import com.android.internal.widget.VerifyCredentialResponse;
@@ -40,6 +43,8 @@
  * By default, those tests run without caching. Untrusted credential reset depends on caching so
  * this class included those tests.
  */
+@SmallTest
+@Presubmit
 public class CachedSyntheticPasswordTests extends SyntheticPasswordTests {
 
     @Override
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java
index 255e694b..7ebc745 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTests.java
@@ -26,8 +26,11 @@
 import static com.android.internal.widget.LockPatternUtils.CREDENTIAL_TYPE_PATTERN;
 
 import android.os.RemoteException;
+import android.platform.test.annotations.Presubmit;
 import android.service.gatekeeper.GateKeeperResponse;
 
+import androidx.test.filters.SmallTest;
+
 import com.android.internal.widget.LockPatternUtils;
 import com.android.internal.widget.VerifyCredentialResponse;
 import com.android.server.locksettings.FakeGateKeeperService.VerifyHandle;
@@ -36,6 +39,8 @@
 /**
  * runtest frameworks-services -c com.android.server.locksettings.LockSettingsServiceTests
  */
+@SmallTest
+@Presubmit
 public class LockSettingsServiceTests extends BaseLockSettingsServiceTests {
 
     @Override
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsShellCommandTest.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsShellCommandTest.java
index fcfc6d2..c00d33b 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsShellCommandTest.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsShellCommandTest.java
@@ -21,7 +21,7 @@
 
 import static com.android.internal.widget.LockPatternUtils.stringToPattern;
 
-import static junit.framework.Assert.*;
+import static junit.framework.Assert.assertEquals;
 
 import static org.mockito.Matchers.anyInt;
 import static org.mockito.Mockito.any;
@@ -30,6 +30,10 @@
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
+import static java.io.FileDescriptor.err;
+import static java.io.FileDescriptor.in;
+import static java.io.FileDescriptor.out;
+
 import android.app.ActivityManager;
 import android.content.Context;
 import android.os.Binder;
@@ -51,8 +55,6 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
-import static java.io.FileDescriptor.*;
-
 /**
  * Test class for {@link LockSettingsShellCommand}.
  *
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java
index 6e1f357..8af4edd 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsStorageTests.java
@@ -29,11 +29,14 @@
 import android.os.FileUtils;
 import android.os.UserManager;
 import android.os.storage.StorageManager;
+import android.platform.test.annotations.Presubmit;
 import android.test.AndroidTestCase;
 import android.util.Log;
 import android.util.Log.TerribleFailure;
 import android.util.Log.TerribleFailureHandler;
 
+import androidx.test.filters.SmallTest;
+
 import com.android.internal.widget.LockPatternUtils;
 import com.android.server.PersistentDataBlockManagerInternal;
 import com.android.server.locksettings.LockSettingsStorage.CredentialHash;
@@ -48,6 +51,8 @@
 /**
  * runtest frameworks-services -c com.android.server.locksettings.LockSettingsStorageTests
  */
+@SmallTest
+@Presubmit
 public class LockSettingsStorageTests extends AndroidTestCase {
     private static final int SOME_USER_ID = 1034;
     private final byte[] PASSWORD_0 = "thepassword0".getBytes();
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/PasswordSlotManagerTests.java b/services/tests/servicestests/src/com/android/server/locksettings/PasswordSlotManagerTests.java
index 1d5a99b..31526b5 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/PasswordSlotManagerTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/PasswordSlotManagerTests.java
@@ -16,8 +16,11 @@
 
 package com.android.server.locksettings;
 
+import android.platform.test.annotations.Presubmit;
 import android.test.AndroidTestCase;
 
+import androidx.test.filters.SmallTest;
+
 import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.util.HashMap;
@@ -25,6 +28,8 @@
 import java.util.Map;
 import java.util.Set;
 
+@SmallTest
+@Presubmit
 public class PasswordSlotManagerTests extends AndroidTestCase {
 
     PasswordSlotManagerTestable mManager;
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/SP800DeriveTests.java b/services/tests/servicestests/src/com/android/server/locksettings/SP800DeriveTests.java
index fc2dcb9..29d0fc1 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/SP800DeriveTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/SP800DeriveTests.java
@@ -16,10 +16,15 @@
 
 package com.android.server.locksettings;
 
+import android.platform.test.annotations.Presubmit;
 import android.test.AndroidTestCase;
 
+import androidx.test.filters.SmallTest;
+
 import com.android.internal.util.HexDump;
 
+@SmallTest
+@Presubmit
 public class SP800DeriveTests extends AndroidTestCase {
     public void testFixedInput() throws Exception {
         // CAVP: https://csrc.nist.gov/projects/cryptographic-algorithm-validation-program/key-derivation
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
index 5a9ca0f..0273f76 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
@@ -33,6 +33,9 @@
 import android.app.admin.PasswordMetrics;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
 
 import com.android.internal.widget.LockPatternUtils;
 import com.android.internal.widget.VerifyCredentialResponse;
@@ -48,6 +51,8 @@
 /**
  * runtest frameworks-services -c com.android.server.locksettings.SyntheticPasswordTests
  */
+@SmallTest
+@Presubmit
 public class SyntheticPasswordTests extends BaseLockSettingsServiceTests {
 
     public static final byte[] PAYLOAD = new byte[] {1, 2, -1, -2, 55};
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/WeaverBasedSyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/WeaverBasedSyntheticPasswordTests.java
index 5e56704..abbf016 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/WeaverBasedSyntheticPasswordTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/WeaverBasedSyntheticPasswordTests.java
@@ -1,5 +1,11 @@
 package com.android.server.locksettings;
 
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+
+@SmallTest
+@Presubmit
 public class WeaverBasedSyntheticPasswordTests extends SyntheticPasswordTests {
 
     @Override
diff --git a/services/tests/uiservicestests/AndroidManifest.xml b/services/tests/uiservicestests/AndroidManifest.xml
index aa3135f..3ff85c8 100644
--- a/services/tests/uiservicestests/AndroidManifest.xml
+++ b/services/tests/uiservicestests/AndroidManifest.xml
@@ -29,6 +29,7 @@
     <uses-permission android:name="android.permission.DEVICE_POWER" />
     <uses-permission android:name="android.permission.ACCESS_CONTENT_PROVIDERS_EXTERNALLY" />
     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.OBSERVE_ROLE_HOLDERS" />
 
     <application android:debuggable="true">
         <uses-library android:name="android.test.runner" />
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 987d46a..4332fea 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -79,6 +79,7 @@
 import android.app.NotificationChannel;
 import android.app.NotificationChannelGroup;
 import android.app.NotificationManager;
+import android.app.PendingIntent;
 import android.app.admin.DevicePolicyManagerInternal;
 import android.app.usage.UsageStatsManagerInternal;
 import android.companion.ICompanionDeviceManager;
@@ -92,6 +93,7 @@
 import android.content.pm.ParceledListSlice;
 import android.content.res.Resources;
 import android.graphics.Color;
+import android.graphics.drawable.Icon;
 import android.media.AudioManager;
 import android.net.Uri;
 import android.os.Binder;
@@ -101,6 +103,7 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.provider.DeviceConfig;
 import android.provider.MediaStore;
 import android.provider.Settings;
@@ -120,9 +123,6 @@
 import android.util.ArraySet;
 import android.util.AtomicFile;
 
-import androidx.annotation.Nullable;
-import androidx.test.InstrumentationRegistry;
-
 import com.android.internal.R;
 import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
 import com.android.internal.statusbar.NotificationVisibility;
@@ -149,7 +149,6 @@
 import java.io.BufferedInputStream;
 import java.io.ByteArrayInputStream;
 import java.io.File;
-import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -160,6 +159,9 @@
 import java.util.Set;
 import java.util.function.Consumer;
 
+import androidx.annotation.Nullable;
+import androidx.test.InstrumentationRegistry;
+
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @RunWithLooper
@@ -226,23 +228,21 @@
     @Mock
     AppOpsManager mAppOpsManager;
     @Mock
-    private UserManagerService mUserMangerService;
-    @Mock
     private TestableNotificationManagerService.NotificationAssistantAccessGrantedCallback
             mNotificationAssistantAccessGrantedCallback;
+    @Mock
+    UserManager mUm;
 
     // Use a Testable subclass so we can simulate calls from the system without failing.
     private static class TestableNotificationManagerService extends NotificationManagerService {
         int countSystemChecks = 0;
         boolean isSystemUid = true;
         int countLogSmartSuggestionsVisible = 0;
-        UserManagerService mUserManagerService;
         @Nullable
         NotificationAssistantAccessGrantedCallback mNotificationAssistantAccessGrantedCallback;
 
-        TestableNotificationManagerService(Context context, UserManagerService userManagerService) {
+        TestableNotificationManagerService(Context context) {
             super(context);
-            mUserManagerService = userManagerService;
         }
 
         @Override
@@ -279,11 +279,6 @@
         }
 
         @Override
-        UserManagerService getUserManagerService() {
-            return mUserManagerService;
-        }
-
-        @Override
         protected void setNotificationAssistantAccessGrantedForUserInternal(
                 ComponentName assistant, int userId, boolean granted) {
             if (mNotificationAssistantAccessGrantedCallback != null) {
@@ -326,7 +321,7 @@
         LocalServices.removeServiceForTest(WindowManagerInternal.class);
         LocalServices.addService(WindowManagerInternal.class, mWindowManagerInternal);
 
-        mService = new TestableNotificationManagerService(mContext, mUserMangerService);
+        mService = new TestableNotificationManagerService(mContext);
 
         // Use this testable looper.
         mTestableLooper = TestableLooper.get(this);
@@ -379,7 +374,7 @@
                     mCompanionMgr, mSnoozeHelper, mUsageStats, mPolicyFile, mActivityManager,
                     mGroupHelper, mAm, mAppUsageStats,
                     mock(DevicePolicyManagerInternal.class), mUgm, mUgmInternal,
-                    mAppOpsManager);
+                    mAppOpsManager, mUm);
             mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
         } catch (SecurityException e) {
             if (!e.getMessage().contains("Permission Denial: not allowed to send broadcast")) {
@@ -507,6 +502,13 @@
                 false);
     }
 
+    private Notification.BubbleMetadata.Builder getBasicBubbleMetadataBuilder() {
+        PendingIntent pi = PendingIntent.getActivity(mContext, 0, new Intent(), 0);
+        return new Notification.BubbleMetadata.Builder()
+                .setIntent(pi)
+                .setIcon(Icon.createWithResource(mContext, android.R.drawable.sym_def_app_icon));
+    }
+
     @Test
     public void testCreateNotificationChannels_SingleChannel() throws Exception {
         final NotificationChannel channel =
@@ -1920,8 +1922,8 @@
     }
 
     @Test
-    public void testHasCompanionDevice_noService() throws Exception {
-        mService = new TestableNotificationManagerService(mContext, mUserMangerService);
+    public void testHasCompanionDevice_noService() {
+        mService = new TestableNotificationManagerService(mContext);
 
         assertFalse(mService.hasCompanionDevice(mListener));
     }
@@ -2623,7 +2625,7 @@
                 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />"
                 + "</dnd_apps>"
                 + "</notification-policy>";
-        when(mUserMangerService.isManagedProfile(10)).thenReturn(true);
+        when(mUm.isManagedProfile(10)).thenReturn(true);
         mService.readPolicyXml(
                 new BufferedInputStream(new ByteArrayInputStream(policyXml.getBytes())),
                 true,
@@ -2647,7 +2649,7 @@
                 + "<service_listing approved=\"test\" user=\"10\" primary=\"true\" />"
                 + "</dnd_apps>"
                 + "</notification-policy>";
-        when(mUserMangerService.isManagedProfile(10)).thenReturn(false);
+        when(mUm.isManagedProfile(10)).thenReturn(false);
         mService.readPolicyXml(
                 new BufferedInputStream(new ByteArrayInputStream(policyXml.getBytes())),
                 true,
@@ -4290,6 +4292,137 @@
                 .onGranted(eq(xmlConfig), eq(0), eq(true));
     }
 
+    @Test
+    public void testFlagBubbleNotifs_flagIfAllowed() throws RemoteException {
+        // Bubbles are allowed!
+        mService.setPreferencesHelper(mPreferencesHelper);
+        when(mPreferencesHelper.areBubblesAllowed(anyString(), anyInt())).thenReturn(true);
+        when(mPreferencesHelper.getNotificationChannel(
+                anyString(), anyInt(), anyString(), anyBoolean())).thenReturn(
+                mTestNotificationChannel);
+        when(mPreferencesHelper.getImportance(anyString(), anyInt())).thenReturn(
+                mTestNotificationChannel.getImportance());
+
+        // Notif with bubble metadata
+        Notification.BubbleMetadata data = getBasicBubbleMetadataBuilder().build();
+        Notification.Builder nb = new Notification.Builder(mContext,
+                mTestNotificationChannel.getId())
+                .setContentTitle("foo")
+                .setBubbleMetadata(data)
+                .setSmallIcon(android.R.drawable.sym_def_app_icon);
+
+        StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, null, mUid, 0,
+                nb.build(), new UserHandle(mUid), null, 0);
+        NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
+
+        mBinderService.enqueueNotificationWithTag(PKG, PKG, null,
+                nr.sbn.getId(), nr.sbn.getNotification(), nr.sbn.getUserId());
+        waitForIdle();
+
+        // yes allowed, yes bubble
+        assertTrue(mService.getNotificationRecord(
+                sbn.getKey()).getNotification().isBubbleNotification());
+    }
+
+    @Test
+    public void testFlagBubbleNotifs_noFlagIfNotAllowed() throws RemoteException {
+        // Bubbles are NOT allowed!
+        mService.setPreferencesHelper(mPreferencesHelper);
+        when(mPreferencesHelper.areBubblesAllowed(anyString(), anyInt())).thenReturn(false);
+        when(mPreferencesHelper.getNotificationChannel(
+                anyString(), anyInt(), anyString(), anyBoolean())).thenReturn(
+                mTestNotificationChannel);
+        when(mPreferencesHelper.getImportance(anyString(), anyInt())).thenReturn(
+                mTestNotificationChannel.getImportance());
+
+        // Notif with bubble metadata
+        Notification.BubbleMetadata data = getBasicBubbleMetadataBuilder().build();
+        Notification.Builder nb = new Notification.Builder(mContext,
+                mTestNotificationChannel.getId())
+                .setContentTitle("foo")
+                .setBubbleMetadata(data)
+                .setSmallIcon(android.R.drawable.sym_def_app_icon);
+
+        StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, null, mUid, 0,
+                nb.build(), new UserHandle(mUid), null, 0);
+        NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
+
+        // Post the notification
+        mBinderService.enqueueNotificationWithTag(PKG, PKG, null,
+                nr.sbn.getId(), nr.sbn.getNotification(), nr.sbn.getUserId());
+        waitForIdle();
+
+        // not allowed, no bubble
+        assertFalse(mService.getNotificationRecord(
+                sbn.getKey()).getNotification().isBubbleNotification());
+    }
+
+    @Test
+    public void testFlagBubbleNotifs_noFlagIfNotBubble() throws RemoteException {
+        // Bubbles are allowed!
+        mService.setPreferencesHelper(mPreferencesHelper);
+        when(mPreferencesHelper.areBubblesAllowed(anyString(), anyInt())).thenReturn(true);
+        when(mPreferencesHelper.getNotificationChannel(
+                anyString(), anyInt(), anyString(), anyBoolean())).thenReturn(
+                mTestNotificationChannel);
+        when(mPreferencesHelper.getImportance(anyString(), anyInt())).thenReturn(
+                mTestNotificationChannel.getImportance());
+
+        // Notif WITHOUT bubble metadata
+        Notification.Builder nb = new Notification.Builder(mContext,
+                mTestNotificationChannel.getId())
+                .setContentTitle("foo")
+                .setSmallIcon(android.R.drawable.sym_def_app_icon);
+
+        StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, null, mUid, 0,
+                nb.build(), new UserHandle(mUid), null, 0);
+        NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
+
+        // Post the notification
+        mBinderService.enqueueNotificationWithTag(PKG, PKG, null,
+                nr.sbn.getId(), nr.sbn.getNotification(), nr.sbn.getUserId());
+        waitForIdle();
+
+        // no bubble metadata, no bubble
+        assertFalse(mService.getNotificationRecord(
+                sbn.getKey()).getNotification().isBubbleNotification());
+    }
+
+    @Test
+    public void testFlagBubbleNotifs_noFlagIfChannelNotBubble() throws RemoteException {
+        // Bubbles are allowed!
+        mService.setPreferencesHelper(mPreferencesHelper);
+        when(mPreferencesHelper.areBubblesAllowed(anyString(), anyInt())).thenReturn(true);
+        when(mPreferencesHelper.getNotificationChannel(
+                anyString(), anyInt(), anyString(), anyBoolean())).thenReturn(
+                mTestNotificationChannel);
+        when(mPreferencesHelper.getImportance(anyString(), anyInt())).thenReturn(
+                mTestNotificationChannel.getImportance());
+
+        // But not on this channel!
+        mTestNotificationChannel.setAllowBubbles(false);
+
+        // Notif with bubble metadata
+        Notification.BubbleMetadata data = getBasicBubbleMetadataBuilder().build();
+        Notification.Builder nb = new Notification.Builder(mContext,
+                mTestNotificationChannel.getId())
+                .setContentTitle("foo")
+                .setBubbleMetadata(data)
+                .setSmallIcon(android.R.drawable.sym_def_app_icon);
+
+        StatusBarNotification sbn = new StatusBarNotification(PKG, PKG, 1, null, mUid, 0,
+                nb.build(), new UserHandle(mUid), null, 0);
+        NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel);
+
+        // Post the notification
+        mBinderService.enqueueNotificationWithTag(PKG, PKG, null,
+                nr.sbn.getId(), nr.sbn.getNotification(), nr.sbn.getUserId());
+        waitForIdle();
+
+        // channel not allowed, no bubble
+        assertFalse(mService.getNotificationRecord(
+                sbn.getKey()).getNotification().isBubbleNotification());
+    }
 
 
     public void testGetAllowedAssistantCapabilities() throws Exception {
@@ -4324,4 +4457,36 @@
         assertEquals(IMPORTANCE_LOW, r.getAssistantImportance());
         assertEquals(USER_SENTIMENT_NEUTRAL, r.getUserSentiment());
     }
+
+    public void testAreNotificationsEnabledForPackage_crossUser() throws Exception {
+        try {
+            mBinderService.areNotificationsEnabledForPackage(mContext.getPackageName(),
+                    mUid + UserHandle.PER_USER_RANGE);
+            fail("Cannot call cross user without permission");
+        } catch (SecurityException e) {
+            // pass
+        }
+
+        // cross user, with permission, no problem
+        TestablePermissions perms = mContext.getTestablePermissions();
+        perms.setPermission(android.Manifest.permission.INTERACT_ACROSS_USERS, PERMISSION_GRANTED);
+        mBinderService.areNotificationsEnabledForPackage(mContext.getPackageName(),
+                mUid + UserHandle.PER_USER_RANGE);
+    }
+
+    public void testAreBubblesAllowedForPackage_crossUser() throws Exception {
+        try {
+            mBinderService.areBubblesAllowedForPackage(mContext.getPackageName(),
+                    mUid + UserHandle.PER_USER_RANGE);
+            fail("Cannot call cross user without permission");
+        } catch (SecurityException e) {
+            // pass
+        }
+
+        // cross user, with permission, no problem
+        TestablePermissions perms = mContext.getTestablePermissions();
+        perms.setPermission(android.Manifest.permission.INTERACT_ACROSS_USERS, PERMISSION_GRANTED);
+        mBinderService.areBubblesAllowedForPackage(mContext.getPackageName(),
+                mUid + UserHandle.PER_USER_RANGE);
+    }
 }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
index e375195..ee09c7e 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
@@ -952,7 +952,31 @@
     }
 
     @Test
-    public void testApplyImportanceAdjustmentsForNonOemLockedChannels() {
+    public void testIgnoreImportanceAdjustmentsForDefaultAppLockedChannels() {
+        NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_DEFAULT);
+        channel.setImportanceLockedByCriticalDeviceFunction(true);
+
+        StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
+                true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
+                false /* lights */, false /* defaultLights */, groupId /* group */);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+
+        assertEquals(IMPORTANCE_DEFAULT, record.getImportance());
+
+        Bundle bundle = new Bundle();
+        bundle.putInt(KEY_IMPORTANCE, IMPORTANCE_LOW);
+        Adjustment adjustment = new Adjustment(
+                PKG_O, record.getKey(), bundle, "", record.getUserId());
+
+        record.addAdjustment(adjustment);
+        record.applyAdjustments();
+        record.calculateImportance();
+
+        assertEquals(IMPORTANCE_DEFAULT, record.getImportance());
+    }
+
+    @Test
+    public void testApplyImportanceAdjustmentsForNonOemDefaultAppLockedChannels() {
         NotificationChannel channel = new NotificationChannel("a", "a", IMPORTANCE_DEFAULT);
         channel.setImportanceLockedByOEM(false);
 
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index 39e47ec..87f10a4 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -62,11 +62,9 @@
 import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.TestableContentResolver;
 import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.Xml;
 
-import androidx.test.InstrumentationRegistry;
-import androidx.test.runner.AndroidJUnit4;
-
 import com.android.internal.util.FastXmlSerializer;
 import com.android.server.UiServiceTestCase;
 
@@ -91,6 +89,9 @@
 import java.util.Objects;
 import java.util.concurrent.ThreadLocalRandom;
 
+import androidx.test.InstrumentationRegistry;
+import androidx.test.runner.AndroidJUnit4;
+
 @SmallTest
 @RunWith(AndroidJUnit4.class)
 public class PreferencesHelperTest extends UiServiceTestCase {
@@ -2442,4 +2443,153 @@
         assertEquals(IMPORTANCE_HIGH,
                 mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).getImportance());
     }
+
+    @Test
+    public void testUpdateDefaultApps_add_multiUser() {
+        NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
+        NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW);
+        NotificationChannel c = new NotificationChannel("c", "c", IMPORTANCE_DEFAULT);
+        // different uids, same package
+        mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false);
+        mHelper.createNotificationChannel(PKG_O, UID_O, b, false, false);
+        mHelper.createNotificationChannel(PKG_O, UserHandle.PER_USER_RANGE + 1, c, true, true);
+
+        ArraySet<String> toAdd = new ArraySet<>();
+        toAdd.add(PKG_O);
+        mHelper.updateDefaultApps(UserHandle.getUserId(UID_O), null, toAdd);
+
+        assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false)
+                .isImportanceLockedByCriticalDeviceFunction());
+        assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, b.getId(), false)
+                .isImportanceLockedByCriticalDeviceFunction());
+        assertFalse(mHelper.getNotificationChannel(
+                PKG_O, UserHandle.PER_USER_RANGE + 1, c.getId(), false)
+                .isImportanceLockedByCriticalDeviceFunction());
+    }
+
+    @Test
+    public void testUpdateDefaultApps_add_onlyGivenPkg() {
+        NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
+        NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW);
+        mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false);
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, b, false, false);
+
+        ArraySet<String> toAdd = new ArraySet<>();
+        toAdd.add(PKG_O);
+        mHelper.updateDefaultApps(UserHandle.getUserId(UID_O), null, toAdd);
+
+
+        assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false)
+                .isImportanceLockedByCriticalDeviceFunction());
+        assertFalse(mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, b.getId(), false)
+                .isImportanceLockedByCriticalDeviceFunction());
+    }
+
+    @Test
+    public void testUpdateDefaultApps_remove() {
+        NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
+        NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW);
+        // different uids, same package
+        mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false);
+        mHelper.createNotificationChannel(PKG_O, UID_O, b, false, false);
+
+        ArraySet<String> toAdd = new ArraySet<>();
+        toAdd.add(PKG_O);
+        mHelper.updateDefaultApps(UserHandle.getUserId(UID_O), null, toAdd);
+
+        assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false)
+                .isImportanceLockedByCriticalDeviceFunction());
+        assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, b.getId(), false)
+                .isImportanceLockedByCriticalDeviceFunction());
+
+        ArraySet<String> toRemove = new ArraySet<>();
+        toRemove.add(PKG_O);
+        mHelper.updateDefaultApps(UserHandle.getUserId(UID_O), toRemove, null);
+
+        assertFalse(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false)
+                .isImportanceLockedByCriticalDeviceFunction());
+        assertFalse(mHelper.getNotificationChannel(PKG_O, UID_O, b.getId(), false)
+                .isImportanceLockedByCriticalDeviceFunction());
+    }
+
+    @Test
+    public void testUpdateDefaultApps_addAndRemove() {
+        NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
+        NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW);
+        mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false);
+        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, b, false, false);
+
+        ArraySet<String> toAdd = new ArraySet<>();
+        toAdd.add(PKG_O);
+        mHelper.updateDefaultApps(UserHandle.getUserId(UID_O), null, toAdd);
+
+
+        assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false)
+                .isImportanceLockedByCriticalDeviceFunction());
+        assertFalse(mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, b.getId(), false)
+                .isImportanceLockedByCriticalDeviceFunction());
+
+        // now the default is PKG_N_MR1
+        ArraySet<String> toRemove = new ArraySet<>();
+        toRemove.add(PKG_O);
+        toAdd = new ArraySet<>();
+        toAdd.add(PKG_N_MR1);
+        mHelper.updateDefaultApps(USER.getIdentifier(), toRemove, toAdd);
+
+        assertFalse(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false)
+                .isImportanceLockedByCriticalDeviceFunction());
+        assertTrue(mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, b.getId(), false)
+                .isImportanceLockedByCriticalDeviceFunction());
+    }
+
+    @Test
+    public void testUpdateDefaultApps_appDoesNotExist_noCrash() {
+        ArraySet<String> toAdd = new ArraySet<>();
+        toAdd.add(PKG_O);
+        ArraySet<String> toRemove = new ArraySet<>();
+        toRemove.add(PKG_N_MR1);
+        mHelper.updateDefaultApps(UserHandle.getUserId(UID_O), toRemove, toAdd);
+    }
+
+    @Test
+    public void testUpdateDefaultApps_channelDoesNotExistYet() {
+        NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
+        NotificationChannel b = new NotificationChannel("b", "b", IMPORTANCE_LOW);
+        mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false);
+
+        ArraySet<String> toAdd = new ArraySet<>();
+        toAdd.add(PKG_O);
+        mHelper.updateDefaultApps(UserHandle.getUserId(UID_O), null, toAdd);
+
+        assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false)
+                .isImportanceLockedByCriticalDeviceFunction());
+
+        mHelper.createNotificationChannel(PKG_O, UID_O, b, true, false);
+        assertTrue(mHelper.getNotificationChannel(PKG_O, UID_O, b.getId(), false)
+                .isImportanceLockedByCriticalDeviceFunction());
+    }
+
+    @Test
+    public void testUpdateNotificationChannel_defaultAppLockedImportance() {
+        NotificationChannel a = new NotificationChannel("a", "a", IMPORTANCE_HIGH);
+        mHelper.createNotificationChannel(PKG_O, UID_O, a, true, false);
+        ArraySet<String> toAdd = new ArraySet<>();
+        toAdd.add(PKG_O);
+        mHelper.updateDefaultApps(UserHandle.getUserId(UID_O), null, toAdd);
+
+        NotificationChannel update = new NotificationChannel("a", "a", IMPORTANCE_NONE);
+        update.setAllowBubbles(false);
+
+        mHelper.updateNotificationChannel(PKG_O, UID_O, update, true);
+
+        assertEquals(IMPORTANCE_HIGH,
+                mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).getImportance());
+        assertEquals(false,
+                mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).canBubble());
+
+        mHelper.updateNotificationChannel(PKG_O, UID_O, update, false);
+
+        assertEquals(IMPORTANCE_HIGH,
+                mHelper.getNotificationChannel(PKG_O, UID_O, a.getId(), false).getImportance());
+    }
 }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
new file mode 100644
index 0000000..91d3e5e
--- /dev/null
+++ b/services/tests/uiservicestests/src/com/android/server/notification/RoleObserverTest.java
@@ -0,0 +1,391 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.notification;
+
+import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
+import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_GONE;
+import static android.app.Notification.FLAG_FOREGROUND_SERVICE;
+import static android.app.NotificationManager.EXTRA_BLOCKED_STATE;
+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_MAX;
+import static android.app.NotificationManager.IMPORTANCE_NONE;
+import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_OFF;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON;
+import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_STATUS_BAR;
+import static android.app.role.RoleManager.ROLE_DIALER;
+import static android.app.role.RoleManager.ROLE_EMERGENCY;
+import static android.app.role.RoleManager.ROLE_SMS;
+import static android.content.pm.PackageManager.FEATURE_WATCH;
+import static android.content.pm.PackageManager.PERMISSION_DENIED;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.os.Build.VERSION_CODES.O_MR1;
+import static android.os.Build.VERSION_CODES.P;
+import static android.service.notification.Adjustment.KEY_IMPORTANCE;
+import static android.service.notification.Adjustment.KEY_USER_SENTIMENT;
+import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEGATIVE;
+import static android.service.notification.NotificationListenerService.Ranking.USER_SENTIMENT_NEUTRAL;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNotNull;
+import static junit.framework.Assert.assertNull;
+import static junit.framework.Assert.assertTrue;
+import static junit.framework.Assert.fail;
+
+import static org.mockito.Matchers.anyBoolean;
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.anyInt;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.timeout;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.ActivityManager;
+import android.app.AppOpsManager;
+import android.app.IActivityManager;
+import android.app.INotificationManager;
+import android.app.ITransientNotification;
+import android.app.IUriGrantsManager;
+import android.app.Notification;
+import android.app.Notification.MessagingStyle.Message;
+import android.app.NotificationChannel;
+import android.app.NotificationChannelGroup;
+import android.app.NotificationManager;
+import android.app.admin.DevicePolicyManagerInternal;
+import android.app.role.RoleManager;
+import android.app.usage.UsageStatsManagerInternal;
+import android.companion.ICompanionDeviceManager;
+import android.content.ComponentName;
+import android.content.ContentUris;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageManager;
+import android.content.pm.ParceledListSlice;
+import android.content.pm.UserInfo;
+import android.graphics.Color;
+import android.media.AudioManager;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.provider.DeviceConfig;
+import android.provider.MediaStore;
+import android.provider.Settings;
+import android.service.notification.Adjustment;
+import android.service.notification.NotificationListenerService;
+import android.service.notification.NotificationStats;
+import android.service.notification.NotifyingApp;
+import android.service.notification.StatusBarNotification;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableContext;
+import android.testing.TestableLooper;
+import android.testing.TestableLooper.RunWithLooper;
+import android.testing.TestablePermissions;
+import android.text.Html;
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.AtomicFile;
+
+import com.android.internal.R;
+import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
+import com.android.internal.statusbar.NotificationVisibility;
+import com.android.server.LocalServices;
+import com.android.server.UiServiceTestCase;
+import com.android.server.lights.Light;
+import com.android.server.lights.LightsManager;
+import com.android.server.notification.NotificationManagerService.NotificationAssistants;
+import com.android.server.notification.NotificationManagerService.NotificationListeners;
+import com.android.server.uri.UriGrantsManagerInternal;
+import com.android.server.wm.WindowManagerInternal;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.mockito.stubbing.Answer;
+
+import java.io.BufferedInputStream;
+import java.io.ByteArrayInputStream;
+import java.io.FileInputStream;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.Executor;
+import java.util.function.Consumer;
+
+import androidx.annotation.Nullable;
+import androidx.test.InstrumentationRegistry;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+public class RoleObserverTest extends UiServiceTestCase {
+    private TestableNotificationManagerService mService;
+    private NotificationManagerService.RoleObserver mRoleObserver;
+
+    private TestableContext mContext = spy(getContext());
+
+    @Mock
+    private PreferencesHelper mPreferencesHelper;
+    @Mock
+    private UserManager mUm;
+    @Mock
+    private Executor mExecutor;
+    @Mock
+    private RoleManager mRoleManager;
+
+    private List<UserInfo> mUsers;
+
+    private static class TestableNotificationManagerService extends NotificationManagerService {
+
+        TestableNotificationManagerService(Context context) {
+            super(context);
+        }
+
+        @Override
+        protected void handleSavePolicyFile() {
+            return;
+        }
+
+        @Override
+        protected void loadPolicyFile() {
+            return;
+        }
+    }
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        LocalServices.removeServiceForTest(WindowManagerInternal.class);
+        LocalServices.addService(WindowManagerInternal.class, mock(WindowManagerInternal.class));
+
+        mUsers = new ArrayList<>();
+        mUsers.add(new UserInfo(0, "system", 0));
+        mUsers.add(new UserInfo(10, "second", 0));
+        when(mUm.getUsers()).thenReturn(mUsers);
+
+        mService = new TestableNotificationManagerService(mContext);
+        mRoleObserver = mService.new RoleObserver(mRoleManager, mExecutor);
+
+        try {
+            mService.init(mock(Looper.class),
+                    mock(IPackageManager.class), mock(PackageManager.class),
+                    mock(LightsManager.class),
+                    mock(NotificationListeners.class), mock(NotificationAssistants.class),
+                    mock(ConditionProviders.class), mock(ICompanionDeviceManager.class),
+                    mock(SnoozeHelper.class), mock(NotificationUsageStats.class),
+                    mock(AtomicFile.class), mock(ActivityManager.class),
+                    mock(GroupHelper.class), mock(IActivityManager.class),
+                    mock(UsageStatsManagerInternal.class),
+                    mock(DevicePolicyManagerInternal.class), mock(IUriGrantsManager.class),
+                    mock(UriGrantsManagerInternal.class),
+                    mock(AppOpsManager.class), mUm);
+        } catch (SecurityException e) {
+            if (!e.getMessage().contains("Permission Denial: not allowed to send broadcast")) {
+                throw e;
+            }
+        }
+        mService.setPreferencesHelper(mPreferencesHelper);
+    }
+
+    @Test
+    public void testInit() {
+        List<String> dialer0 = new ArrayList<>();
+        dialer0.add("dialer");
+        List<String> emer0 = new ArrayList<>();
+        emer0.add("emergency");
+        List<String> sms10 = new ArrayList<>();
+        sms10.add("sms");
+        when(mRoleManager.getRoleHoldersAsUser(
+                ROLE_DIALER,
+                mUsers.get(0).getUserHandle())).
+                thenReturn(dialer0);
+        when(mRoleManager.getRoleHoldersAsUser(
+                ROLE_EMERGENCY,
+                mUsers.get(0).getUserHandle())).
+                thenReturn(emer0);
+        when(mRoleManager.getRoleHoldersAsUser(
+                ROLE_SMS,
+                mUsers.get(1).getUserHandle())).
+                thenReturn(sms10);
+
+        mRoleObserver.init();
+
+        // verify internal records of current state of the world
+        assertTrue(mRoleObserver.isApprovedPackageForRoleForUser(
+                ROLE_DIALER, dialer0.get(0), mUsers.get(0).id));
+        assertFalse(mRoleObserver.isApprovedPackageForRoleForUser(
+                ROLE_DIALER, dialer0.get(0), mUsers.get(1).id));
+        assertFalse(mRoleObserver.isApprovedPackageForRoleForUser(
+                ROLE_SMS, dialer0.get(0), mUsers.get(1).id));
+
+        assertTrue(mRoleObserver.isApprovedPackageForRoleForUser(
+                ROLE_EMERGENCY, emer0.get(0), mUsers.get(0).id));
+        assertFalse(mRoleObserver.isApprovedPackageForRoleForUser(
+                ROLE_EMERGENCY, emer0.get(0), mUsers.get(1).id));
+
+        assertFalse(mRoleObserver.isApprovedPackageForRoleForUser(
+                ROLE_SMS, sms10.get(0), mUsers.get(0).id));
+        assertFalse(mRoleObserver.isApprovedPackageForRoleForUser(
+                ROLE_DIALER, sms10.get(0), mUsers.get(0).id));
+        assertTrue(mRoleObserver.isApprovedPackageForRoleForUser(
+                ROLE_SMS, sms10.get(0), mUsers.get(1).id));
+
+        // make sure we're listening to updates
+        verify(mRoleManager, times(1)).addOnRoleHoldersChangedListenerAsUser(
+                eq(mExecutor), any(), eq(UserHandle.ALL));
+
+        // make sure we told pref helper about the state of the world
+        verify(mPreferencesHelper, times(1)).updateDefaultApps(0, null, new ArraySet<>(dialer0));
+        verify(mPreferencesHelper, times(1)).updateDefaultApps(0, null, new ArraySet<>(emer0));
+        verify(mPreferencesHelper, times(1)).updateDefaultApps(10, null, new ArraySet<>(sms10));
+    }
+
+    @Test
+    public void testSwapDefault() {
+        List<String> dialer0 = new ArrayList<>();
+        dialer0.add("dialer");
+
+        when(mRoleManager.getRoleHoldersAsUser(
+                ROLE_DIALER,
+                mUsers.get(0).getUserHandle())).
+                thenReturn(dialer0);
+
+        mRoleObserver.init();
+
+        List<String> newDefault = new ArrayList<>();
+        newDefault.add("phone");
+
+        when(mRoleManager.getRoleHoldersAsUser(
+                ROLE_DIALER,
+                mUsers.get(0).getUserHandle())).
+                thenReturn(newDefault);
+
+        mRoleObserver.onRoleHoldersChanged(ROLE_DIALER, UserHandle.of(0));
+
+        verify(mPreferencesHelper, times(1)).updateDefaultApps(
+                0, new ArraySet<>(dialer0), new ArraySet<>(newDefault));
+    }
+
+    @Test
+    public void testSwapDefault_multipleOverlappingApps() {
+        List<String> dialer0 = new ArrayList<>();
+        dialer0.add("dialer");
+        dialer0.add("phone");
+
+        when(mRoleManager.getRoleHoldersAsUser(
+                ROLE_DIALER,
+                mUsers.get(0).getUserHandle())).
+                thenReturn(dialer0);
+
+        mRoleObserver.init();
+
+        assertTrue(mRoleObserver.isApprovedPackageForRoleForUser(ROLE_DIALER, "phone", 0));
+        assertFalse(mRoleObserver.isApprovedPackageForRoleForUser(ROLE_DIALER, "emerPhone", 0));
+        assertTrue(mRoleObserver.isApprovedPackageForRoleForUser(ROLE_DIALER, "dialer", 0));
+
+        List<String> newDefault = new ArrayList<>();
+        newDefault.add("phone");
+        newDefault.add("emerPhone");
+
+        when(mRoleManager.getRoleHoldersAsUser(
+                ROLE_DIALER,
+                mUsers.get(0).getUserHandle())).
+                thenReturn(newDefault);
+
+        mRoleObserver.onRoleHoldersChanged(ROLE_DIALER, UserHandle.of(0));
+
+        ArraySet<String> expectedRemove = new ArraySet<>();
+        expectedRemove.add("dialer");
+        ArraySet<String> expectedAdd = new ArraySet<>();
+        expectedAdd.add("emerPhone");
+
+        verify(mPreferencesHelper, times(1)).updateDefaultApps(
+                0, expectedRemove, expectedAdd);
+
+        assertTrue(mRoleObserver.isApprovedPackageForRoleForUser(ROLE_DIALER, "phone", 0));
+        assertTrue(mRoleObserver.isApprovedPackageForRoleForUser(ROLE_DIALER, "emerPhone", 0));
+        assertFalse(mRoleObserver.isApprovedPackageForRoleForUser(ROLE_DIALER, "dialer", 0));
+    }
+
+    @Test
+    public void testSwapDefault_newUser() {
+        List<String> dialer0 = new ArrayList<>();
+        dialer0.add("dialer");
+
+        when(mRoleManager.getRoleHoldersAsUser(
+                ROLE_DIALER,
+                mUsers.get(0).getUserHandle())).
+                thenReturn(dialer0);
+
+        mRoleObserver.init();
+
+        List<String> dialer10 = new ArrayList<>();
+        dialer10.add("phone");
+
+        when(mRoleManager.getRoleHoldersAsUser(
+                ROLE_DIALER,
+                mUsers.get(1).getUserHandle())).
+                thenReturn(dialer10);
+
+        mRoleObserver.onRoleHoldersChanged(ROLE_DIALER, UserHandle.of(10));
+
+        ArraySet<String> expectedRemove = new ArraySet<>();
+        ArraySet<String> expectedAdd = new ArraySet<>();
+        expectedAdd.add("phone");
+
+        verify(mPreferencesHelper, times(1)).updateDefaultApps(
+                10, expectedRemove, expectedAdd);
+
+        assertTrue(mRoleObserver.isApprovedPackageForRoleForUser(ROLE_DIALER, "phone", 10));
+        assertTrue(mRoleObserver.isApprovedPackageForRoleForUser(ROLE_DIALER, "dialer", 0));
+    }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
index 822700f..1e00b30 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackTests.java
@@ -31,6 +31,7 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
 import static com.android.server.wm.ActivityStack.ActivityState.DESTROYING;
+import static com.android.server.wm.ActivityStack.ActivityState.FINISHING;
 import static com.android.server.wm.ActivityStack.ActivityState.PAUSED;
 import static com.android.server.wm.ActivityStack.ActivityState.PAUSING;
 import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
@@ -929,6 +930,16 @@
     }
 
     @Test
+    public void testWontFinishHomeStackImmediately() {
+        final ActivityStack homeStack = createStackForShouldBeVisibleTest(mDefaultDisplay,
+                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, true /* onTop */);
+
+        // Home stack should not be destroyed immediately.
+        final ActivityRecord activity1 = finishCurrentActivity(homeStack);
+        assertEquals(FINISHING, activity1.getState());
+    }
+
+    @Test
     public void testFinishCurrentActivity() {
         // Create 2 activities on a new display.
         final ActivityDisplay display = addNewActivityDisplayAt(ActivityDisplay.POSITION_TOP);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java
index 85b2f7b..2ab48a9 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTestsBase.java
@@ -86,7 +86,6 @@
                 Math.min(DISPLAY_WIDTH, DISPLAY_HEIGHT) * DENSITY_DEFAULT / DISPLAY_DENSITY;
         mDisplayContent.getDisplayRotation().configure(
                 DISPLAY_WIDTH, DISPLAY_HEIGHT, shortSizeDp, longSizeDp);
-        mDisplayPolicy.configure(DISPLAY_WIDTH, DISPLAY_HEIGHT, shortSizeDp);
         mDisplayPolicy.onConfigurationChanged();
 
         mStatusBarWindow.mAttrs.gravity = Gravity.TOP;
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
index 9a8a732..652ea7d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
@@ -16,6 +16,8 @@
 
 package com.android.server.wm;
 
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.view.WindowManager.REMOVE_CONTENT_MODE_DESTROY;
 import static android.view.WindowManager.REMOVE_CONTENT_MODE_MOVE_TO_PRIMARY;
 
@@ -40,7 +42,9 @@
 
 import android.app.WindowConfiguration;
 import android.platform.test.annotations.Presubmit;
+import android.util.Xml;
 import android.view.Display;
+import android.view.DisplayAddress;
 import android.view.DisplayInfo;
 import android.view.Surface;
 
@@ -53,14 +57,22 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.MockitoSession;
+import org.xmlpull.v1.XmlPullParser;
 
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
 import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.charset.StandardCharsets;
 
 /**
  * Tests for the {@link DisplayWindowSettings} class.
  *
  * Build/Install/Run:
- *  atest FrameworksServicesTests:DisplayWindowSettingsTests
+ *  atest WmTests:DisplayWindowSettingsTests
  */
 @SmallTest
 @Presubmit
@@ -69,12 +81,14 @@
     private static final File TEST_FOLDER = getInstrumentation().getTargetContext().getCacheDir();
     private DisplayWindowSettings mTarget;
 
-    DisplayInfo mPrivateDisplayInfo;
+    private DisplayInfo mPrivateDisplayInfo;
 
     private DisplayContent mPrimaryDisplay;
     private DisplayContent mSecondaryDisplay;
     private DisplayContent mPrivateDisplay;
 
+    private TestStorage mStorage;
+
     @Before
     public void setUp() throws Exception {
         deleteRecursively(TEST_FOLDER);
@@ -83,7 +97,8 @@
         mWm.setIsPc(false);
         mWm.setForceDesktopModeOnExternalDisplays(false);
 
-        mTarget = new DisplayWindowSettings(mWm, TEST_FOLDER);
+        mStorage = new TestStorage();
+        mTarget = new DisplayWindowSettings(mWm, mStorage);
 
         mPrimaryDisplay = mWm.getDefaultDisplayContentLocked();
         mSecondaryDisplay = mDisplayContent;
@@ -143,7 +158,7 @@
 
         mTarget.applySettingsToDisplayLocked(mPrimaryDisplay);
 
-        assertEquals(WindowConfiguration.WINDOWING_MODE_FREEFORM,
+        assertEquals(WINDOWING_MODE_FREEFORM,
                 mPrimaryDisplay.getWindowingMode());
     }
 
@@ -185,7 +200,7 @@
 
         mTarget.applySettingsToDisplayLocked(mSecondaryDisplay);
 
-        assertEquals(WindowConfiguration.WINDOWING_MODE_FREEFORM,
+        assertEquals(WINDOWING_MODE_FREEFORM,
                 mSecondaryDisplay.getWindowingMode());
     }
 
@@ -196,7 +211,7 @@
 
         mTarget.applySettingsToDisplayLocked(mSecondaryDisplay);
 
-        assertEquals(WindowConfiguration.WINDOWING_MODE_FREEFORM,
+        assertEquals(WINDOWING_MODE_FREEFORM,
                 mSecondaryDisplay.getWindowingMode());
     }
 
@@ -474,6 +489,171 @@
         mockitoSession.finishMocking();
     }
 
+    @Test
+    public void testReadingDisplaySettingsFromStorage() {
+        final String displayIdentifier = mSecondaryDisplay.getDisplayInfo().uniqueId;
+        prepareDisplaySettings(displayIdentifier);
+
+        readAndAssertDisplaySettings(mPrimaryDisplay);
+    }
+
+    @Test
+    public void testReadingDisplaySettingsFromStorage_LegacyDisplayId() {
+        final String displayIdentifier = mPrimaryDisplay.getDisplayInfo().name;
+        prepareDisplaySettings(displayIdentifier);
+
+        readAndAssertDisplaySettings(mPrimaryDisplay);
+    }
+
+    @Test
+    public void testReadingDisplaySettingsFromStorage_LegacyDisplayId_UpdateAfterAccess()
+            throws Exception {
+        // Store display settings with legacy display identifier.
+        final String displayIdentifier = mPrimaryDisplay.getDisplayInfo().name;
+        prepareDisplaySettings(displayIdentifier);
+
+        // Update settings with new value, should trigger write to injector.
+        final DisplayWindowSettings settings = new DisplayWindowSettings(mWm, mStorage);
+        settings.setRemoveContentModeLocked(mPrimaryDisplay, REMOVE_CONTENT_MODE_MOVE_TO_PRIMARY);
+        assertEquals("Settings value must be updated", REMOVE_CONTENT_MODE_MOVE_TO_PRIMARY,
+                settings.getRemoveContentModeLocked(mPrimaryDisplay));
+        assertTrue(mStorage.wasWriteSuccessful());
+
+        // Verify that display identifier was updated.
+        final String newDisplayIdentifier = getStoredDisplayAttributeValue("name");
+        assertEquals("Display identifier must be updated to use uniqueId",
+                mPrimaryDisplay.getDisplayInfo().uniqueId, newDisplayIdentifier);
+    }
+
+    @Test
+    public void testReadingDisplaySettingsFromStorage_UsePortAsId() {
+        final DisplayAddress.Physical displayAddress = DisplayAddress.fromPhysicalDisplayId(123456);
+        mPrimaryDisplay.getDisplayInfo().address = displayAddress;
+
+        final String displayIdentifier = "port:" + displayAddress.getPort();
+        prepareDisplaySettings(displayIdentifier, true /* usePortAsId */);
+
+        readAndAssertDisplaySettings(mPrimaryDisplay);
+    }
+
+    @Test
+    public void testReadingDisplaySettingsFromStorage_UsePortAsId_IncorrectAddress() {
+        final String displayIdentifier = mPrimaryDisplay.getDisplayInfo().uniqueId;
+        prepareDisplaySettings(displayIdentifier, true /* usePortAsId */);
+
+        mPrimaryDisplay.getDisplayInfo().address = DisplayAddress.fromPhysicalDisplayId(123456);
+
+        // Verify that the entry is not matched and default settings are returned instead.
+        final DisplayWindowSettings settings = new DisplayWindowSettings(mWm);
+        assertNotEquals("Default setting must be returned for new entry",
+                WINDOWING_MODE_PINNED, settings.getWindowingModeLocked(mPrimaryDisplay));
+    }
+
+    @Test
+    public void testWritingDisplaySettingsToStorage() throws Exception {
+        // Write some settings to storage.
+        final DisplayWindowSettings settings = new DisplayWindowSettings(mWm, mStorage);
+        settings.setShouldShowSystemDecorsLocked(mSecondaryDisplay, true);
+        settings.setShouldShowImeLocked(mSecondaryDisplay, true);
+        assertTrue(mStorage.wasWriteSuccessful());
+
+        // Verify that settings were stored correctly.
+        assertEquals("Attribute value must be stored", mSecondaryDisplay.getDisplayInfo().uniqueId,
+                getStoredDisplayAttributeValue("name"));
+        assertEquals("Attribute value must be stored", "true",
+                getStoredDisplayAttributeValue("shouldShowSystemDecors"));
+        assertEquals("Attribute value must be stored", "true",
+                getStoredDisplayAttributeValue("shouldShowIme"));
+    }
+
+    @Test
+    public void testWritingDisplaySettingsToStorage_UsePortAsId() throws Exception {
+        // Store config to use port as identifier.
+        final DisplayAddress.Physical displayAddress = DisplayAddress.fromPhysicalDisplayId(123456);
+        mSecondaryDisplay.getDisplayInfo().address = displayAddress;
+        prepareDisplaySettings(null /* displayIdentifier */, true /* usePortAsId */);
+
+        // Write some settings.
+        final DisplayWindowSettings settings = new DisplayWindowSettings(mWm, mStorage);
+        settings.setShouldShowSystemDecorsLocked(mSecondaryDisplay, true);
+        settings.setShouldShowImeLocked(mSecondaryDisplay, true);
+        assertTrue(mStorage.wasWriteSuccessful());
+
+        // Verify that settings were stored correctly.
+        assertEquals("Attribute value must be stored", "port:" + displayAddress.getPort(),
+                getStoredDisplayAttributeValue("name"));
+        assertEquals("Attribute value must be stored", "true",
+                getStoredDisplayAttributeValue("shouldShowSystemDecors"));
+        assertEquals("Attribute value must be stored", "true",
+                getStoredDisplayAttributeValue("shouldShowIme"));
+    }
+
+    /**
+     * Prepares display settings and stores in {@link #mStorage}. Uses provided display identifier
+     * and stores windowingMode=WINDOWING_MODE_PINNED.
+     */
+    private void prepareDisplaySettings(String displayIdentifier) {
+        prepareDisplaySettings(displayIdentifier, false /* usePortAsId */);
+    }
+
+    private void prepareDisplaySettings(String displayIdentifier, boolean usePortAsId) {
+        String contents = "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n"
+                + "<display-settings>\n";
+        if (usePortAsId) {
+            contents += "  <config identifier=\"1\"/>\n";
+        }
+        if (displayIdentifier != null) {
+            contents += "  <display\n"
+                    + "    name=\"" + displayIdentifier + "\"\n"
+                    + "    windowingMode=\"" + WINDOWING_MODE_PINNED + "\"/>\n";
+        }
+        contents += "</display-settings>\n";
+
+        final InputStream is = new ByteArrayInputStream(contents.getBytes(StandardCharsets.UTF_8));
+        mStorage.setReadStream(is);
+    }
+
+    private void readAndAssertDisplaySettings(DisplayContent displayContent) {
+        final DisplayWindowSettings settings = new DisplayWindowSettings(mWm, mStorage);
+        assertEquals("Stored setting must be read",
+                WINDOWING_MODE_PINNED, settings.getWindowingModeLocked(displayContent));
+        assertEquals("Not stored setting must be set to default value",
+                REMOVE_CONTENT_MODE_MOVE_TO_PRIMARY,
+                settings.getRemoveContentModeLocked(displayContent));
+    }
+
+    private String getStoredDisplayAttributeValue(String attr) throws Exception {
+        try (InputStream stream = mStorage.openRead()) {
+            XmlPullParser parser = Xml.newPullParser();
+            parser.setInput(stream, StandardCharsets.UTF_8.name());
+            int type;
+            while ((type = parser.next()) != XmlPullParser.START_TAG
+                    && type != XmlPullParser.END_DOCUMENT) {
+                // Do nothing.
+            }
+
+            if (type != XmlPullParser.START_TAG) {
+                throw new IllegalStateException("no start tag found");
+            }
+
+            int outerDepth = parser.getDepth();
+            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+                    && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+                if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+                    continue;
+                }
+
+                String tagName = parser.getName();
+                if (tagName.equals("display")) {
+                    return parser.getAttributeValue(null, attr);
+                }
+            }
+        } finally {
+            mStorage.closeRead();
+        }
+        return null;
+    }
+
     private static void assertOverscan(DisplayContent display, int left, int top, int right,
             int bottom) {
         final DisplayInfo info = display.getDisplayInfo();
@@ -490,7 +670,11 @@
      * path that also means the previous state must be written correctly.
      */
     private void applySettingsToDisplayByNewInstance(DisplayContent display) {
-        new DisplayWindowSettings(mWm, TEST_FOLDER).applySettingsToDisplayLocked(display);
+        // Assert that prior write completed successfully.
+        assertTrue(mStorage.wasWriteSuccessful());
+
+        // Read and apply settings.
+        new DisplayWindowSettings(mWm, mStorage).applySettingsToDisplayLocked(display);
     }
 
     private static boolean deleteRecursively(File file) {
@@ -506,4 +690,81 @@
         }
         return fullyDeleted;
     }
+
+    /** In-memory storage implementation. */
+    public class TestStorage implements DisplayWindowSettings.SettingPersister {
+        private InputStream mReadStream;
+        private ByteArrayOutputStream mWriteStream;
+
+        private boolean mWasSuccessful;
+
+        /**
+         * Returns input stream for reading. By default tries forward the output stream if previous
+         * write was successful.
+         * @see #closeRead()
+         */
+        @Override
+        public InputStream openRead() throws FileNotFoundException {
+            if (mReadStream == null && mWasSuccessful) {
+                mReadStream = new ByteArrayInputStream(mWriteStream.toByteArray());
+            }
+            if (mReadStream == null) {
+                throw new FileNotFoundException();
+            }
+            if (mReadStream.markSupported()) {
+                mReadStream.mark(Integer.MAX_VALUE);
+            }
+            return mReadStream;
+        }
+
+        /** Must be called after each {@link #openRead} to reset the position in the stream. */
+        void closeRead() throws IOException {
+            if (mReadStream == null) {
+                throw new FileNotFoundException();
+            }
+            if (mReadStream.markSupported()) {
+                mReadStream.reset();
+            }
+            mReadStream = null;
+        }
+
+        /**
+         * Creates new or resets existing output stream for write. Automatically closes previous
+         * read stream, since following reads should happen based on this new write.
+         */
+        @Override
+        public OutputStream startWrite() throws IOException {
+            if (mWriteStream == null) {
+                mWriteStream = new ByteArrayOutputStream();
+            } else {
+                mWriteStream.reset();
+            }
+            if (mReadStream != null) {
+                closeRead();
+            }
+            return mWriteStream;
+        }
+
+        @Override
+        public void finishWrite(OutputStream os, boolean success) {
+            mWasSuccessful = success;
+            try {
+                os.close();
+            } catch (IOException e) {
+                // This method can't throw IOException since the super implementation doesn't, so
+                // we just wrap it in a RuntimeException so we end up crashing the test all the
+                // same.
+                throw new RuntimeException(e);
+            }
+        }
+
+        /** Override the read stream of the injector. By default it uses current write stream. */
+        private void setReadStream(InputStream is) {
+            mReadStream = is;
+        }
+
+        private boolean wasWriteSuccessful() {
+            return mWasSuccessful;
+        }
+    }
 }
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 88ac96d..4f03726 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java
@@ -181,15 +181,10 @@
     public void testDeferFinish() {
 
         // Start animation
-        mDeferFinishAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec,
-                true /* hidden */);
-        final ArgumentCaptor<OnAnimationFinishedCallback> callbackCaptor = ArgumentCaptor.forClass(
-                OnAnimationFinishedCallback.class);
-        assertAnimating(mDeferFinishAnimatable);
-        verify(mSpec).startAnimation(any(), any(), callbackCaptor.capture());
+        final OnAnimationFinishedCallback onFinishedCallback = startDeferFinishAnimatable(mSpec);
 
         // Finish the animation but then make sure we are deferring.
-        callbackCaptor.getValue().onAnimationFinished(mSpec);
+        onFinishedCallback.onAnimationFinished(mSpec);
         assertAnimating(mDeferFinishAnimatable);
 
         // Now end defer finishing.
@@ -199,6 +194,36 @@
         verify(mTransaction).remove(eq(mDeferFinishAnimatable.mLeash));
     }
 
+    @Test
+    public void testDeferFinishDoNotFinishNextAnimation() {
+        // Start the first animation.
+        final OnAnimationFinishedCallback onFinishedCallback = startDeferFinishAnimatable(mSpec);
+        onFinishedCallback.onAnimationFinished(mSpec);
+        // The callback is the resetAndInvokeFinish in {@link SurfaceAnimator#getFinishedCallback}.
+        final Runnable firstDeferFinishCallback = mDeferFinishAnimatable.mEndDeferFinishCallback;
+
+        // Start the second animation.
+        mDeferFinishAnimatable.mSurfaceAnimator.cancelAnimation();
+        startDeferFinishAnimatable(mSpec2);
+        mDeferFinishAnimatable.mFinishedCallbackCalled = false;
+
+        // Simulate the first deferred callback is executed from
+        // {@link AnimatingAppWindowTokenRegistry#endDeferringFinished}.
+        firstDeferFinishCallback.run();
+        // The second animation should not be finished.
+        assertFalse(mDeferFinishAnimatable.mFinishedCallbackCalled);
+    }
+
+    private OnAnimationFinishedCallback startDeferFinishAnimatable(AnimationAdapter anim) {
+        mDeferFinishAnimatable.mSurfaceAnimator.startAnimation(mTransaction, anim,
+                true /* hidden */);
+        final ArgumentCaptor<OnAnimationFinishedCallback> callbackCaptor = ArgumentCaptor.forClass(
+                OnAnimationFinishedCallback.class);
+        assertAnimating(mDeferFinishAnimatable);
+        verify(anim).startAnimation(any(), any(), callbackCaptor.capture());
+        return callbackCaptor.getValue();
+    }
+
     private void assertAnimating(MyAnimatable animatable) {
         assertTrue(animatable.mSurfaceAnimator.isAnimating());
         assertNotNull(animatable.mSurfaceAnimator.getAnimation());
diff --git a/services/usage/java/com/android/server/usage/IntervalStats.java b/services/usage/java/com/android/server/usage/IntervalStats.java
index 8feed7f..a783a40 100644
--- a/services/usage/java/com/android/server/usage/IntervalStats.java
+++ b/services/usage/java/com/android/server/usage/IntervalStats.java
@@ -66,7 +66,7 @@
     public final ArrayMap<String, UsageStats> packageStats = new ArrayMap<>();
     public final ArrayMap<Configuration, ConfigurationStats> configurations = new ArrayMap<>();
     public Configuration activeConfiguration;
-    public EventList events = new EventList();
+    public final EventList events = new EventList();
 
     // A string cache. This is important as when we're parsing XML files, we don't want to
     // keep hundreds of strings that have the same contents. We will read the string
@@ -82,7 +82,7 @@
 
         public void commitTime(long timeStamp) {
             if (curStartTime != 0) {
-                duration += timeStamp - duration;
+                duration += timeStamp - curStartTime;
                 curStartTime = 0;
             }
         }
@@ -305,7 +305,9 @@
             UsageStats usageStats = getOrCreateUsageStats(packageName);
             usageStats.update(className, timeStamp, eventType, instanceId);
         }
-        endTime = timeStamp;
+        if (timeStamp > endTime) {
+            endTime = timeStamp;
+        }
     }
 
     /**
@@ -328,6 +330,9 @@
             event.mNotificationChannelId = getCachedStringRef(event.mNotificationChannelId);
         }
         events.insert(event);
+        if (event.mTimeStamp > endTime) {
+            endTime = event.mTimeStamp;
+        }
     }
 
     void updateChooserCounts(String packageName, String category, String action) {
@@ -360,8 +365,9 @@
             configStats.mActivationCount += 1;
             activeConfiguration = configStats.mConfiguration;
         }
-
-        endTime = timeStamp;
+        if (timeStamp > endTime) {
+            endTime = timeStamp;
+        }
     }
 
     void incrementAppLaunchCount(String packageName) {
diff --git a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
index 485a79d..c55bb3c 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
@@ -1166,7 +1166,8 @@
         if (beingRestored == null) return null;
         beingRestored.activeConfiguration = onDevice.activeConfiguration;
         beingRestored.configurations.putAll(onDevice.configurations);
-        beingRestored.events = onDevice.events;
+        beingRestored.events.clear();
+        beingRestored.events.merge(onDevice.events);
         return beingRestored;
     }
 
diff --git a/services/usage/java/com/android/server/usage/UserUsageStatsService.java b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
index 9498e16..26bfcc9 100644
--- a/services/usage/java/com/android/server/usage/UserUsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UserUsageStatsService.java
@@ -334,7 +334,7 @@
                 final IntervalStats diskStats = mDatabase.getLatestUsageStats(
                         INTERVAL_DAILY);
                 StringBuilder sb = new StringBuilder(256);
-                sb.append("Last 24 hours of UsageStats missing! timeRange : ");
+                sb.append("Recent UsageStats missing! timeRange : ");
                 sb.append(beginTime);
                 sb.append(", ");
                 sb.append(endTime);
diff --git a/startop/iorap/tests/Android.bp b/startop/iorap/tests/Android.bp
index 4359978..3e60ad4 100644
--- a/startop/iorap/tests/Android.bp
+++ b/startop/iorap/tests/Android.bp
@@ -16,32 +16,48 @@
 java_library {
     name: "libiorap-java-test-lib",
     srcs: ["src/**/*.kt"],
-
     static_libs: [
-      // Non-test dependencies
-
-      // library under test
-      "services.startop.iorap",
-      // need the system_server code to be on the classpath,
-      "services.core",
-
-      // Test Dependencies
-
-      // test android dependencies
-      "platform-test-annotations",
-      "androidx.test.rules",
-      // test framework dependencies
-      "mockito-target-inline-minus-junit4",
-      // "mockito-target-minus-junit4",
+        // Non-test dependencies
+        // library under test
+        "services.startop.iorap",
+        // need the system_server code to be on the classpath,
+        "services.core",
+        // Test Dependencies
+        // test android dependencies
+        "platform-test-annotations",
+        "androidx.test.rules",
+        // test framework dependencies
+        "mockito-target-inline-minus-junit4",
+        // "mockito-target-minus-junit4",
         // Mockito also requires JNI (see Android.mk)
         // and android:debuggable=true (see AndroidManifest.xml)
-      "truth-prebuilt",
+        "truth-prebuilt",
     ],
-
     // sdk_version: "current",
     // certificate: "platform",
-
-    libs: ["android.test.base", "android.test.runner"],
-
+    libs: [
+        "android.test.base",
+        "android.test.runner",
+    ],
     // test_suites: ["device-tests"],
 }
+
+android_test {
+    name: "libiorap-java-tests",
+    dxflags: ["--multi-dex"],
+    test_suites: ["device-tests"],
+    static_libs: ["libiorap-java-test-lib"],
+    compile_multilib: "both",
+    jni_libs: [
+        "libdexmakerjvmtiagent",
+        "libstaticjvmtiagent",
+        "libmultiplejvmtiagentsinterferenceagent",
+    ],
+    libs: [
+        "android.test.base",
+        "android.test.runner",
+    ],
+    // Use private APIs
+    certificate: "platform",
+    platform_apis: true,
+}
diff --git a/startop/iorap/tests/Android.mk b/startop/iorap/tests/Android.mk
deleted file mode 100644
index fa8c8b5..0000000
--- a/startop/iorap/tests/Android.mk
+++ /dev/null
@@ -1,49 +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.
-
-# android_test does not support JNI libraries
-# TODO: once b/80095087 is fixed, rewrite this back to android_test
-LOCAL_PATH := $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-
-LOCAL_JACK_FLAGS := --multi-dex native
-LOCAL_DX_FLAGS := --multi-dex
-
-LOCAL_PACKAGE_NAME := libiorap-java-tests
-LOCAL_COMPATIBILITY_SUITE := device-tests
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    libiorap-java-test-lib
-
-LOCAL_MULTILIB := both
-
-LOCAL_JNI_SHARED_LIBRARIES := \
-    libdexmakerjvmtiagent \
-    libstaticjvmtiagent \
-    libmultiplejvmtiagentsinterferenceagent
-
-LOCAL_JAVA_LIBRARIES := \
-    android.test.base \
-    android.test.runner
-
-# Use private APIs
-LOCAL_CERTIFICATE := platform
-LOCAL_PRIVATE_PLATFORM_APIS := true
-
-# Disable presubmit test until it works with disabled iorap by default.
-LOCAL_PRESUBMIT_DISABLED := true
-
-include $(BUILD_PACKAGE)
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index fffa935..6aca693 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -2571,6 +2571,22 @@
             "emergency_number_prefix_string_array";
 
     /**
+     * Smart forwarding config. Smart forwarding is a feature to configure call forwarding to a
+     * different SIM in the device when one SIM is not reachable. The config here specifies a smart
+     * forwarding component that will launch UI for changing the configuration. An empty string
+     * indicates that no smart forwarding component is specified.
+     *
+     * Currently, only one non-empty configuration of smart forwarding component within system will
+     * be used when multiple SIMs are inserted.
+     *
+     * Empty string by default.
+     *
+     * @hide
+     */
+    public static final String KEY_SMART_FORWARDING_CONFIG_COMPONENT_NAME_STRING =
+            "smart_forwarding_config_component_name_string";
+
+    /**
      * Indicates when a carrier has a primary subscription and an opportunistic subscription active,
      * and when Internet data is switched to opportunistic network, whether to still show
      * signal bar of primary network. By default it will be false, meaning whenever data
@@ -3107,14 +3123,14 @@
         sDefaults.putString(KEY_5G_ICON_CONFIGURATION_STRING,
                 "connected_mmwave:None,connected:5G,not_restricted:None,restricted:None");
         sDefaults.putBoolean(KEY_ASCII_7_BIT_SUPPORT_FOR_LONG_MESSAGE_BOOL, false);
-        /* Default value is minimum RSRP level needed for SIGNAL_STRENGTH_GOOD */
-        sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_RSRP_INT, -108);
         /* Default value is minimum RSRP level needed for SIGNAL_STRENGTH_MODERATE */
-        sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSRP_INT, -118);
-        /* Default value is minimum RSSNR level needed for SIGNAL_STRENGTH_GOOD */
-        sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_RSSNR_INT, 45);
+        sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_RSRP_INT, -118);
+        /* Default value is minimum RSRP level needed for SIGNAL_STRENGTH_POOR */
+        sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSRP_INT, -128);
         /* Default value is minimum RSSNR level needed for SIGNAL_STRENGTH_MODERATE */
-        sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSSNR_INT, 10);
+        sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_RSSNR_INT, 10);
+        /* Default value is minimum RSSNR level needed for SIGNAL_STRENGTH_POOR */
+        sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_RSSNR_INT, -30);
         /* Default value is 1024 kbps */
         sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_BANDWIDTH_INT, 1024);
         /* Default value is 10 seconds */
@@ -3130,6 +3146,7 @@
         sDefaults.putBoolean(KEY_USE_USIM_BOOL, false);
         sDefaults.putBoolean(KEY_SHOW_WFC_LOCATION_PRIVACY_POLICY_BOOL, true);
         sDefaults.putBoolean(KEY_AUTO_CANCEL_CS_REJECT_NOTIFICATION, false);
+        sDefaults.putString(KEY_SMART_FORWARDING_CONFIG_COMPONENT_NAME_STRING, "");
         sDefaults.putBoolean(KEY_ALWAYS_SHOW_PRIMARY_SIGNAL_BAR_IN_OPPORTUNISTIC_NETWORK_BOOLEAN,
                 false);
     }
diff --git a/telephony/java/android/telephony/SmsManager.java b/telephony/java/android/telephony/SmsManager.java
index dde8057..09046a6 100644
--- a/telephony/java/android/telephony/SmsManager.java
+++ b/telephony/java/android/telephony/SmsManager.java
@@ -27,10 +27,6 @@
 import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityThread;
 import android.app.PendingIntent;
-import android.bluetooth.BluetoothAdapter;
-import android.bluetooth.BluetoothDevice;
-import android.bluetooth.BluetoothMapClient;
-import android.bluetooth.BluetoothProfile;
 import android.content.ActivityNotFoundException;
 import android.content.ContentValues;
 import android.content.Context;
@@ -43,7 +39,6 @@
 import android.os.Bundle;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.telecom.PhoneAccount;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.Log;
@@ -76,7 +71,6 @@
  */
 public final class SmsManager {
     private static final String TAG = "SmsManager";
-    private static final boolean DBG = false;
 
     /**
      * A psuedo-subId that represents the default subId at any given time. The actual subId it
@@ -357,42 +351,11 @@
             throw new IllegalArgumentException("Invalid message body");
         }
 
-        // A Manager code accessing another manager is *not* acceptable, in Android.
-        // In this particular case, it is unavoidable because of the following:
-        // If the subscription for this SmsManager instance belongs to a remote SIM
-        // then a listener to get BluetoothMapClient proxy needs to be started up.
-        // Doing that is possible only in a foreground thread or as a system user.
-        // i.e., Can't be done in ISms service.
-        // For that reason, SubscriptionManager needs to be accessed here to determine
-        // if the subscription belongs to a remote SIM.
-        // Ideally, there should be another API in ISms to service messages going thru
-        // remote SIM subscriptions (and ISms should be tweaked to be able to access
-        // BluetoothMapClient proxy)
-        Context context = ActivityThread.currentApplication().getApplicationContext();
-        SubscriptionManager manager = (SubscriptionManager) context
-                .getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
-        int subId = getSubscriptionId();
-        SubscriptionInfo info = manager.getActiveSubscriptionInfo(subId);
-        if (DBG) {
-            Log.d(TAG, "for subId: " + subId + ", subscription-info: " + info);
-        }
-
-        /* If the Subscription associated with this SmsManager instance belongs to a remote-sim,
-         * then send the message thru the remote-sim subscription.
-         */
-        if (info != null
-                && info.getSubscriptionType() == SubscriptionManager.SUBSCRIPTION_TYPE_REMOTE_SIM) {
-            if (DBG) Log.d(TAG, "sending message thru bluetooth");
-            sendTextMessageBluetooth(destinationAddress, scAddress, text, sentIntent,
-                    deliveryIntent, info);
-            return;
-        }
-
         try {
             // If the subscription is invalid or default, we will use the default phone to send the
             // SMS and possibly fail later in the SMS sending process.
-            ISms iccISms = getISmsServiceOrThrow();
-            iccISms.sendTextForSubscriber(subId, ActivityThread.currentPackageName(),
+            ISms iSms = getISmsServiceOrThrow();
+            iSms.sendTextForSubscriber(getSubscriptionId(), ActivityThread.currentPackageName(),
                     destinationAddress,
                     scAddress, text, sentIntent, deliveryIntent,
                     persistMessage);
@@ -401,82 +364,6 @@
         }
     }
 
-    private void sendTextMessageBluetooth(String destAddr, String scAddress,
-            String text, PendingIntent sentIntent, PendingIntent deliveryIntent,
-            SubscriptionInfo info) {
-        BluetoothAdapter btAdapter = BluetoothAdapter.getDefaultAdapter();
-        if (btAdapter == null) {
-            // No bluetooth service on this platform?
-            sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_ERROR_NO_SERVICE);
-            return;
-        }
-        BluetoothDevice device = btAdapter.getRemoteDevice(info.getIccId());
-        if (device == null) {
-            if (DBG) Log.d(TAG, "Bluetooth device addr invalid: " + info.getIccId());
-            sendErrorInPendingIntent(sentIntent, SmsManager.RESULT_ERROR_NO_SERVICE);
-            return;
-        }
-        btAdapter.getProfileProxy(ActivityThread.currentApplication().getApplicationContext(),
-                new MapMessageSender(destAddr, text, device, sentIntent, deliveryIntent),
-                BluetoothProfile.MAP_CLIENT);
-    }
-
-    private class MapMessageSender implements BluetoothProfile.ServiceListener {
-        final Uri[] mDestAddr;
-        private String mMessage;
-        final BluetoothDevice mDevice;
-        final PendingIntent mSentIntent;
-        final PendingIntent mDeliveryIntent;
-        MapMessageSender(final String destAddr, final String message, final BluetoothDevice device,
-                final PendingIntent sentIntent, final PendingIntent deliveryIntent) {
-            super();
-            mDestAddr = new Uri[] {new Uri.Builder()
-                    .appendPath(destAddr)
-                    .scheme(PhoneAccount.SCHEME_TEL)
-                    .build()};
-            mMessage = message;
-            mDevice = device;
-            mSentIntent = sentIntent;
-            mDeliveryIntent = deliveryIntent;
-        }
-
-        @Override
-        public void onServiceConnected(int profile, BluetoothProfile proxy) {
-            if (DBG) Log.d(TAG, "Service connected");
-            if (profile != BluetoothProfile.MAP_CLIENT) return;
-            BluetoothMapClient mapProfile = (BluetoothMapClient) proxy;
-            if (mMessage != null) {
-                if (DBG) Log.d(TAG, "Sending message thru bluetooth");
-                mapProfile.sendMessage(mDevice, mDestAddr, mMessage, mSentIntent, mDeliveryIntent);
-                mMessage = null;
-            }
-            BluetoothAdapter.getDefaultAdapter()
-                    .closeProfileProxy(BluetoothProfile.MAP_CLIENT, mapProfile);
-        }
-
-        @Override
-        public void onServiceDisconnected(int profile) {
-            if (mMessage != null) {
-                if (DBG) Log.d(TAG, "Bluetooth disconnected before sending the message");
-                sendErrorInPendingIntent(mSentIntent, SmsManager.RESULT_ERROR_NO_SERVICE);
-                mMessage = null;
-            }
-        }
-    }
-
-    private void sendErrorInPendingIntent(PendingIntent intent, int errorCode) {
-        if (intent == null) {
-            return;
-        }
-        try {
-            intent.send(errorCode);
-        } catch (PendingIntent.CanceledException e) {
-            // PendingIntent is cancelled. ignore sending this error code back to
-            // caller.
-            if (DBG) Log.d(TAG, "PendingIntent.CanceledException: " + e.getMessage());
-        }
-    }
-
     /**
      * Send a text based SMS without writing it into the SMS Provider.
      *
@@ -526,8 +413,8 @@
         }
 
         try {
-            ISms iccISms = getISmsServiceOrThrow();
-            iccISms.sendTextForSubscriberWithSelfPermissions(getSubscriptionId(),
+            ISms iSms = getISmsServiceOrThrow();
+            iSms.sendTextForSubscriberWithSelfPermissions(getSubscriptionId(),
                     ActivityThread.currentPackageName(),
                     destinationAddress,
                     scAddress, text, sentIntent, deliveryIntent, persistMessage);
@@ -610,9 +497,9 @@
         }
 
         try {
-             ISms iccISms = getISmsServiceOrThrow();
-            if (iccISms != null) {
-                iccISms.sendTextForSubscriberWithOptions(getSubscriptionId(),
+            ISms iSms = getISmsServiceOrThrow();
+            if (iSms != null) {
+                iSms.sendTextForSubscriberWithOptions(getSubscriptionId(),
                         ActivityThread.currentPackageName(), destinationAddress, scAddress, text,
                         sentIntent, deliveryIntent, persistMessage,  priority, expectMore,
                         validityPeriod);
@@ -671,9 +558,9 @@
                     "Invalid pdu format. format must be either 3gpp or 3gpp2");
         }
         try {
-            ISms iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
-            if (iccISms != null) {
-                iccISms.injectSmsPduForSubscriber(
+            ISms iSms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
+            if (iSms != null) {
+                iSms.injectSmsPduForSubscriber(
                         getSubscriptionId(), pdu, format, receivedIntent);
             }
         } catch (RemoteException ex) {
@@ -759,8 +646,8 @@
 
         if (parts.size() > 1) {
             try {
-                ISms iccISms = getISmsServiceOrThrow();
-                iccISms.sendMultipartTextForSubscriber(getSubscriptionId(),
+                ISms iSms = getISmsServiceOrThrow();
+                iSms.sendMultipartTextForSubscriber(getSubscriptionId(),
                         ActivityThread.currentPackageName(),
                         destinationAddress, scAddress, parts,
                         sentIntents, deliveryIntents, persistMessage);
@@ -891,9 +778,9 @@
 
         if (parts.size() > 1) {
             try {
-                 ISms iccISms = getISmsServiceOrThrow();
-                if (iccISms != null) {
-                    iccISms.sendMultipartTextForSubscriberWithOptions(getSubscriptionId(),
+                ISms iSms = getISmsServiceOrThrow();
+                if (iSms != null) {
+                    iSms.sendMultipartTextForSubscriberWithOptions(getSubscriptionId(),
                             ActivityThread.currentPackageName(), destinationAddress, scAddress,
                             parts, sentIntents, deliveryIntents, persistMessage, priority,
                             expectMore, validityPeriod);
@@ -979,8 +866,8 @@
         }
 
         try {
-            ISms iccISms = getISmsServiceOrThrow();
-            iccISms.sendDataForSubscriber(getSubscriptionId(), ActivityThread.currentPackageName(),
+            ISms iSms = getISmsServiceOrThrow();
+            iSms.sendDataForSubscriber(getSubscriptionId(), ActivityThread.currentPackageName(),
                     destinationAddress, scAddress, destinationPort & 0xFFFF,
                     data, sentIntent, deliveryIntent);
         } catch (RemoteException ex) {
@@ -1006,8 +893,8 @@
         }
 
         try {
-            ISms iccISms = getISmsServiceOrThrow();
-            iccISms.sendDataForSubscriberWithSelfPermissions(getSubscriptionId(),
+            ISms iSms = getISmsServiceOrThrow();
+            iSms.sendDataForSubscriberWithSelfPermissions(getSubscriptionId(),
                     ActivityThread.currentPackageName(), destinationAddress, scAddress,
                     destinationPort & 0xFFFF, data, sentIntent, deliveryIntent);
         } catch (RemoteException ex) {
@@ -1069,9 +956,9 @@
         boolean isSmsSimPickActivityNeeded = false;
         final Context context = ActivityThread.currentApplication().getApplicationContext();
         try {
-            ISms iccISms = getISmsService();
-            if (iccISms != null) {
-                isSmsSimPickActivityNeeded = iccISms.isSmsSimPickActivityNeeded(subId);
+            ISms iSms = getISmsService();
+            if (iSms != null) {
+                isSmsSimPickActivityNeeded = iSms.isSmsSimPickActivityNeeded(subId);
             }
         } catch (RemoteException ex) {
             Log.e(TAG, "Exception in getSubscriptionId");
@@ -1102,11 +989,11 @@
      * the service does not exist.
      */
     private static ISms getISmsServiceOrThrow() {
-        ISms iccISms = getISmsService();
-        if (iccISms == null) {
+        ISms iSms = getISmsService();
+        if (iSms == null) {
             throw new UnsupportedOperationException("Sms is not supported");
         }
-        return iccISms;
+        return iSms;
     }
 
     private static ISms getISmsService() {
@@ -1135,9 +1022,9 @@
             throw new IllegalArgumentException("pdu is NULL");
         }
         try {
-            ISms iccISms = getISmsService();
-            if (iccISms != null) {
-                success = iccISms.copyMessageToIccEfForSubscriber(getSubscriptionId(),
+            ISms iSms = getISmsService();
+            if (iSms != null) {
+                success = iSms.copyMessageToIccEfForSubscriber(getSubscriptionId(),
                         ActivityThread.currentPackageName(),
                         status, pdu, smsc);
             }
@@ -1166,9 +1053,9 @@
         Arrays.fill(pdu, (byte)0xff);
 
         try {
-            ISms iccISms = getISmsService();
-            if (iccISms != null) {
-                success = iccISms.updateMessageOnIccEfForSubscriber(getSubscriptionId(),
+            ISms iSms = getISmsService();
+            if (iSms != null) {
+                success = iSms.updateMessageOnIccEfForSubscriber(getSubscriptionId(),
                         ActivityThread.currentPackageName(),
                         messageIndex, STATUS_ON_ICC_FREE, pdu);
             }
@@ -1198,9 +1085,9 @@
         boolean success = false;
 
         try {
-            ISms iccISms = getISmsService();
-            if (iccISms != null) {
-                success = iccISms.updateMessageOnIccEfForSubscriber(getSubscriptionId(),
+            ISms iSms = getISmsService();
+            if (iSms != null) {
+                success = iSms.updateMessageOnIccEfForSubscriber(getSubscriptionId(),
                         ActivityThread.currentPackageName(),
                         messageIndex, newStatus, pdu);
             }
@@ -1225,9 +1112,9 @@
         List<SmsRawData> records = null;
 
         try {
-            ISms iccISms = getISmsService();
-            if (iccISms != null) {
-                records = iccISms.getAllMessagesFromIccEfForSubscriber(
+            ISms iSms = getISmsService();
+            if (iSms != null) {
+                records = iSms.getAllMessagesFromIccEfForSubscriber(
                         getSubscriptionId(),
                         ActivityThread.currentPackageName());
             }
@@ -1262,9 +1149,9 @@
         boolean success = false;
 
         try {
-            ISms iccISms = getISmsService();
-            if (iccISms != null) {
-                success = iccISms.enableCellBroadcastForSubscriber(
+            ISms iSms = getISmsService();
+            if (iSms != null) {
+                success = iSms.enableCellBroadcastForSubscriber(
                         getSubscriptionId(), messageIdentifier, ranType);
             }
         } catch (RemoteException ex) {
@@ -1298,9 +1185,9 @@
         boolean success = false;
 
         try {
-            ISms iccISms = getISmsService();
-            if (iccISms != null) {
-                success = iccISms.disableCellBroadcastForSubscriber(
+            ISms iSms = getISmsService();
+            if (iSms != null) {
+                success = iSms.disableCellBroadcastForSubscriber(
                         getSubscriptionId(), messageIdentifier, ranType);
             }
         } catch (RemoteException ex) {
@@ -1341,9 +1228,9 @@
             throw new IllegalArgumentException("endMessageId < startMessageId");
         }
         try {
-            ISms iccISms = getISmsService();
-            if (iccISms != null) {
-                success = iccISms.enableCellBroadcastRangeForSubscriber(getSubscriptionId(),
+            ISms iSms = getISmsService();
+            if (iSms != null) {
+                success = iSms.enableCellBroadcastRangeForSubscriber(getSubscriptionId(),
                         startMessageId, endMessageId, ranType);
             }
         } catch (RemoteException ex) {
@@ -1384,9 +1271,9 @@
             throw new IllegalArgumentException("endMessageId < startMessageId");
         }
         try {
-            ISms iccISms = getISmsService();
-            if (iccISms != null) {
-                success = iccISms.disableCellBroadcastRangeForSubscriber(getSubscriptionId(),
+            ISms iSms = getISmsService();
+            if (iSms != null) {
+                success = iSms.disableCellBroadcastRangeForSubscriber(getSubscriptionId(),
                         startMessageId, endMessageId, ranType);
             }
         } catch (RemoteException ex) {
@@ -1436,9 +1323,9 @@
     public boolean isImsSmsSupported() {
         boolean boSupported = false;
         try {
-            ISms iccISms = getISmsService();
-            if (iccISms != null) {
-                boSupported = iccISms.isImsSmsSupportedForSubscriber(getSubscriptionId());
+            ISms iSms = getISmsService();
+            if (iSms != null) {
+                boSupported = iSms.isImsSmsSupportedForSubscriber(getSubscriptionId());
             }
         } catch (RemoteException ex) {
             // ignore it
@@ -1461,9 +1348,9 @@
     public String getImsSmsFormat() {
         String format = com.android.internal.telephony.SmsConstants.FORMAT_UNKNOWN;
         try {
-            ISms iccISms = getISmsService();
-            if (iccISms != null) {
-                format = iccISms.getImsSmsFormatForSubscriber(getSubscriptionId());
+            ISms iSms = getISmsService();
+            if (iSms != null) {
+                format = iSms.getImsSmsFormatForSubscriber(getSubscriptionId());
             }
         } catch (RemoteException ex) {
             // ignore it
@@ -1477,10 +1364,10 @@
      * @return the default SMS subscription id
      */
     public static int getDefaultSmsSubscriptionId() {
-        ISms iccISms = null;
+        ISms iSms = null;
         try {
-            iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
-            return iccISms.getPreferredSmsSubscription();
+            iSms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
+            return iSms.getPreferredSmsSubscription();
         } catch (RemoteException ex) {
             return -1;
         } catch (NullPointerException ex) {
@@ -1496,10 +1383,10 @@
      */
     @UnsupportedAppUsage
     public boolean isSMSPromptEnabled() {
-        ISms iccISms = null;
+        ISms iSms = null;
         try {
-            iccISms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
-            return iccISms.isSMSPromptEnabled();
+            iSms = ISms.Stub.asInterface(ServiceManager.getService("isms"));
+            return iSms.isSMSPromptEnabled();
         } catch (RemoteException ex) {
             return false;
         } catch (NullPointerException ex) {
@@ -1976,8 +1863,8 @@
             throw new IllegalArgumentException("Empty message URI");
         }
         try {
-            ISms iccISms = getISmsServiceOrThrow();
-            iccISms.sendStoredText(
+            ISms iSms = getISmsServiceOrThrow();
+            iSms.sendStoredText(
                     getSubscriptionId(), ActivityThread.currentPackageName(), messageUri,
                     scAddress, sentIntent, deliveryIntent);
         } catch (RemoteException ex) {
@@ -2024,8 +1911,8 @@
             throw new IllegalArgumentException("Empty message URI");
         }
         try {
-            ISms iccISms = getISmsServiceOrThrow();
-            iccISms.sendStoredMultipartText(
+            ISms iSms = getISmsServiceOrThrow();
+            iSms.sendStoredMultipartText(
                     getSubscriptionId(), ActivityThread.currentPackageName(), messageUri,
                     scAddress, sentIntents, deliveryIntents);
         } catch (RemoteException ex) {
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index ffd5b16..e4debd6 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -4845,22 +4845,18 @@
      * Registers a listener object to receive notification of changes
      * in specified telephony states.
      * <p>
-     * To register a listener, pass a {@link PhoneStateListener} and specify at least one telephony
-     * state of interest in the events argument.
+     * To register a listener, pass a {@link PhoneStateListener}
+     * and specify at least one telephony state of interest in
+     * the events argument.
      *
-     * At registration, and when a specified telephony state changes, the telephony manager invokes
-     * the appropriate callback method on the listener object and passes the current (updated)
-     * values.
+     * At registration, and when a specified telephony state
+     * changes, the telephony manager invokes the appropriate
+     * callback method on the listener object and passes the
+     * current (updated) values.
      * <p>
-     * To un-register a listener, pass the listener object and set the events argument to
+     * To unregister a listener, pass the listener object and set the
+     * events argument to
      * {@link PhoneStateListener#LISTEN_NONE LISTEN_NONE} (0).
-     *
-     * If this TelephonyManager object has been created with {@link #createForSubscriptionId},
-     * applies to the given subId. Otherwise, applies to
-     * {@link SubscriptionManager#getDefaultSubscriptionId()}. To listen events for multiple subIds,
-     * pass a separate listener object to each TelephonyManager object created with
-     * {@link #createForSubscriptionId}.
-     *
      * Note: if you call this method while in the middle of a binder transaction, you <b>must</b>
      * call {@link android.os.Binder#clearCallingIdentity()} before calling this method. A
      * {@link SecurityException} will be thrown otherwise.
@@ -4875,18 +4871,17 @@
         if (mContext == null) return;
         try {
             boolean notifyNow = (getITelephony() != null);
+            // If the listener has not explicitly set the subId (for example, created with the
+            // default constructor), replace the subId so it will listen to the account the
+            // telephony manager is created with.
+            if (listener.mSubId == null) {
+                listener.mSubId = mSubId;
+            }
+
             ITelephonyRegistry registry = getTelephonyRegistry();
             if (registry != null) {
-                // listen to the subId the telephony manager is created with. Ignore subId in
-                // PhoneStateListener.
-                registry.listenForSubscriber(mSubId, getOpPackageName(),
+                registry.listenForSubscriber(listener.mSubId, getOpPackageName(),
                         listener.callback, events, notifyNow);
-                // TODO: remove this once we remove PhoneStateListener constructor with subId.
-                if (events == PhoneStateListener.LISTEN_NONE) {
-                    listener.mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
-                } else {
-                    listener.mSubId = mSubId;
-                }
             } else {
                 Rlog.w(TAG, "telephony registry not ready.");
             }
@@ -10703,6 +10698,25 @@
     }
 
     /**
+     * It indicates whether modem is enabled or not per slot.
+     * It's the corresponding status of {@link #enableModemForSlot}.
+     *
+     * @param slotIndex which slot it's checking.
+     * @hide
+     */
+    public boolean isModemEnabledForSlot(int slotIndex) {
+        try {
+            ITelephony telephony = getITelephony();
+            if (telephony != null) {
+                return telephony.isModemEnabledForSlot(slotIndex, mContext.getOpPackageName());
+            }
+        } catch (RemoteException ex) {
+            Log.e(TAG, "enableModem RemoteException", ex);
+        }
+        return false;
+    }
+
+    /**
      * Broadcast intent action for network country code changes.
      *
      * <p>
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 9e2d9ee..8332ffe 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1958,5 +1958,7 @@
     /**
      * Get the IRadio HAL Version encoded as 100 * MAJOR_VERSION + MINOR_VERSION or -1 if unknown
      */
-     int getRadioHalVersion();
+    int getRadioHalVersion();
+
+    boolean isModemEnabledForSlot(int slotIndex, String callingPackage);
 }
diff --git a/tests/FlickerTests/AndroidTest.xml b/tests/FlickerTests/AndroidTest.xml
index 41cb74a..e36f976 100644
--- a/tests/FlickerTests/AndroidTest.xml
+++ b/tests/FlickerTests/AndroidTest.xml
@@ -17,6 +17,7 @@
     </target_preparer>
     <test class="com.android.tradefed.testtype.AndroidJUnitTest">
         <option name="package" value="com.android.server.wm.flicker"/>
+        <option name="exclude-annotation" value="org.junit.Ignore" />
         <option name="shell-timeout" value="6600s" />
         <option name="test-timeout" value="6000s" />
         <option name="hidden-api-checks" value="false" />
diff --git a/packages/PackageInstaller/Android.mk b/tests/GamePerformance/Android.mk
similarity index 73%
rename from packages/PackageInstaller/Android.mk
rename to tests/GamePerformance/Android.mk
index ab5483c..58654de 100644
--- a/packages/PackageInstaller/Android.mk
+++ b/tests/GamePerformance/Android.mk
@@ -16,17 +16,24 @@
 
 include $(CLEAR_VARS)
 
+# Don't include this package in any target
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_DEX_PREOPT := false
+
+LOCAL_PROGUARD_ENABLED := disabled
+
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
-LOCAL_PACKAGE_NAME := PackageInstaller
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-test
 
-LOCAL_CERTIFICATE := platform
-LOCAL_PRIVILEGED_MODULE := true
+LOCAL_JAVA_LIBRARIES := android.test.base android.test.runner
+
+LOCAL_PACKAGE_NAME := GamePerformance
+
 LOCAL_PRIVATE_PLATFORM_APIS := true
 
-LOCAL_STATIC_JAVA_LIBRARIES := xz-java
-LOCAL_STATIC_ANDROID_LIBRARIES := androidx.leanback_leanback
+LOCAL_CERTIFICATE := platform
+
 
 include $(BUILD_PACKAGE)
-
-include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/tests/GamePerformance/AndroidManifest.xml b/tests/GamePerformance/AndroidManifest.xml
new file mode 100644
index 0000000..b331e2c
--- /dev/null
+++ b/tests/GamePerformance/AndroidManifest.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.gameperformance">
+    <uses-sdk android:minSdkVersion="25"/>
+    <uses-feature android:glEsVersion="0x00020000" android:required="true" />
+
+    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+    <application android:theme="@style/noeffects">
+        <uses-library android:name="android.test.runner" />
+        <activity android:name="android.gameperformance.GamePerformanceActivity" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+        <uses-library android:name="android.test.runner" />
+    </application>
+
+    <!--  self-instrumenting test package. -->
+    <instrumentation android:name="android.test.InstrumentationTestRunner"
+                     android:targetPackage="android.gameperformance">
+    </instrumentation>
+</manifest>
diff --git a/tests/GamePerformance/res/values/themes.xml b/tests/GamePerformance/res/values/themes.xml
new file mode 100644
index 0000000..6313071
--- /dev/null
+++ b/tests/GamePerformance/res/values/themes.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+<resources>
+    <style name="noeffects" parent="@android:style/Theme.Holo.NoActionBar.Fullscreen">
+        <item name="android:windowNoTitle">true</item>
+        <item name="android:windowFullscreen">true</item>
+        <item name="android:fadingEdge">none</item>
+        <item name="android:windowContentTransitions">false</item>
+        <item name="android:windowAnimationStyle">@null</item>
+    </style>
+</resources>
diff --git a/tests/GamePerformance/src/android/gameperformance/ATraceRunner.java b/tests/GamePerformance/src/android/gameperformance/ATraceRunner.java
new file mode 100644
index 0000000..25754fd
--- /dev/null
+++ b/tests/GamePerformance/src/android/gameperformance/ATraceRunner.java
@@ -0,0 +1,94 @@
+/*
+ * 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.gameperformance;
+
+import java.io.BufferedReader;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+
+import android.app.Instrumentation;
+import android.os.AsyncTask;
+import android.os.ParcelFileDescriptor;
+import android.util.Log;
+
+/**
+ * Helper that runs atrace command for required duration and category. Results are read from
+ * the output of atrace and serialized to the provided file. We cannot use direct atrace to
+ * file because atrace is executed in UI automator context and analysis is done in test context.
+ * In last case output file is not accessible from the both contexts.
+ */
+public class ATraceRunner extends AsyncTask<Void, Integer, Boolean>{
+    private final static String TAG = "ATraceRunner";
+
+    // Report that atrace is done.
+    public interface Delegate {
+        public void onProcessed(boolean success);
+    }
+
+    private final Instrumentation mInstrumentation;
+    private final String mOutput;
+    private final int mTimeInSeconds;
+    private final String mCategory;
+    private final Delegate mDelegate;
+
+    public ATraceRunner(Instrumentation instrumentation,
+                        String output,
+                        int timeInSeconds,
+                        String category,
+                        Delegate delegate) {
+        mInstrumentation = instrumentation;
+        mOutput = output;
+        mTimeInSeconds = timeInSeconds;
+        mCategory = category;
+        mDelegate = delegate;
+    }
+
+    @Override
+    protected Boolean doInBackground(Void... params) {
+        BufferedReader bufferedReader = null;
+        FileWriter writer = null;
+        try {
+            // Run the command.
+            final String cmd = "atrace -t " + mTimeInSeconds + " " + mCategory;
+            Log.i(TAG, "Running atrace... " + cmd);
+            writer = new FileWriter(mOutput);
+            final ParcelFileDescriptor fd =
+                    mInstrumentation.getUiAutomation().executeShellCommand(cmd);
+            bufferedReader = new BufferedReader(
+                    new InputStreamReader(new ParcelFileDescriptor.AutoCloseInputStream(fd)));
+            String line;
+            while ((line = bufferedReader.readLine()) != null) {
+                writer.write(line);
+                writer.write("\n");
+            }
+            Log.i(TAG, "Running atrace... DONE");
+            return true;
+        } catch (IOException e) {
+            Log.i(TAG, "atrace failed", e);
+            return false;
+        } finally {
+            Utils.closeQuietly(bufferedReader);
+            Utils.closeQuietly(writer);
+        }
+    }
+
+    @Override
+    protected void onPostExecute(Boolean result) {
+        mDelegate.onProcessed(result);
+    }
+
+}
diff --git a/tests/GamePerformance/src/android/gameperformance/CustomOpenGLView.java b/tests/GamePerformance/src/android/gameperformance/CustomOpenGLView.java
new file mode 100644
index 0000000..2b37280
--- /dev/null
+++ b/tests/GamePerformance/src/android/gameperformance/CustomOpenGLView.java
@@ -0,0 +1,91 @@
+/*
+ * 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.gameperformance;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
+
+import android.content.Context;
+import android.opengl.GLES20;
+import android.opengl.GLSurfaceView;
+
+public class CustomOpenGLView extends GLSurfaceView {
+    private Random mRandom;
+    private List<Long> mFrameTimes;
+
+    public CustomOpenGLView(Context context) {
+        super(context);
+
+        mRandom = new Random();
+        mFrameTimes = new ArrayList<Long>();
+
+        setEGLContextClientVersion(2);
+
+        setRenderer(new GLSurfaceView.Renderer() {
+            @Override
+            public void onSurfaceCreated(GL10 gl, EGLConfig config) {
+                GLES20.glClearColor(1.0f, 0.0f, 0.0f, 1.0f);
+                gl.glClearDepthf(1.0f);
+                gl.glEnable(GL10.GL_DEPTH_TEST);
+                gl.glDepthFunc(GL10.GL_LEQUAL);
+
+                gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT,
+                          GL10.GL_NICEST);            }
+
+            @Override
+            public void onSurfaceChanged(GL10 gl, int width, int height) {
+                GLES20.glViewport(0, 0, width, height);
+            }
+
+            @Override
+            public void onDrawFrame(GL10 gl) {
+                GLES20.glClearColor(
+                        mRandom.nextFloat(), mRandom.nextFloat(), mRandom.nextFloat(), 1.0f);
+                gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
+                synchronized (mFrameTimes) {
+                    mFrameTimes.add(System.currentTimeMillis());
+                }
+            }
+        });
+        setRenderMode(GLSurfaceView.RENDERMODE_CONTINUOUSLY);
+    }
+
+    /**
+     * Resets frame times in order to calculate fps for different test pass.
+     */
+    public void resetFrameTimes() {
+        synchronized (mFrameTimes) {
+            mFrameTimes.clear();
+        }
+    }
+
+    /**
+     * Returns current fps based on collected frame times.
+     */
+    public double getFps() {
+        synchronized (mFrameTimes) {
+            if (mFrameTimes.size() < 2) {
+                return 0.0f;
+            }
+            return 1000.0 * mFrameTimes.size() /
+                    (mFrameTimes.get(mFrameTimes.size() - 1) - mFrameTimes.get(0));
+        }
+    }
+}
diff --git a/tests/GamePerformance/src/android/gameperformance/CustomSurfaceView.java b/tests/GamePerformance/src/android/gameperformance/CustomSurfaceView.java
new file mode 100644
index 0000000..a46668d
--- /dev/null
+++ b/tests/GamePerformance/src/android/gameperformance/CustomSurfaceView.java
@@ -0,0 +1,190 @@
+/*
+ * 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.gameperformance;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.Trace;
+import android.view.Surface;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+
+/**
+ * Minimal SurfaceView that sends buffer on request.
+ */
+public class CustomSurfaceView extends SurfaceView implements SurfaceHolder.Callback {
+    // Tag for trace when buffer is requested.
+    public final static String LOCAL_REQUEST_BUFFER = "localRequestBuffer";
+    // Tag for trace when buffer is posted.
+    public final static String LOCAL_POST_BUFFER = "localPostBuffer";
+
+    private final Object mSurfaceLock = new Object();
+    // Keeps frame times. Used to calculate fps.
+    private List<Long> mFrameTimes;
+    // Surface to send.
+    private Surface mSurface;
+    private Handler mHandler;
+
+    private Runnable mInvalidateSurfaceTask = new Runnable() {
+        @Override
+        public void run() {
+            synchronized (mSurfaceLock) {
+                if (mSurface == null) {
+                    return;
+                }
+                invalidateSurface(true, true);
+                mHandler.post(this);
+            }
+        }
+    };
+
+    public CustomSurfaceView(Context context) {
+        super(context);
+        mFrameTimes = new ArrayList<Long>();
+        getHolder().addCallback(this);
+        getHolder().setFormat(PixelFormat.OPAQUE);
+
+        HandlerThread thread = new HandlerThread("SurfaceInvalidator");
+        thread.start();
+        mHandler = new Handler(thread.getLooper());
+    }
+
+    /**
+     * Resets frame times in order to calculate fps for different test pass.
+     */
+    public void resetFrameTimes() {
+        synchronized (mSurfaceLock) {
+            mFrameTimes.clear();
+        }
+    }
+
+    /**
+     * Returns current fps based on collected frame times.
+     */
+    public double getFps() {
+        synchronized (mSurfaceLock) {
+            if (mFrameTimes.size() < 2) {
+                return 0.0f;
+            }
+            return 1000.0 * mFrameTimes.size() /
+                    (mFrameTimes.get(mFrameTimes.size() - 1) - mFrameTimes.get(0));
+        }
+    }
+
+    /**
+     * Invalidates surface.
+     * @param traceCalls set to true in case we need register trace calls. Not used for warm-up.
+     * @param drawFps perform drawing current fps on surface to have some payload on surface.
+     */
+    public void invalidateSurface(boolean traceCalls, boolean drawFps) {
+        synchronized (mSurfaceLock) {
+            if (mSurface == null) {
+                throw new IllegalStateException("Surface is not ready");
+            }
+            if (traceCalls) {
+                Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, LOCAL_REQUEST_BUFFER);
+            }
+            Canvas canvas = mSurface.lockHardwareCanvas();
+            if (traceCalls) {
+                Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS);
+            }
+
+            if (drawFps) {
+                int textSize = canvas.getHeight() / 24;
+                Paint paint = new Paint();
+                paint.setTextSize(textSize);
+                paint.setColor(0xFFFF8040);
+                canvas.drawARGB(92, 255, 255, 255);
+                canvas.drawText("FPS: " + String.format("%.2f", getFps()), 10, 300, paint);
+            }
+
+            if (traceCalls) {
+                Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, LOCAL_POST_BUFFER);
+            }
+            mSurface.unlockCanvasAndPost(canvas);
+            if (traceCalls) {
+                Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS);
+            }
+
+            mFrameTimes.add(System.currentTimeMillis());
+        }
+    }
+
+    /**
+     * Wait until surface is created and ready to use or return immediately if surface
+     * already exists.
+     */
+    public void waitForSurfaceReady() {
+        synchronized (mSurfaceLock) {
+            if (mSurface == null) {
+                try {
+                    mSurfaceLock.wait(5000);
+                } catch(InterruptedException e) {
+                    e.printStackTrace();
+                }
+            }
+            if (mSurface == null)
+                throw new IllegalStateException("Surface is not ready.");
+        }
+    }
+
+    /**
+     * Waits until surface is destroyed or return immediately if surface does not exist.
+     */
+    public void waitForSurfaceDestroyed() {
+        synchronized (mSurfaceLock) {
+            if (mSurface != null) {
+                try {
+                    mSurfaceLock.wait(5000);
+                } catch(InterruptedException e) {
+                }
+            }
+            if (mSurface != null)
+                throw new IllegalStateException("Surface still exists.");
+        }
+    }
+
+
+    @Override
+    public void surfaceCreated(SurfaceHolder holder) {
+    }
+
+    @Override
+    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+        // This method is always called at least once, after surfaceCreated.
+        synchronized (mSurfaceLock) {
+            mSurface = holder.getSurface();
+            mSurfaceLock.notify();
+            mHandler.post(mInvalidateSurfaceTask);
+        }
+    }
+
+    @Override
+    public void surfaceDestroyed(SurfaceHolder holder) {
+        synchronized (mSurfaceLock) {
+            mHandler.removeCallbacks(mInvalidateSurfaceTask);
+            mSurface = null;
+            mSurfaceLock.notify();
+        }
+    }
+}
diff --git a/tests/GamePerformance/src/android/gameperformance/GamePerformanceActivity.java b/tests/GamePerformance/src/android/gameperformance/GamePerformanceActivity.java
new file mode 100644
index 0000000..b0e6196
--- /dev/null
+++ b/tests/GamePerformance/src/android/gameperformance/GamePerformanceActivity.java
@@ -0,0 +1,132 @@
+/*
+ * 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.gameperformance;
+
+import java.util.concurrent.CountDownLatch;
+
+import android.app.Activity;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.view.ViewGroup;
+import android.view.WindowManager;
+import android.widget.RelativeLayout;
+
+/**
+ * Minimal activity that holds SurfaceView or GLSurfaceView.
+ * call attachSurfaceView or attachOpenGLView to switch views.
+ */
+public class GamePerformanceActivity extends Activity {
+    private CustomSurfaceView mSurfaceView = null;
+    private CustomOpenGLView mOpenGLView = null;
+    private RelativeLayout mRootLayout;
+
+    public void attachSurfaceView() throws InterruptedException {
+        synchronized (mRootLayout) {
+            if (mSurfaceView != null) {
+                return;
+            }
+            final CountDownLatch latch = new CountDownLatch(1);
+            runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    if (mOpenGLView != null) {
+                        mRootLayout.removeView(mOpenGLView);
+                        mOpenGLView = null;
+                    }
+                    mSurfaceView = new CustomSurfaceView(GamePerformanceActivity.this);
+                    mRootLayout.addView(mSurfaceView);
+                    latch.countDown();
+                }
+            });
+            latch.await();
+            mSurfaceView.waitForSurfaceReady();
+        }
+    }
+
+    public void attachOpenGLView() throws InterruptedException {
+        synchronized (mRootLayout) {
+            if (mOpenGLView != null) {
+                return;
+            }
+            final CountDownLatch latch = new CountDownLatch(1);
+            runOnUiThread(new Runnable() {
+                @Override
+                public void run() {
+                    if (mSurfaceView != null) {
+                        mRootLayout.removeView(mSurfaceView);
+                        mSurfaceView = null;
+                    }
+                    mOpenGLView = new CustomOpenGLView(GamePerformanceActivity.this);
+                    mRootLayout.addView(mOpenGLView);
+                    latch.countDown();
+                }
+            });
+            latch.await();
+        }
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+
+        // To layouts in parent. First contains list of Surfaces and second
+        // controls. Controls stay on top.
+        mRootLayout = new RelativeLayout(this);
+        mRootLayout.setLayoutParams(new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.MATCH_PARENT,
+                ViewGroup.LayoutParams.MATCH_PARENT));
+
+        Rect rect = new Rect();
+        getWindow().getDecorView().getWindowVisibleDisplayFrame(rect);
+
+        mOpenGLView =  new CustomOpenGLView(this);
+        mRootLayout.addView(mOpenGLView);
+
+        setContentView(mRootLayout);
+    }
+
+    public void resetFrameTimes() {
+        if (mSurfaceView != null) {
+            mSurfaceView.resetFrameTimes();
+        } else if (mOpenGLView != null) {
+            mOpenGLView.resetFrameTimes();
+        } else {
+            throw new IllegalStateException("Nothing attached");
+        }
+    }
+
+    public double getFps() {
+        if (mSurfaceView != null) {
+            return mSurfaceView.getFps();
+        } else if (mOpenGLView != null) {
+            return mOpenGLView.getFps();
+        } else {
+            throw new IllegalStateException("Nothing attached");
+        }
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+    }
+}
\ No newline at end of file
diff --git a/tests/GamePerformance/src/android/gameperformance/GamePerformanceTest.java b/tests/GamePerformance/src/android/gameperformance/GamePerformanceTest.java
new file mode 100644
index 0000000..e5de7d7
--- /dev/null
+++ b/tests/GamePerformance/src/android/gameperformance/GamePerformanceTest.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.gameperformance;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Map;
+import java.util.concurrent.CountDownLatch;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.PixelFormat;
+import android.os.Build;
+import android.os.Bundle;
+import android.os.Trace;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Log;
+
+public class GamePerformanceTest extends
+        ActivityInstrumentationTestCase2<GamePerformanceActivity> {
+    private final static String TAG = "GamePerformanceTest";
+
+    private final static int GRAPHIC_BUFFER_WARMUP_LOOP_CNT = 60;
+
+    public GamePerformanceTest() {
+        super(GamePerformanceActivity.class);
+    }
+
+    @SmallTest
+    public void testGraphicBufferMetrics() throws IOException, InterruptedException {
+        Bundle status = new Bundle();
+
+        for (int i = 0; i < 2; ++i) {
+            if (i == 0) {
+                getActivity().attachSurfaceView();
+            } else {
+                getActivity().attachOpenGLView();
+            }
+
+            // Perform warm-up.
+            Thread.sleep(2000);
+
+            // Once atrace is done, this one is triggered.
+            CountDownLatch latch = new CountDownLatch(1);
+
+            final String passTag = i == 0 ? "surface" : "opengl";
+            final String output = (new File(getInstrumentation().getContext().getFilesDir(),
+                    "atrace_" + passTag + ".log")).getAbsolutePath();
+            Log.i(TAG, "Collecting traces to " + output);
+            new ATraceRunner(getInstrumentation(), output, 5, "gfx", new ATraceRunner.Delegate() {
+                @Override
+                public void onProcessed(boolean success) {
+                    latch.countDown();
+                }
+            }).execute();
+
+            // Reset frame times and perform invalidation loop while atrace is running.
+            getActivity().resetFrameTimes();
+            latch.await();
+
+            // Copy results.
+            final Map<String, Double> metrics =
+                    GraphicBufferMetrics.processGraphicBufferResult(output, passTag);
+            for (Map.Entry<String, Double> metric : metrics.entrySet()) {
+                status.putDouble(metric.getKey(), metric.getValue());
+            }
+            // Also record FPS.
+            status.putDouble(passTag + "_fps", getActivity().getFps());
+        }
+
+        getInstrumentation().sendStatus(Activity.RESULT_OK, status);
+    }
+}
diff --git a/tests/GamePerformance/src/android/gameperformance/GraphicBufferMetrics.java b/tests/GamePerformance/src/android/gameperformance/GraphicBufferMetrics.java
new file mode 100644
index 0000000..dffce1a
--- /dev/null
+++ b/tests/GamePerformance/src/android/gameperformance/GraphicBufferMetrics.java
@@ -0,0 +1,530 @@
+/*
+ * 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.gameperformance;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.StringTokenizer;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+/**
+ * Utility class that performs analysis of atrace logs. This is implemented without Android
+ * dependencies and therefore can be used in stand-alone mode.
+ * Idea of this is to track atrace gfx event from graphics buffer producer/consumer.
+ * We analyze here from surfaceflinger
+ *   queueBuffer - event when buffer was queued.
+ *   acquireBuffer - event when buffer was requested for composition.
+ *   releaseBuffer - even when buffer was released after composition.
+ * This also track events, issued locally
+ *   localPostBuffer - event when buffer was posted from the local app.
+ *
+ *  queueBuffer, acquireBuffer, releaseBuffer is accompanied with buffer name so we
+ *  can track life-cycle of particular buffer.
+ *  We don't have such information for localPostBuffer, however we can track next queueBuffer
+ *  from surfaceflinger corresponds to previous localPostBuffer.
+ *
+ *  Following results are calculated:
+ *    post_time_[min/max/avr]_mcs - time for localPostBuffer duration.
+ *    ready_time_[min/max/avr]_mcs - time from localPostBuffer to when buffer was acquired by
+ *                                   surfaceflinger.
+ *    latency_[min/max/avr]_mcs - time from localPostBuffer to when buffer was released by
+ *                                 surfaceflinger.
+ *    missed_frame_percents - percentage of missed frames (frames that do not have right sequence
+ *                            of events).
+ *
+ * Following is example of atrace logs from different platforms
+ *            <...>-5237  (-----) [000] ...1   228.380392: tracing_mark_write: B|11|SurfaceView - android.gameperformance/android.gameperformance.GamePerformanceActivity#0: 2
+ *   surfaceflinger-5855  ( 5855) [001] ...1   169.627364: tracing_mark_write: B|24|acquireBuffer
+ *   HwBinder:617_2-652   (  617) [002] d..1 360262.921756: sde_evtlog: 617|sde_encoder_virt_atomic_check:855|19|0|0|0|0|0|0|0|0|0|0|0|0|0|0
+ */
+public class GraphicBufferMetrics {
+    private final static String TAG = "GraphicBufferMetrics";
+
+    private final static String KEY_POST_TIME = "post_time";
+    private final static String KEY_READY_TIME = "ready_time";
+    private final static String KEY_LATENCY = "latency";
+    private final static String SUFFIX_MIN = "min";
+    private final static String SUFFIX_MAX = "max";
+    private final static String SUFFIX_MEDIAN = "median";
+    private final static String KEY_MISSED_FRAME_RATE = "missed_frame_percents";
+
+    private final static int EVENT_POST_BUFFER = 0;
+    private final static int EVENT_QUEUE_BUFFER = 1;
+    private final static int EVENT_ACQUIRE_BUFFER = 2;
+    private final static int EVENT_RELEASE_BUFFER = 3;
+
+    // atrace prints this line. Used as a marker to make sure that we can parse its output.
+    private final static String ATRACE_HEADER =
+            "#           TASK-PID    TGID   CPU#  ||||    TIMESTAMP  FUNCTION";
+
+    private final static String[] KNOWN_PHRASES = new String[] {
+            "capturing trace... done", "TRACE:"};
+    private final static List<String> KNWON_PHRASES_LIST = Arrays.asList(KNOWN_PHRASES);
+
+    // Type of the atrace event we can parse and analyze.
+    private final static String FUNCTION_TRACING_MARK_WRITE = "tracing_mark_write";
+
+    // Trace event we can ignore. It contains current timestamp information for the atrace output.
+    private final static String TRACE_EVENT_CLOCK_SYNC = "trace_event_clock_sync:";
+
+    // Threshold we consider test passes successfully. If we cannot collect enough amount of frames
+    // let fail the test. 50 is calculated 10 frames per second running for five seconds.
+    private final static int MINIMAL_SAMPLE_CNT_TO_PASS = 50;
+
+    /**
+     * Raw event in atrace. Stored hierarchically.
+     */
+    private static class RawEvent {
+        // Parent of this event or null for the root holder.
+        public final RawEvent mParent;
+        // Time of the event in mcs.
+        public final long mTime;
+        // Duration of the event in mcs.
+        public long mDuration;
+        // Name/body of the event.
+        public final String mName;
+        // Children events.
+        public final List<RawEvent> mChildren;
+
+        public RawEvent(RawEvent parent, long time, String name) {
+            mParent = parent;
+            mTime = time;
+            mName = name;
+            mDuration = -1;
+            mChildren = new ArrayList<>();
+        }
+
+        /**
+         * Recursively finds child events.
+         * @param path specify path to events. For example a/b. That means to find child with name
+         *             'a' of the current event and in this child find child with name 'b'. Path
+         *             can consist from only one segment and that means we analyze only children of
+         *             the current event.
+         * @param collector to collect found events.
+         */
+        public void findEvents(String path, List<RawEvent> collector) {
+            final int separator = path.indexOf('/');
+            final String current = separator > 0 ? path.substring(0, separator) : path;
+            final String nextPath = separator > 0 ? path.substring(separator + 1) : null;
+            for (RawEvent child : mChildren) {
+                if (child.mName.equals(current)) {
+                    if (nextPath != null) {
+                        child.findEvents(nextPath, collector);
+                    } else {
+                        collector.add(child);
+                    }
+                }
+            }
+        }
+
+        public void dump(String prefix) {
+            System.err.print(prefix);
+            System.err.println(mTime + "[" + mDuration + "] " + mName);
+            for (RawEvent e : mChildren) {
+                e.dump(prefix + "  ");
+            }
+        }
+    }
+
+    /**
+     * Describes graphic buffer event. local post, queued, acquired, released.
+     */
+    private static class BufferEvent {
+        public final int mType;
+        public final long mTime;
+        public final long mDuration;
+        public final String mBufferId;
+
+        public BufferEvent(int type, long time, long duration, String bufferId) {
+            mType = type;
+            mTime = time;
+            mDuration = duration;
+            mBufferId = bufferId;
+        }
+
+        @Override
+        public String toString() {
+            return "Type: " + mType + ". Time: " + mTime +
+                    "[" + mDuration + "]. Buffer: " + mBufferId + ".";
+        }
+    }
+
+    /**
+     * Returns true if given char is digit.
+     */
+    private static boolean isDigitChar(char c) {
+        return (c >= '0') && (c <= '9');
+    }
+
+    /**
+     * Returns true if given char is digit or '.'.
+     */
+    private static boolean isDoubleDigitChar(char c) {
+        return (c == '.') || isDigitChar(c);
+    }
+
+    /**
+     * Convert timestamp string that represents double value in seconds to long time that represents
+     * timestamp in microseconds.
+     */
+    private static long getTimeStamp(String timeStampStr) {
+        return (long)(1000000.0 * Double.parseDouble(timeStampStr));
+    }
+
+    /**
+     * Reads atrace log and build event model. Result is a map, where key specifies event for the
+     * particular thread. Value is the synthetic root RawEvent that holds all events for the
+     * thread. Events are stored hierarchically.
+     */
+    private static Map<Integer, RawEvent> buildEventModel(String fileName) throws IOException {
+        Map<Integer, RawEvent> result = new HashMap<>();
+
+        BufferedReader bufferedReader = null;
+        String line = "";
+        boolean headerDetected = false;
+        try {
+            bufferedReader = new BufferedReader(new FileReader(fileName));
+            while ((line = bufferedReader.readLine()) != null) {
+                // Make sure we find comment that describes output format we can with.
+                headerDetected |= line.equals(ATRACE_HEADER);
+                // Skip comments.
+                if (line.startsWith("#")) {
+                    continue;
+                }
+                // Skip known service output
+                if (KNWON_PHRASES_LIST.contains(line)) {
+                    continue;
+                }
+
+                if (!headerDetected) {
+                    // We don't know the format of this line.
+                    throw new IllegalStateException("Header was not detected");
+                }
+
+                // TASK-PID in header exists at position 12. PID position 17 should contains first
+                // digit of thread id after the '-'.
+                if (!isDigitChar(line.charAt(17)) || line.charAt(16) != '-') {
+                    throw new IllegalStateException("Failed to parse thread id: " + line);
+                }
+                int rightIndex = line.indexOf(' ', 17);
+                final String threadIdStr = line.substring(17, rightIndex);
+                final int threadId = Integer.parseInt(threadIdStr);
+
+                // TIMESTAMP in header exists at position 45
+                // This position should point in the middle of timestamp which is ended by ':'.
+                int leftIndex = 45;
+                while (isDoubleDigitChar(line.charAt(leftIndex))) {
+                    --leftIndex;
+                }
+                rightIndex = line.indexOf(':', 45);
+
+                final String timeStampString = line.substring(leftIndex + 1, rightIndex);
+                final long timeStampMcs = getTimeStamp(timeStampString);
+
+                // Find function name, pointed by FUNCTION. Long timestamp can shift if position
+                // so use end of timestamp to find the function which is ended by ':'.
+                leftIndex = rightIndex + 1;
+                while (Character.isWhitespace(line.charAt(leftIndex))) {
+                    ++leftIndex;
+                }
+                rightIndex = line.indexOf(':', leftIndex);
+                final String function = line.substring(leftIndex, rightIndex);
+
+                if (!function.equals(FUNCTION_TRACING_MARK_WRITE)) {
+                    continue;
+                }
+
+                // Rest of the line is event body.
+                leftIndex = rightIndex + 1;
+                while (Character.isWhitespace(line.charAt(leftIndex))) {
+                    ++leftIndex;
+                }
+
+                final String event = line.substring(leftIndex);
+                if (event.startsWith(TRACE_EVENT_CLOCK_SYNC)) {
+                    continue;
+                }
+
+                // Parse event, for example:
+                // B|615|SurfaceView - android.gameperformance.GamePerformanceActivity#0: 1
+                // E|615
+                // C|11253|operation id|2
+                StringTokenizer eventTokenizer = new StringTokenizer(event, "|");
+                final String eventType = eventTokenizer.nextToken();
+
+                // Attach root on demand.
+                if (!result.containsKey(threadId)) {
+                    result.put(threadId, new RawEvent(null /* parent */,
+                                                      timeStampMcs,
+                                                      "#ROOT_" + threadId));
+                }
+
+                switch (eventType) {
+                case "B": {
+                        // Log entry starts.
+                        eventTokenizer.nextToken(); // PID
+                        String eventText = eventTokenizer.nextToken();
+                        while (eventTokenizer.hasMoreTokens()) {
+                            eventText += " ";
+                            eventText += eventTokenizer.nextToken();
+                        }
+                        RawEvent parent = result.get(threadId);
+                        RawEvent current = new RawEvent(parent, timeStampMcs, eventText);
+                        parent.mChildren.add(current);
+                        result.put(threadId, current);
+                    }
+                    break;
+                case "E": {
+                        // Log entry ends.
+                        RawEvent current = result.get(threadId);
+                        current.mDuration = timeStampMcs - current.mTime;
+                        if (current.mParent == null) {
+                            // Detect a tail of the previous call. Remove last child element if it
+                            // exists once it does not belong to the root.
+                            if (!current.mChildren.isEmpty()) {
+                                current.mChildren.remove(current.mChildren.size() -1);
+                            }
+                        } else {
+                            result.put(threadId, current.mParent);
+                        }
+                    }
+                    break;
+                case "C":
+                    // Counter, ignore
+                    break;
+                default:
+                    throw new IllegalStateException(
+                            "Unrecognized trace: " + line + " # " + eventType + " # " + event);
+                }
+            }
+
+            // Detect incomplete events and detach from the root.
+            Set<Integer> threadIds = new TreeSet<>();
+            threadIds.addAll(result.keySet());
+            for (int threadId : threadIds) {
+                RawEvent root = result.get(threadId);
+                if (root.mParent == null) {
+                    // Last trace was closed.
+                    continue;
+                }
+                // Find the root.
+                while (root.mParent != null) {
+                    root = root.mParent;
+                }
+                // Discard latest incomplete element.
+                root.mChildren.remove(root.mChildren.size() - 1);
+                result.put(threadId, root);
+            }
+        } catch (Exception e) {
+            throw new IOException("Failed to process " + line, e);
+        } finally {
+            Utils.closeQuietly(bufferedReader);
+        }
+
+        return result;
+    }
+
+    /**
+     * Processes provided atrace log and calculates graphics buffer metrics.
+     * @param fileName name of atrace log file.
+     * @param testTag tag to separate results for the different passes.
+     */
+    public static Map<String, Double> processGraphicBufferResult(
+            String fileName, String testTag) throws IOException {
+        final Map<Integer, RawEvent> model = buildEventModel(fileName);
+
+        List<RawEvent> collectorPostBuffer = new ArrayList<>();
+        List<RawEvent> collectorQueueBuffer = new ArrayList<>();
+        List<RawEvent> collectorReleaseBuffer = new ArrayList<>();
+        List<RawEvent> collectorAcquireBuffer = new ArrayList<>();
+
+        // Collect required events.
+        for (RawEvent root : model.values()) {
+            // Surface view
+            root.findEvents("localPostBuffer", collectorPostBuffer);
+            // OpengGL view
+            root.findEvents("eglSwapBuffersWithDamageKHR", collectorPostBuffer);
+
+            root.findEvents("queueBuffer", collectorQueueBuffer);
+            root.findEvents("onMessageReceived/handleMessageInvalidate/latchBuffer/" +
+                    "updateTexImage/acquireBuffer",
+                    collectorAcquireBuffer);
+            // PI stack
+            root.findEvents(
+                    "onMessageReceived/handleMessageRefresh/postComposition/releaseBuffer",
+                    collectorReleaseBuffer);
+            // NYC stack
+            root.findEvents(
+                    "onMessageReceived/handleMessageRefresh/releaseBuffer",
+                    collectorReleaseBuffer);
+        }
+
+        // Convert raw event to buffer events.
+        List<BufferEvent> bufferEvents = new ArrayList<>();
+        for (RawEvent event : collectorPostBuffer) {
+            bufferEvents.add(
+                    new BufferEvent(EVENT_POST_BUFFER, event.mTime, event.mDuration, null));
+        }
+        toBufferEvents(EVENT_QUEUE_BUFFER, collectorQueueBuffer, bufferEvents);
+        toBufferEvents(EVENT_ACQUIRE_BUFFER, collectorAcquireBuffer, bufferEvents);
+        toBufferEvents(EVENT_RELEASE_BUFFER, collectorReleaseBuffer, bufferEvents);
+
+        // Sort events based on time. These events are originally taken from different threads so
+        // order is not always preserved.
+        Collections.sort(bufferEvents, new Comparator<BufferEvent>() {
+            @Override
+            public int compare(BufferEvent o1, BufferEvent o2) {
+                if (o1.mTime < o2.mTime) {
+                    return -1;
+                } if (o1.mTime > o2.mTime) {
+                    return +1;
+                } else {
+                    return 0;
+                }
+            }
+        });
+
+        // Collect samples.
+        List<Long> postTimes = new ArrayList<>();
+        List<Long> readyTimes = new ArrayList<>();
+        List<Long> latencyTimes = new ArrayList<>();
+        long missedCnt = 0;
+
+        for (int i = 0; i < bufferEvents.size(); ++i) {
+            if (bufferEvents.get(i).mType != EVENT_POST_BUFFER) {
+                continue;
+            }
+            final int queueIndex = findNextOfType(bufferEvents, i + 1, EVENT_QUEUE_BUFFER);
+            if (queueIndex < 0) {
+                break;
+            }
+            final int acquireIndex = findNextOfBufferId(bufferEvents, queueIndex + 1,
+                    bufferEvents.get(queueIndex).mBufferId);
+            if (acquireIndex < 0) {
+                break;
+            }
+            if (bufferEvents.get(acquireIndex).mType != EVENT_ACQUIRE_BUFFER) {
+                // Was not actually presented.
+                ++missedCnt;
+                continue;
+            }
+            final int releaseIndex = findNextOfBufferId(bufferEvents, acquireIndex + 1,
+                    bufferEvents.get(queueIndex).mBufferId);
+            if (releaseIndex < 0) {
+                break;
+            }
+            if (bufferEvents.get(releaseIndex).mType != EVENT_RELEASE_BUFFER) {
+                // Was not actually presented.
+                ++missedCnt;
+                continue;
+            }
+
+            postTimes.add(bufferEvents.get(i).mDuration);
+            readyTimes.add(
+                    bufferEvents.get(acquireIndex).mTime - bufferEvents.get(i).mTime);
+            latencyTimes.add(
+                    bufferEvents.get(releaseIndex).mTime - bufferEvents.get(i).mTime);
+        }
+
+        if (postTimes.size() < MINIMAL_SAMPLE_CNT_TO_PASS) {
+            throw new IllegalStateException("Too few sample cnt: " + postTimes.size() +". " +
+                    MINIMAL_SAMPLE_CNT_TO_PASS + " is required.");
+        }
+
+        Map<String, Double> status = new TreeMap<>();
+        addResults(status, testTag, KEY_POST_TIME, postTimes);
+        addResults(status, testTag, KEY_READY_TIME, readyTimes);
+        addResults(status, testTag, KEY_LATENCY, latencyTimes);
+        status.put(testTag + "_" + KEY_MISSED_FRAME_RATE,
+                100.0 * missedCnt / (missedCnt + postTimes.size()));
+        return status;
+    }
+
+    private static void addResults(
+            Map<String, Double> status, String tag, String key, List<Long> times) {
+        Collections.sort(times);
+        long min = times.get(0);
+        long max = times.get(0);
+        for (long time : times) {
+            min = Math.min(min, time);
+            max = Math.max(max, time);
+        }
+        status.put(tag + "_" + key + "_" + SUFFIX_MIN, (double)min);
+        status.put(tag + "_" + key + "_" + SUFFIX_MAX, (double)max);
+        status.put(tag + "_" + key + "_" + SUFFIX_MEDIAN, (double)times.get(times.size() / 2));
+    }
+
+    // Helper to convert surface flinger events to buffer events.
+    private static void toBufferEvents(
+            int type, List<RawEvent> rawEvents, List<BufferEvent> bufferEvents) {
+        for (RawEvent event : rawEvents) {
+            if (event.mChildren.isEmpty()) {
+                throw new IllegalStateException("Buffer name is expected");
+            }
+            final String bufferName = event.mChildren.get(0).mName;
+            if (bufferName.startsWith("SurfaceView - android.gameperformance")) {
+                bufferEvents.add(
+                        new BufferEvent(type, event.mTime, event.mDuration, bufferName));
+            }
+        }
+    }
+
+    private static int findNextOfType(List<BufferEvent> events, int startIndex, int type) {
+        for (int i = startIndex; i < events.size(); ++i) {
+            if (events.get(i).mType == type) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    private static int findNextOfBufferId(
+            List<BufferEvent> events, int startIndex, String bufferId) {
+        for (int i = startIndex; i < events.size(); ++i) {
+            if (bufferId.equals(events.get(i).mBufferId)) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    public static void main(String[] args) {
+        if (args.length != 1) {
+            System.err.println("Usage: " + TAG + " atrace.log");
+            return;
+        }
+
+        try {
+            System.out.println("Results:");
+            for (Map.Entry<?, ?> entry :
+                processGraphicBufferResult(args[0], "default").entrySet()) {
+                System.out.println("    " + entry.getKey() + " = " + entry.getValue());
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+}
diff --git a/tests/GamePerformance/src/android/gameperformance/Utils.java b/tests/GamePerformance/src/android/gameperformance/Utils.java
new file mode 100644
index 0000000..6481971
--- /dev/null
+++ b/tests/GamePerformance/src/android/gameperformance/Utils.java
@@ -0,0 +1,31 @@
+/*
+ * 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.gameperformance;
+
+import java.io.Closeable;
+import java.io.IOException;
+
+public class Utils {
+    public static void closeQuietly(Closeable closeable) {
+        try {
+            if (closeable != null) {
+                closeable.close();
+            }
+        } catch (IOException e) {
+            // Ignore
+        }
+    }
+}
diff --git a/tests/TouchLatency/app/build.gradle b/tests/TouchLatency/app/build.gradle
index 2594322..04a8788 100644
--- a/tests/TouchLatency/app/build.gradle
+++ b/tests/TouchLatency/app/build.gradle
@@ -6,7 +6,7 @@
 
     defaultConfig {
         applicationId "com.prefabulated.touchlatency"
-        minSdkVersion 21
+        minSdkVersion 28
         targetSdkVersion 28
         versionCode 1
         versionName "1.0"
diff --git a/tests/TouchLatency/app/src/main/java/com/prefabulated/touchlatency/TouchLatencyActivity.java b/tests/TouchLatency/app/src/main/java/com/prefabulated/touchlatency/TouchLatencyActivity.java
index 360c22f..ba77a74 100644
--- a/tests/TouchLatency/app/src/main/java/com/prefabulated/touchlatency/TouchLatencyActivity.java
+++ b/tests/TouchLatency/app/src/main/java/com/prefabulated/touchlatency/TouchLatencyActivity.java
@@ -24,11 +24,15 @@
 import android.os.Bundle;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.view.Display;
+import android.view.Display.Mode;
 import android.view.Menu;
 import android.view.MenuItem;
 import android.view.MotionEvent;
 import android.view.View;
 import android.os.Trace;
+import android.view.Window;
+import android.view.WindowManager;
 import java.math.RoundingMode;
 import java.text.DecimalFormat;
 
@@ -219,14 +223,30 @@
 }
 
 public class TouchLatencyActivity extends Activity {
+    private Mode mDisplayModes[];
+    private int mCurrentModeIndex;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
+
         Trace.beginSection("TouchLatencyActivity onCreate");
         setContentView(R.layout.activity_touch_latency);
 
         mTouchView = findViewById(R.id.canvasView);
+
+        WindowManager wm = getWindowManager();
+        Display display = wm.getDefaultDisplay();
+        mDisplayModes = display.getSupportedModes();
+        Mode currentMode = getWindowManager().getDefaultDisplay().getMode();
+
+        for (int i = 0; i < mDisplayModes.length; i++) {
+            if (currentMode.getModeId() == mDisplayModes[i].getModeId()) {
+                mCurrentModeIndex = i;
+                break;
+            }
+        }
+
         Trace.endSection();
     }
 
@@ -236,10 +256,35 @@
         Trace.beginSection("TouchLatencyActivity onCreateOptionsMenu");
         // Inflate the menu; this adds items to the action bar if it is present.
         getMenuInflater().inflate(R.menu.menu_touch_latency, menu);
+        if (mDisplayModes.length > 1) {
+            MenuItem menuItem = menu.findItem(R.id.display_mode);
+            Mode currentMode = getWindowManager().getDefaultDisplay().getMode();
+            updateDisplayMode(menuItem, currentMode);
+        }
         Trace.endSection();
         return true;
     }
 
+
+    private void updateDisplayMode(MenuItem menuItem, Mode displayMode) {
+        int fps = (int) displayMode.getRefreshRate();
+        menuItem.setTitle(fps + "hz");
+        menuItem.setVisible(true);
+    }
+
+    public void changeDisplayMode(MenuItem item) {
+        Window w = getWindow();
+        WindowManager.LayoutParams params = w.getAttributes();
+
+        int modeIndex = (mCurrentModeIndex + 1) % mDisplayModes.length;
+        params.preferredDisplayModeId = mDisplayModes[modeIndex].getModeId();
+        w.setAttributes(params);
+
+        updateDisplayMode(item, mDisplayModes[modeIndex]);
+        mCurrentModeIndex = modeIndex;
+    }
+
+
     @Override
     public boolean onOptionsItemSelected(MenuItem item) {
         Trace.beginSection("TouchLatencyActivity onOptionsItemSelected");
@@ -251,6 +296,8 @@
         //noinspection SimplifiableIfStatement
         if (id == R.id.action_settings) {
             mTouchView.changeMode(item);
+        } else if (id == R.id.display_mode) {
+            changeDisplayMode(item);
         }
 
         Trace.endSection();
diff --git a/tests/TouchLatency/app/src/main/res/layout/activity_touch_latency.xml b/tests/TouchLatency/app/src/main/res/layout/activity_touch_latency.xml
index 8d20ff2..6257576 100644
--- a/tests/TouchLatency/app/src/main/res/layout/activity_touch_latency.xml
+++ b/tests/TouchLatency/app/src/main/res/layout/activity_touch_latency.xml
@@ -18,6 +18,7 @@
     android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
     android:paddingRight="@dimen/activity_horizontal_margin"
     android:paddingTop="@dimen/activity_vertical_margin"
+    android:keepScreenOn="true"
     android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".TouchLatencyActivity">
 
     <com.prefabulated.touchlatency.TouchLatencyView
diff --git a/tests/TouchLatency/app/src/main/res/menu/menu_touch_latency.xml b/tests/TouchLatency/app/src/main/res/menu/menu_touch_latency.xml
index 5aef72e..52be919 100644
--- a/tests/TouchLatency/app/src/main/res/menu/menu_touch_latency.xml
+++ b/tests/TouchLatency/app/src/main/res/menu/menu_touch_latency.xml
@@ -15,6 +15,14 @@
 -->
 <menu xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:tools="http://schemas.android.com/tools" tools:context=".TouchLatencyActivity">
-    <item android:id="@+id/action_settings" android:title="@string/mode"
-        android:orderInCategory="100" android:showAsAction="always" />
+    <item
+        android:id="@+id/action_settings"
+        android:orderInCategory="101"
+        android:showAsAction="always"
+        android:title="@string/mode"/>
+    <item
+        android:id="@+id/display_mode"
+        android:showAsAction="ifRoom"
+        android:title="@string/display_mode"
+        android:visible="false"/>
 </menu>
diff --git a/tests/TouchLatency/app/src/main/res/values/strings.xml b/tests/TouchLatency/app/src/main/res/values/strings.xml
index b97f095..771992c 100644
--- a/tests/TouchLatency/app/src/main/res/values/strings.xml
+++ b/tests/TouchLatency/app/src/main/res/values/strings.xml
@@ -17,4 +17,5 @@
     <string name="app_name">Touch Latency</string>
 
     <string name="mode">Touch</string>
+    <string name="display_mode">Mode</string>
 </resources>
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index 2fac8e0..0ead228 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -104,6 +104,7 @@
 import android.net.ConnectivityManager.PacketKeepaliveCallback;
 import android.net.ConnectivityManager.TooManyRequestsException;
 import android.net.ConnectivityThread;
+import android.net.IDnsResolver;
 import android.net.INetd;
 import android.net.INetworkMonitor;
 import android.net.INetworkMonitorCallbacks;
@@ -240,6 +241,7 @@
     private static final String CLAT_PREFIX = "v4-";
     private static final String MOBILE_IFNAME = "test_rmnet_data0";
     private static final String WIFI_IFNAME = "test_wlan0";
+    private static final String[] EMPTY_STRING_ARRAY = new String[0];
 
     private MockContext mServiceContext;
     private WrappedConnectivityService mService;
@@ -256,6 +258,7 @@
     @Mock INetworkManagementService mNetworkManagementService;
     @Mock INetworkStatsService mStatsService;
     @Mock INetworkPolicyManager mNpm;
+    @Mock IDnsResolver mMockDnsResolver;
     @Mock INetd mMockNetd;
     @Mock NetworkStackClient mNetworkStack;
 
@@ -1053,8 +1056,8 @@
 
         public WrappedConnectivityService(Context context, INetworkManagementService netManager,
                 INetworkStatsService statsService, INetworkPolicyManager policyManager,
-                IpConnectivityLog log, INetd netd) {
-            super(context, netManager, statsService, policyManager, log);
+                IpConnectivityLog log, INetd netd, IDnsResolver dnsResolver) {
+            super(context, netManager, statsService, policyManager, dnsResolver, log);
             mNetd = netd;
             mLingerDelayMs = TEST_LINGER_DELAY_MS;
         }
@@ -1218,7 +1221,8 @@
                 mStatsService,
                 mNpm,
                 mock(IpConnectivityLog.class),
-                mMockNetd);
+                mMockNetd,
+                mMockDnsResolver);
 
         final ArgumentCaptor<INetworkPolicyListener> policyListenerCaptor =
                 ArgumentCaptor.forClass(INetworkPolicyListener.class);
@@ -4066,8 +4070,6 @@
         // TODO: 1. Move this outside of ConnectivityServiceTest.
         //       2. Make test to verify that Nat-T keepalive socket is created by IpSecService.
         //       3. Mock ipsec service.
-        //       4. Find a free port instead of a fixed port.
-        final int srcPort = 12345;
         final InetAddress myIPv4 = InetAddress.getByName("192.0.2.129");
         final InetAddress notMyIPv4 = InetAddress.getByName("192.0.2.35");
         final InetAddress myIPv6 = InetAddress.getByName("2001:db8::1");
@@ -4078,7 +4080,8 @@
         final int invalidKaInterval = 9;
 
         final IpSecManager mIpSec = (IpSecManager) mContext.getSystemService(Context.IPSEC_SERVICE);
-        final UdpEncapsulationSocket testSocket = mIpSec.openUdpEncapsulationSocket(srcPort);
+        final UdpEncapsulationSocket testSocket = mIpSec.openUdpEncapsulationSocket();
+        final int srcPort = testSocket.getPort();
 
         LinkProperties lp = new LinkProperties();
         lp.setInterfaceName("wlan12");
@@ -4198,6 +4201,7 @@
 
         // Check that keepalive slots start from 1 and increment. The first one gets slot 1.
         mWiFiNetworkAgent.setExpectedKeepaliveSlot(1);
+        int srcPort2 = 0;
         try (SocketKeepalive ka = mCm.createSocketKeepalive(
                 myNet, testSocket, myIPv4, dstIPv4, executor, callback)) {
             ka.start(validKaInterval);
@@ -4205,7 +4209,8 @@
 
             // The second one gets slot 2.
             mWiFiNetworkAgent.setExpectedKeepaliveSlot(2);
-            final UdpEncapsulationSocket testSocket2 = mIpSec.openUdpEncapsulationSocket(6789);
+            final UdpEncapsulationSocket testSocket2 = mIpSec.openUdpEncapsulationSocket();
+            srcPort2 = testSocket2.getPort();
             TestSocketKeepaliveCallback callback2 = new TestSocketKeepaliveCallback(executor);
             try (SocketKeepalive ka2 = mCm.createSocketKeepalive(
                     myNet, testSocket2, myIPv4, dstIPv4, executor, callback2)) {
@@ -4223,6 +4228,10 @@
             }
         }
 
+        // Check that there is no port leaked after all keepalives and sockets are closed.
+        assertFalse(isUdpPortInUse(srcPort));
+        assertFalse(isUdpPortInUse(srcPort2));
+
         mWiFiNetworkAgent.disconnect();
         waitFor(mWiFiNetworkAgent.getDisconnectedCV());
         mWiFiNetworkAgent = null;
@@ -4305,7 +4314,6 @@
     }
 
     private void doTestNattSocketKeepalivesFdWithExecutor(Executor executor) throws Exception {
-        final int srcPort = 12345;
         final InetAddress myIPv4 = InetAddress.getByName("192.0.2.129");
         final InetAddress anyIPv4 = InetAddress.getByName("0.0.0.0");
         final InetAddress dstIPv4 = InetAddress.getByName("8.8.8.8");
@@ -4324,7 +4332,8 @@
 
         // Prepare the target file descriptor, keep only one instance.
         final IpSecManager mIpSec = (IpSecManager) mContext.getSystemService(Context.IPSEC_SERVICE);
-        final UdpEncapsulationSocket testSocket = mIpSec.openUdpEncapsulationSocket(srcPort);
+        final UdpEncapsulationSocket testSocket = mIpSec.openUdpEncapsulationSocket();
+        final int srcPort = testSocket.getPort();
         final ParcelFileDescriptor testPfd =
                 ParcelFileDescriptor.dup(testSocket.getFileDescriptor());
         testSocket.close();
@@ -4772,14 +4781,14 @@
         ArgumentCaptor<String[]> tlsServers = ArgumentCaptor.forClass(String[].class);
 
         // Clear any interactions that occur as a result of CS starting up.
-        reset(mNetworkManagementService);
+        reset(mMockDnsResolver);
 
-        final String[] EMPTY_STRING_ARRAY = new String[0];
         mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
         waitForIdle();
-        verify(mNetworkManagementService, never()).setDnsConfigurationForNetwork(
-                anyInt(), eq(EMPTY_STRING_ARRAY), any(), any(), eq(""), eq(EMPTY_STRING_ARRAY));
-        verifyNoMoreInteractions(mNetworkManagementService);
+        verify(mMockDnsResolver, never()).setResolverConfiguration(
+                anyInt(), eq(EMPTY_STRING_ARRAY), any(), any(), eq(""),
+                eq(EMPTY_STRING_ARRAY), eq(EMPTY_STRING_ARRAY));
+        verifyNoMoreInteractions(mMockDnsResolver);
 
         final LinkProperties cellLp = new LinkProperties();
         cellLp.setInterfaceName(MOBILE_IFNAME);
@@ -4796,28 +4805,29 @@
         mCellNetworkAgent.connect(false);
         waitForIdle();
         // CS tells netd about the empty DNS config for this network.
-        verify(mNetworkManagementService, atLeastOnce()).setDnsConfigurationForNetwork(
-                anyInt(), eq(EMPTY_STRING_ARRAY), any(), any(), eq(""), eq(EMPTY_STRING_ARRAY));
-        reset(mNetworkManagementService);
+        verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(
+                anyInt(), eq(EMPTY_STRING_ARRAY), any(), any(), eq(""),
+                eq(EMPTY_STRING_ARRAY), eq(EMPTY_STRING_ARRAY));
+        reset(mMockDnsResolver);
 
         cellLp.addDnsServer(InetAddress.getByName("2001:db8::1"));
         mCellNetworkAgent.sendLinkProperties(cellLp);
         waitForIdle();
-        verify(mNetworkManagementService, atLeastOnce()).setDnsConfigurationForNetwork(
+        verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(
                 anyInt(), mStringArrayCaptor.capture(), any(), any(),
-                eq(""), tlsServers.capture());
+                eq(""), tlsServers.capture(), eq(EMPTY_STRING_ARRAY));
         assertEquals(1, mStringArrayCaptor.getValue().length);
         assertTrue(ArrayUtils.contains(mStringArrayCaptor.getValue(), "2001:db8::1"));
         // Opportunistic mode.
         assertTrue(ArrayUtils.contains(tlsServers.getValue(), "2001:db8::1"));
-        reset(mNetworkManagementService);
+        reset(mMockDnsResolver);
 
         cellLp.addDnsServer(InetAddress.getByName("192.0.2.1"));
         mCellNetworkAgent.sendLinkProperties(cellLp);
         waitForIdle();
-        verify(mNetworkManagementService, atLeastOnce()).setDnsConfigurationForNetwork(
+        verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(
                 anyInt(), mStringArrayCaptor.capture(), any(), any(),
-                eq(""), tlsServers.capture());
+                eq(""), tlsServers.capture(), eq(EMPTY_STRING_ARRAY));
         assertEquals(2, mStringArrayCaptor.getValue().length);
         assertTrue(ArrayUtils.containsAll(mStringArrayCaptor.getValue(),
                 new String[]{"2001:db8::1", "192.0.2.1"}));
@@ -4825,7 +4835,7 @@
         assertEquals(2, tlsServers.getValue().length);
         assertTrue(ArrayUtils.containsAll(tlsServers.getValue(),
                 new String[]{"2001:db8::1", "192.0.2.1"}));
-        reset(mNetworkManagementService);
+        reset(mMockDnsResolver);
 
         final String TLS_SPECIFIER = "tls.example.com";
         final String TLS_SERVER6 = "2001:db8:53::53";
@@ -4835,22 +4845,21 @@
                 new PrivateDnsConfig(TLS_SPECIFIER, TLS_IPS).toParcel());
 
         waitForIdle();
-        verify(mNetworkManagementService, atLeastOnce()).setDnsConfigurationForNetwork(
+        verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(
                 anyInt(), mStringArrayCaptor.capture(), any(), any(),
-                eq(TLS_SPECIFIER), eq(TLS_SERVERS));
+                eq(TLS_SPECIFIER), eq(TLS_SERVERS), eq(EMPTY_STRING_ARRAY));
         assertEquals(2, mStringArrayCaptor.getValue().length);
         assertTrue(ArrayUtils.containsAll(mStringArrayCaptor.getValue(),
                 new String[]{"2001:db8::1", "192.0.2.1"}));
-        reset(mNetworkManagementService);
+        reset(mMockDnsResolver);
     }
 
     @Test
     public void testPrivateDnsSettingsChange() throws Exception {
-        final String[] EMPTY_STRING_ARRAY = new String[0];
         ArgumentCaptor<String[]> tlsServers = ArgumentCaptor.forClass(String[].class);
 
         // Clear any interactions that occur as a result of CS starting up.
-        reset(mNetworkManagementService);
+        reset(mMockDnsResolver);
 
         // The default on Android is opportunistic mode ("Automatic").
         setPrivateDnsSettings(PRIVATE_DNS_MODE_OPPORTUNISTIC, "ignored.example.com");
@@ -4863,9 +4872,10 @@
         mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
         waitForIdle();
         // CS tells netd about the empty DNS config for this network.
-        verify(mNetworkManagementService, never()).setDnsConfigurationForNetwork(
-                anyInt(), eq(EMPTY_STRING_ARRAY), any(), any(), eq(""), eq(EMPTY_STRING_ARRAY));
-        verifyNoMoreInteractions(mNetworkManagementService);
+        verify(mMockDnsResolver, never()).setResolverConfiguration(
+                anyInt(), eq(EMPTY_STRING_ARRAY), any(), any(), eq(""),
+                eq(EMPTY_STRING_ARRAY), eq(EMPTY_STRING_ARRAY));
+        verifyNoMoreInteractions(mMockDnsResolver);
 
         final LinkProperties cellLp = new LinkProperties();
         cellLp.setInterfaceName(MOBILE_IFNAME);
@@ -4884,9 +4894,9 @@
         mCellNetworkAgent.sendLinkProperties(cellLp);
         mCellNetworkAgent.connect(false);
         waitForIdle();
-        verify(mNetworkManagementService, atLeastOnce()).setDnsConfigurationForNetwork(
+        verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(
                 anyInt(), mStringArrayCaptor.capture(), any(), any(),
-                eq(""), tlsServers.capture());
+                eq(""), tlsServers.capture(), eq(EMPTY_STRING_ARRAY));
         assertEquals(2, mStringArrayCaptor.getValue().length);
         assertTrue(ArrayUtils.containsAll(mStringArrayCaptor.getValue(),
                 new String[]{"2001:db8::1", "192.0.2.1"}));
@@ -4894,7 +4904,7 @@
         assertEquals(2, tlsServers.getValue().length);
         assertTrue(ArrayUtils.containsAll(tlsServers.getValue(),
                 new String[]{"2001:db8::1", "192.0.2.1"}));
-        reset(mNetworkManagementService);
+        reset(mMockDnsResolver);
         cellNetworkCallback.expectCallback(CallbackState.AVAILABLE, mCellNetworkAgent);
         cellNetworkCallback.expectCallback(CallbackState.NETWORK_CAPABILITIES,
                 mCellNetworkAgent);
@@ -4906,26 +4916,26 @@
         assertNull(((LinkProperties)cbi.arg).getPrivateDnsServerName());
 
         setPrivateDnsSettings(PRIVATE_DNS_MODE_OFF, "ignored.example.com");
-        verify(mNetworkManagementService, times(1)).setDnsConfigurationForNetwork(
+        verify(mMockDnsResolver, times(1)).setResolverConfiguration(
                 anyInt(), mStringArrayCaptor.capture(), any(), any(),
-                eq(""), eq(EMPTY_STRING_ARRAY));
+                eq(""), eq(EMPTY_STRING_ARRAY), eq(EMPTY_STRING_ARRAY));
         assertEquals(2, mStringArrayCaptor.getValue().length);
         assertTrue(ArrayUtils.containsAll(mStringArrayCaptor.getValue(),
                 new String[]{"2001:db8::1", "192.0.2.1"}));
-        reset(mNetworkManagementService);
+        reset(mMockDnsResolver);
         cellNetworkCallback.assertNoCallback();
 
         setPrivateDnsSettings(PRIVATE_DNS_MODE_OPPORTUNISTIC, "ignored.example.com");
-        verify(mNetworkManagementService, atLeastOnce()).setDnsConfigurationForNetwork(
+        verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(
                 anyInt(), mStringArrayCaptor.capture(), any(), any(),
-                eq(""), tlsServers.capture());
+                eq(""), tlsServers.capture(), eq(EMPTY_STRING_ARRAY));
         assertEquals(2, mStringArrayCaptor.getValue().length);
         assertTrue(ArrayUtils.containsAll(mStringArrayCaptor.getValue(),
                 new String[]{"2001:db8::1", "192.0.2.1"}));
         assertEquals(2, tlsServers.getValue().length);
         assertTrue(ArrayUtils.containsAll(tlsServers.getValue(),
                 new String[]{"2001:db8::1", "192.0.2.1"}));
-        reset(mNetworkManagementService);
+        reset(mMockDnsResolver);
         cellNetworkCallback.assertNoCallback();
 
         setPrivateDnsSettings(PRIVATE_DNS_MODE_PROVIDER_HOSTNAME, "strict.example.com");
@@ -5756,6 +5766,7 @@
         cellLp.addRoute(new RouteInfo((IpPrefix) null, myIpv6.getAddress(), MOBILE_IFNAME));
         cellLp.addRoute(new RouteInfo(myIpv6, null, MOBILE_IFNAME));
         reset(mNetworkManagementService);
+        reset(mMockDnsResolver);
         when(mNetworkManagementService.getInterfaceConfig(CLAT_PREFIX + MOBILE_IFNAME))
                 .thenReturn(getClatInterfaceConfig(myIpv4));
 
@@ -5763,7 +5774,7 @@
         mCellNetworkAgent.sendLinkProperties(cellLp);
         mCellNetworkAgent.connect(true);
         networkCallback.expectAvailableThenValidatedCallbacks(mCellNetworkAgent);
-        verify(mMockNetd, times(1)).resolverStartPrefix64Discovery(cellNetId);
+        verify(mMockDnsResolver, times(1)).startPrefix64Discovery(cellNetId);
 
         // Switching default network updates TCP buffer sizes.
         verifyTcpBufferSizeChange(ConnectivityService.DEFAULT_TCP_BUFFER_SIZES);
@@ -5773,17 +5784,22 @@
         cellLp.addLinkAddress(myIpv4);
         mCellNetworkAgent.sendLinkProperties(cellLp);
         networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
-        verify(mMockNetd, times(1)).resolverStopPrefix64Discovery(cellNetId);
+        verify(mMockDnsResolver, times(1)).stopPrefix64Discovery(cellNetId);
+        verify(mMockDnsResolver, atLeastOnce()).setResolverConfiguration(
+                eq(cellNetId), eq(EMPTY_STRING_ARRAY), any(), any(),
+                eq(""), eq(EMPTY_STRING_ARRAY), eq(EMPTY_STRING_ARRAY));
 
         verifyNoMoreInteractions(mMockNetd);
+        verifyNoMoreInteractions(mMockDnsResolver);
         reset(mMockNetd);
+        reset(mMockDnsResolver);
 
         // Remove IPv4 address. Expect prefix discovery to be started again.
         cellLp.removeLinkAddress(myIpv4);
         cellLp.removeRoute(new RouteInfo(myIpv4, null, MOBILE_IFNAME));
         mCellNetworkAgent.sendLinkProperties(cellLp);
         networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
-        verify(mMockNetd, times(1)).resolverStartPrefix64Discovery(cellNetId);
+        verify(mMockDnsResolver, times(1)).startPrefix64Discovery(cellNetId);
 
         // When NAT64 prefix discovery succeeds, LinkProperties are updated and clatd is started.
         Nat464Xlat clat = mService.getNat464Xlat(mCellNetworkAgent);
@@ -5813,6 +5829,12 @@
         assertNotEquals(stackedLpsAfterChange, Collections.EMPTY_LIST);
         assertEquals(makeClatLinkProperties(myIpv4), stackedLpsAfterChange.get(0));
 
+        verify(mMockDnsResolver, times(1)).setResolverConfiguration(
+                eq(cellNetId), mStringArrayCaptor.capture(), any(), any(),
+                eq(""), eq(EMPTY_STRING_ARRAY), eq(EMPTY_STRING_ARRAY));
+        assertEquals(1, mStringArrayCaptor.getValue().length);
+        assertTrue(ArrayUtils.contains(mStringArrayCaptor.getValue(), "8.8.8.8"));
+
         // Add ipv4 address, expect that clatd and prefix discovery are stopped and stacked
         // linkproperties are cleaned up.
         cellLp.addLinkAddress(myIpv4);
@@ -5820,7 +5842,7 @@
         mCellNetworkAgent.sendLinkProperties(cellLp);
         networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
         verify(mMockNetd, times(1)).clatdStop(MOBILE_IFNAME);
-        verify(mMockNetd, times(1)).resolverStopPrefix64Discovery(cellNetId);
+        verify(mMockDnsResolver, times(1)).stopPrefix64Discovery(cellNetId);
 
         // As soon as stop is called, the linkproperties lose the stacked interface.
         networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
@@ -5835,7 +5857,9 @@
         networkCallback.assertNoCallback();
 
         verifyNoMoreInteractions(mMockNetd);
+        verifyNoMoreInteractions(mMockDnsResolver);
         reset(mMockNetd);
+        reset(mMockDnsResolver);
 
         // Stopping prefix discovery causes netd to tell us that the NAT64 prefix is gone.
         mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, false /* added */,
@@ -5849,7 +5873,7 @@
         cellLp.removeDnsServer(InetAddress.getByName("8.8.8.8"));
         mCellNetworkAgent.sendLinkProperties(cellLp);
         networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
-        verify(mMockNetd, times(1)).resolverStartPrefix64Discovery(cellNetId);
+        verify(mMockDnsResolver, times(1)).startPrefix64Discovery(cellNetId);
         mService.mNetdEventCallback.onNat64PrefixEvent(cellNetId, true /* added */,
                 kNat64PrefixString, 96);
         networkCallback.expectCallback(CallbackState.LINK_PROPERTIES, mCellNetworkAgent);
@@ -5932,6 +5956,7 @@
 
         // Disconnect cell
         reset(mNetworkManagementService);
+        reset(mMockNetd);
         mCellNetworkAgent.disconnect();
         networkCallback.expectCallback(CallbackState.LOST, mCellNetworkAgent);
         // LOST callback is triggered earlier than removing idle timer. Broadcast should also be
@@ -5939,8 +5964,9 @@
         // unexpectedly before network being removed.
         waitForIdle();
         verify(mNetworkManagementService, times(0)).removeIdleTimer(eq(MOBILE_IFNAME));
-        verify(mNetworkManagementService, times(1)).removeNetwork(
-                eq(mCellNetworkAgent.getNetwork().netId));
+        verify(mMockNetd, times(1)).networkDestroy(eq(mCellNetworkAgent.getNetwork().netId));
+        verify(mMockDnsResolver, times(1))
+                .clearResolverConfiguration(eq(mCellNetworkAgent.getNetwork().netId));
 
         // Disconnect wifi
         ConditionVariable cv = waitForConnectivityBroadcasts(1);
diff --git a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java b/tests/net/java/com/android/server/connectivity/DnsManagerTest.java
index 15ba43d..8fa0ab9 100644
--- a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java
+++ b/tests/net/java/com/android/server/connectivity/DnsManagerTest.java
@@ -29,13 +29,13 @@
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
+import android.net.IDnsResolver;
 import android.net.IpPrefix;
 import android.net.LinkAddress;
 import android.net.LinkProperties;
 import android.net.Network;
 import android.net.RouteInfo;
 import android.net.shared.PrivateDnsConfig;
-import android.os.INetworkManagementService;
 import android.provider.Settings;
 import android.test.mock.MockContentResolver;
 
@@ -73,7 +73,7 @@
     MockContentResolver mContentResolver;
 
     @Mock Context mCtx;
-    @Mock INetworkManagementService mNMService;
+    @Mock IDnsResolver mMockDnsResolver;
     @Mock MockableSystemProperties mSystemProperties;
 
     @Before
@@ -83,7 +83,7 @@
         mContentResolver.addProvider(Settings.AUTHORITY,
                 new FakeSettingsProvider());
         when(mCtx.getContentResolver()).thenReturn(mContentResolver);
-        mDnsManager = new DnsManager(mCtx, mNMService, mSystemProperties);
+        mDnsManager = new DnsManager(mCtx, mMockDnsResolver, mSystemProperties);
 
         // Clear the private DNS settings
         Settings.Global.putString(mContentResolver, PRIVATE_DNS_DEFAULT_MODE, "");
diff --git a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
index 6de4aa1..142769f 100644
--- a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
@@ -32,6 +32,7 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.net.ConnectivityManager;
+import android.net.IDnsResolver;
 import android.net.INetd;
 import android.net.Network;
 import android.net.NetworkCapabilities;
@@ -69,6 +70,7 @@
     LingerMonitor mMonitor;
 
     @Mock ConnectivityService mConnService;
+    @Mock IDnsResolver mDnsResolver;
     @Mock INetd mNetd;
     @Mock INetworkManagementService mNMS;
     @Mock Context mCtx;
@@ -353,7 +355,7 @@
         caps.addCapability(0);
         caps.addTransportType(transport);
         NetworkAgentInfo nai = new NetworkAgentInfo(null, null, new Network(netId), info, null,
-                caps, 50, mCtx, null, mMisc, mConnService, mNetd, mNMS,
+                caps, 50, mCtx, null, mMisc, mConnService, mNetd, mDnsResolver, mNMS,
                 NetworkFactory.SerialNumber.NONE);
         nai.everValidated = true;
         return nai;
diff --git a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java b/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
index cc09fb7..b709af1 100644
--- a/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
+++ b/tests/net/java/com/android/server/connectivity/Nat464XlatTest.java
@@ -27,6 +27,7 @@
 import static org.mockito.Mockito.when;
 
 import android.net.ConnectivityManager;
+import android.net.IDnsResolver;
 import android.net.INetd;
 import android.net.InterfaceConfiguration;
 import android.net.IpPrefix;
@@ -63,6 +64,7 @@
 
     @Mock ConnectivityService mConnectivity;
     @Mock NetworkMisc mMisc;
+    @Mock IDnsResolver mDnsResolver;
     @Mock INetd mNetd;
     @Mock INetworkManagementService mNms;
     @Mock InterfaceConfiguration mConfig;
@@ -72,7 +74,7 @@
     Handler mHandler;
 
     Nat464Xlat makeNat464Xlat() {
-        return new Nat464Xlat(mNai, mNetd, mNms) {
+        return new Nat464Xlat(mNai, mNetd, mDnsResolver, mNms) {
             @Override protected int getNetId() {
                 return NETID;
             }
@@ -205,7 +207,7 @@
         verify(mNms).unregisterObserver(eq(nat));
         assertTrue(c.getValue().getStackedLinks().isEmpty());
         assertFalse(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
-        verify(mNetd).resolverStopPrefix64Discovery(eq(NETID));
+        verify(mDnsResolver).stopPrefix64Discovery(eq(NETID));
         assertIdle(nat);
 
         // Stacked interface removed notification arrives and is ignored.
@@ -331,7 +333,7 @@
         verify(mNetd).clatdStop(eq(BASE_IFACE));
         verify(mConnectivity, times(2)).handleUpdateLinkProperties(eq(mNai), c.capture());
         verify(mNms).unregisterObserver(eq(nat));
-        verify(mNetd).resolverStopPrefix64Discovery(eq(NETID));
+        verify(mDnsResolver).stopPrefix64Discovery(eq(NETID));
         assertTrue(c.getValue().getStackedLinks().isEmpty());
         assertFalse(c.getValue().getAllInterfaceNames().contains(STACKED_IFACE));
         assertIdle(nat);
@@ -358,7 +360,7 @@
 
         verify(mNetd).clatdStop(eq(BASE_IFACE));
         verify(mNms).unregisterObserver(eq(nat));
-        verify(mNetd).resolverStopPrefix64Discovery(eq(NETID));
+        verify(mDnsResolver).stopPrefix64Discovery(eq(NETID));
         assertIdle(nat);
 
         // In-flight interface up notification arrives: no-op
@@ -390,7 +392,7 @@
 
         verify(mNetd).clatdStop(eq(BASE_IFACE));
         verify(mNms).unregisterObserver(eq(nat));
-        verify(mNetd).resolverStopPrefix64Discovery(eq(NETID));
+        verify(mDnsResolver).stopPrefix64Discovery(eq(NETID));
         assertIdle(nat);
 
         verifyNoMoreInteractions(mNetd, mNms, mConnectivity);
diff --git a/tests/net/java/com/android/server/connectivity/tethering/EntitlementManagerTest.java b/tests/net/java/com/android/server/connectivity/tethering/EntitlementManagerTest.java
index bac5098..d28ab70 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/EntitlementManagerTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/EntitlementManagerTest.java
@@ -16,6 +16,7 @@
 
 package com.android.server.connectivity.tethering;
 
+import static android.net.ConnectivityManager.TETHERING_BLUETOOTH;
 import static android.net.ConnectivityManager.TETHERING_USB;
 import static android.net.ConnectivityManager.TETHERING_WIFI;
 import static android.net.ConnectivityManager.TETHER_ERROR_ENTITLEMENT_UNKONWN;
@@ -30,6 +31,8 @@
 import static org.mockito.Matchers.anyBoolean;
 import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.content.ContentResolver;
@@ -72,12 +75,14 @@
 
     private static final int EVENT_EM_UPDATE = 1;
     private static final String[] PROVISIONING_APP_NAME = {"some", "app"};
+    private static final String PROVISIONING_NO_UI_APP_NAME = "no_ui_app";
 
     @Mock private CarrierConfigManager mCarrierConfigManager;
     @Mock private Context mContext;
     @Mock private MockableSystemProperties mSystemProperties;
     @Mock private Resources mResources;
     @Mock private SharedLog mLog;
+    @Mock private EntitlementManager.OnUiEntitlementFailedListener mEntitlementFailedListener;
 
     // Like so many Android system APIs, these cannot be mocked because it is marked final.
     // We have to use the real versions.
@@ -107,18 +112,31 @@
 
     public class WrappedEntitlementManager extends EntitlementManager {
         public int fakeEntitlementResult = TETHER_ERROR_ENTITLEMENT_UNKONWN;
-        public boolean everRunUiEntitlement = false;
+        public int uiProvisionCount = 0;
+        public int silentProvisionCount = 0;
 
         public WrappedEntitlementManager(Context ctx, StateMachine target,
-                SharedLog log, MockableSystemProperties systemProperties) {
-            super(ctx, target, log, systemProperties);
+                SharedLog log, int what, MockableSystemProperties systemProperties) {
+            super(ctx, target, log, what, systemProperties);
+        }
+
+        public void reset() {
+            fakeEntitlementResult = TETHER_ERROR_ENTITLEMENT_UNKONWN;
+            uiProvisionCount = 0;
+            silentProvisionCount = 0;
         }
 
         @Override
         protected void runUiTetherProvisioning(int type, ResultReceiver receiver) {
-            everRunUiEntitlement = true;
+            uiProvisionCount++;
             receiver.send(fakeEntitlementResult, null);
         }
+
+        @Override
+        protected void runSilentTetherProvisioning(int type) {
+            silentProvisionCount++;
+            addDownstreamMapping(type, fakeEntitlementResult);
+        }
     }
 
     @Before
@@ -141,7 +159,9 @@
         mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
         mMockContext = new MockContext(mContext);
         mSM = new TestStateMachine();
-        mEnMgr = new WrappedEntitlementManager(mMockContext, mSM, mLog, mSystemProperties);
+        mEnMgr = new WrappedEntitlementManager(mMockContext, mSM, mLog, EVENT_EM_UPDATE,
+                mSystemProperties);
+        mEnMgr.setOnUiEntitlementFailedListener(mEntitlementFailedListener);
         mEnMgr.updateConfiguration(
                 new TetheringConfiguration(mMockContext, mLog, INVALID_SUBSCRIPTION_ID));
     }
@@ -158,7 +178,9 @@
         // Produce some acceptable looking provision app setting if requested.
         when(mResources.getStringArray(R.array.config_mobile_hotspot_provision_app))
                 .thenReturn(PROVISIONING_APP_NAME);
-        // Don't disable tethering provisioning unless requested.
+        when(mResources.getString(R.string.config_mobile_hotspot_provision_app_no_ui))
+                .thenReturn(PROVISIONING_NO_UI_APP_NAME);
+       // Don't disable tethering provisioning unless requested.
         when(mSystemProperties.getBoolean(eq(EntitlementManager.DISABLE_PROVISIONING_SYSPROP_KEY),
                 anyBoolean())).thenReturn(false);
         // Act like the CarrierConfigManager is present and ready unless told otherwise.
@@ -229,7 +251,6 @@
         final CountDownLatch mCallbacklatch = new CountDownLatch(1);
         // 1. Entitlement check is not required.
         mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
-        mEnMgr.everRunUiEntitlement = false;
         ResultReceiver receiver = new ResultReceiver(null) {
             @Override
             protected void onReceiveResult(int resultCode, Bundle resultData) {
@@ -238,14 +259,15 @@
             }
         };
         mEnMgr.getLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, true);
+        mLooper.dispatchAll();
         callbackTimeoutHelper(mCallbacklatch);
-        assertFalse(mEnMgr.everRunUiEntitlement);
+        assertEquals(0, mEnMgr.uiProvisionCount);
+        mEnMgr.reset();
 
         setupForRequiredProvisioning();
         mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog,
                   INVALID_SUBSCRIPTION_ID));
         // 2. No cache value and don't need to run entitlement check.
-        mEnMgr.everRunUiEntitlement = false;
         receiver = new ResultReceiver(null) {
             @Override
             protected void onReceiveResult(int resultCode, Bundle resultData) {
@@ -254,11 +276,12 @@
             }
         };
         mEnMgr.getLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, false);
+        mLooper.dispatchAll();
         callbackTimeoutHelper(mCallbacklatch);
-        assertFalse(mEnMgr.everRunUiEntitlement);
+        assertEquals(0, mEnMgr.uiProvisionCount);
+        mEnMgr.reset();
         // 3. No cache value and ui entitlement check is needed.
         mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISION_FAILED;
-        mEnMgr.everRunUiEntitlement = false;
         receiver = new ResultReceiver(null) {
             @Override
             protected void onReceiveResult(int resultCode, Bundle resultData) {
@@ -269,10 +292,10 @@
         mEnMgr.getLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, true);
         mLooper.dispatchAll();
         callbackTimeoutHelper(mCallbacklatch);
-        assertTrue(mEnMgr.everRunUiEntitlement);
+        assertEquals(1, mEnMgr.uiProvisionCount);
+        mEnMgr.reset();
         // 4. Cache value is TETHER_ERROR_PROVISION_FAILED and don't need to run entitlement check.
         mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
-        mEnMgr.everRunUiEntitlement = false;
         receiver = new ResultReceiver(null) {
             @Override
             protected void onReceiveResult(int resultCode, Bundle resultData) {
@@ -281,11 +304,12 @@
             }
         };
         mEnMgr.getLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, false);
+        mLooper.dispatchAll();
         callbackTimeoutHelper(mCallbacklatch);
-        assertFalse(mEnMgr.everRunUiEntitlement);
+        assertEquals(0, mEnMgr.uiProvisionCount);
+        mEnMgr.reset();
         // 5. Cache value is TETHER_ERROR_PROVISION_FAILED and ui entitlement check is needed.
         mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
-        mEnMgr.everRunUiEntitlement = false;
         receiver = new ResultReceiver(null) {
             @Override
             protected void onReceiveResult(int resultCode, Bundle resultData) {
@@ -296,10 +320,10 @@
         mEnMgr.getLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, true);
         mLooper.dispatchAll();
         callbackTimeoutHelper(mCallbacklatch);
-        assertTrue(mEnMgr.everRunUiEntitlement);
+        assertEquals(1, mEnMgr.uiProvisionCount);
+        mEnMgr.reset();
         // 6. Cache value is TETHER_ERROR_NO_ERROR.
         mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
-        mEnMgr.everRunUiEntitlement = false;
         receiver = new ResultReceiver(null) {
             @Override
             protected void onReceiveResult(int resultCode, Bundle resultData) {
@@ -308,10 +332,11 @@
             }
         };
         mEnMgr.getLatestTetheringEntitlementResult(TETHERING_WIFI, receiver, true);
+        mLooper.dispatchAll();
         callbackTimeoutHelper(mCallbacklatch);
-        assertFalse(mEnMgr.everRunUiEntitlement);
+        assertEquals(0, mEnMgr.uiProvisionCount);
+        mEnMgr.reset();
         // 7. Test get value for other downstream type.
-        mEnMgr.everRunUiEntitlement = false;
         receiver = new ResultReceiver(null) {
             @Override
             protected void onReceiveResult(int resultCode, Bundle resultData) {
@@ -320,19 +345,152 @@
             }
         };
         mEnMgr.getLatestTetheringEntitlementResult(TETHERING_USB, receiver, false);
+        mLooper.dispatchAll();
         callbackTimeoutHelper(mCallbacklatch);
-        assertFalse(mEnMgr.everRunUiEntitlement);
+        assertEquals(0, mEnMgr.uiProvisionCount);
+        mEnMgr.reset();
     }
 
     void callbackTimeoutHelper(final CountDownLatch latch) throws Exception {
         if (!latch.await(1, TimeUnit.SECONDS)) {
-            fail("Timout, fail to recieve callback");
+            fail("Timout, fail to receive callback");
         }
     }
+
+    @Test
+    public void verifyPermissionResult() {
+        setupForRequiredProvisioning();
+        mEnMgr.notifyUpstream(true);
+        mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog,
+                  INVALID_SUBSCRIPTION_ID));
+        mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISION_FAILED;
+        mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true);
+        mLooper.dispatchAll();
+        assertFalse(mEnMgr.isCellularUpstreamPermitted());
+        mEnMgr.stopProvisioningIfNeeded(TETHERING_WIFI);
+        mLooper.dispatchAll();
+        mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
+        mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true);
+        mLooper.dispatchAll();
+        assertTrue(mEnMgr.isCellularUpstreamPermitted());
+    }
+
+    @Test
+    public void verifyPermissionIfAllNotApproved() {
+        setupForRequiredProvisioning();
+        mEnMgr.notifyUpstream(true);
+        mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog,
+                  INVALID_SUBSCRIPTION_ID));
+        mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISION_FAILED;
+        mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true);
+        mLooper.dispatchAll();
+        assertFalse(mEnMgr.isCellularUpstreamPermitted());
+        mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISION_FAILED;
+        mEnMgr.startProvisioningIfNeeded(TETHERING_USB, true);
+        mLooper.dispatchAll();
+        assertFalse(mEnMgr.isCellularUpstreamPermitted());
+        mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISION_FAILED;
+        mEnMgr.startProvisioningIfNeeded(TETHERING_BLUETOOTH, true);
+        mLooper.dispatchAll();
+        assertFalse(mEnMgr.isCellularUpstreamPermitted());
+    }
+
+    @Test
+    public void verifyPermissionIfAnyApproved() {
+        setupForRequiredProvisioning();
+        mEnMgr.notifyUpstream(true);
+        mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog,
+                  INVALID_SUBSCRIPTION_ID));
+        mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
+        mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true);
+        mLooper.dispatchAll();
+        assertTrue(mEnMgr.isCellularUpstreamPermitted());
+        mLooper.dispatchAll();
+        mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISION_FAILED;
+        mEnMgr.startProvisioningIfNeeded(TETHERING_USB, true);
+        mLooper.dispatchAll();
+        assertTrue(mEnMgr.isCellularUpstreamPermitted());
+        mEnMgr.stopProvisioningIfNeeded(TETHERING_WIFI);
+        mLooper.dispatchAll();
+        assertFalse(mEnMgr.isCellularUpstreamPermitted());
+
+    }
+
+    @Test
+    public void testRunTetherProvisioning() {
+        setupForRequiredProvisioning();
+        mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog,
+                INVALID_SUBSCRIPTION_ID));
+        // 1. start ui provisioning, upstream is mobile
+        mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
+        mEnMgr.notifyUpstream(true);
+        mLooper.dispatchAll();
+        mEnMgr.startProvisioningIfNeeded(TETHERING_USB, true);
+        mLooper.dispatchAll();
+        assertEquals(1, mEnMgr.uiProvisionCount);
+        assertEquals(0, mEnMgr.silentProvisionCount);
+        assertTrue(mEnMgr.isCellularUpstreamPermitted());
+        mEnMgr.reset();
+        // 2. start no-ui provisioning
+        mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
+        mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, false);
+        mLooper.dispatchAll();
+        assertEquals(0, mEnMgr.uiProvisionCount);
+        assertEquals(1, mEnMgr.silentProvisionCount);
+        assertTrue(mEnMgr.isCellularUpstreamPermitted());
+        mEnMgr.reset();
+        // 3. tear down mobile, then start ui provisioning
+        mEnMgr.notifyUpstream(false);
+        mLooper.dispatchAll();
+        mEnMgr.startProvisioningIfNeeded(TETHERING_BLUETOOTH, true);
+        mLooper.dispatchAll();
+        assertEquals(0, mEnMgr.uiProvisionCount);
+        assertEquals(0, mEnMgr.silentProvisionCount);
+        mEnMgr.reset();
+        // 4. switch upstream back to mobile
+        mEnMgr.fakeEntitlementResult = TETHER_ERROR_NO_ERROR;
+        mEnMgr.notifyUpstream(true);
+        mLooper.dispatchAll();
+        assertEquals(1, mEnMgr.uiProvisionCount);
+        assertEquals(0, mEnMgr.silentProvisionCount);
+        assertTrue(mEnMgr.isCellularUpstreamPermitted());
+        mEnMgr.reset();
+        // 5. tear down mobile, then switch SIM
+        mEnMgr.notifyUpstream(false);
+        mLooper.dispatchAll();
+        mEnMgr.reevaluateSimCardProvisioning();
+        assertEquals(0, mEnMgr.uiProvisionCount);
+        assertEquals(0, mEnMgr.silentProvisionCount);
+        mEnMgr.reset();
+        // 6. switch upstream back to mobile again
+        mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISION_FAILED;
+        mEnMgr.notifyUpstream(true);
+        mLooper.dispatchAll();
+        assertEquals(0, mEnMgr.uiProvisionCount);
+        assertEquals(3, mEnMgr.silentProvisionCount);
+        mEnMgr.reset();
+    }
+
+    @Test
+    public void testCallStopTetheringWhenUiProvisioningFail() {
+        setupForRequiredProvisioning();
+        mEnMgr.updateConfiguration(new TetheringConfiguration(mMockContext, mLog,
+                INVALID_SUBSCRIPTION_ID));
+        verify(mEntitlementFailedListener, times(0)).onUiEntitlementFailed(TETHERING_WIFI);
+        mEnMgr.fakeEntitlementResult = TETHER_ERROR_PROVISION_FAILED;
+        mEnMgr.notifyUpstream(true);
+        mLooper.dispatchAll();
+        mEnMgr.startProvisioningIfNeeded(TETHERING_WIFI, true);
+        mLooper.dispatchAll();
+        assertEquals(1, mEnMgr.uiProvisionCount);
+        verify(mEntitlementFailedListener, times(1)).onUiEntitlementFailed(TETHERING_WIFI);
+    }
+
+
     public class TestStateMachine extends StateMachine {
         public final ArrayList<Message> messages = new ArrayList<>();
-        private final State mLoggingState =
-                new EntitlementManagerTest.TestStateMachine.LoggingState();
+        private final State
+                mLoggingState = new EntitlementManagerTest.TestStateMachine.LoggingState();
 
         class LoggingState extends State {
             @Override public void enter() {
diff --git a/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java b/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
index 5a1f853..0d276cb 100644
--- a/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/tethering/UpstreamNetworkMonitorTest.java
@@ -90,6 +90,7 @@
     private static final NetworkRequest mDefaultRequest = new NetworkRequest.Builder().build();
 
     @Mock private Context mContext;
+    @Mock private EntitlementManager mEntitleMgr;
     @Mock private IConnectivityManager mCS;
     @Mock private SharedLog mLog;
 
@@ -103,6 +104,7 @@
         reset(mCS);
         reset(mLog);
         when(mLog.forSubComponent(anyString())).thenReturn(mLog);
+        when(mEntitleMgr.isCellularUpstreamPermitted()).thenReturn(true);
 
         mCM = spy(new TestConnectivityManager(mContext, mCS));
         mSM = new TestStateMachine();
@@ -138,7 +140,7 @@
     @Test
     public void testDefaultNetworkIsTracked() throws Exception {
         assertTrue(mCM.hasNoCallbacks());
-        mUNM.startTrackDefaultNetwork(mDefaultRequest);
+        mUNM.startTrackDefaultNetwork(mDefaultRequest, mEntitleMgr);
 
         mUNM.startObserveAllNetworks();
         assertEquals(1, mCM.trackingDefault.size());
@@ -151,7 +153,7 @@
     public void testListensForAllNetworks() throws Exception {
         assertTrue(mCM.listening.isEmpty());
 
-        mUNM.startTrackDefaultNetwork(mDefaultRequest);
+        mUNM.startTrackDefaultNetwork(mDefaultRequest, mEntitleMgr);
         mUNM.startObserveAllNetworks();
         assertFalse(mCM.listening.isEmpty());
         assertTrue(mCM.isListeningForAll());
@@ -162,7 +164,7 @@
 
     @Test
     public void testCallbacksRegistered() {
-        mUNM.startTrackDefaultNetwork(mDefaultRequest);
+        mUNM.startTrackDefaultNetwork(mDefaultRequest, mEntitleMgr);
         verify(mCM, times(1)).requestNetwork(
                 eq(mDefaultRequest), any(NetworkCallback.class), any(Handler.class));
         mUNM.startObserveAllNetworks();
@@ -285,7 +287,7 @@
         final Collection<Integer> preferredTypes = new ArrayList<>();
         preferredTypes.add(TYPE_WIFI);
 
-        mUNM.startTrackDefaultNetwork(mDefaultRequest);
+        mUNM.startTrackDefaultNetwork(mDefaultRequest, mEntitleMgr);
         mUNM.startObserveAllNetworks();
         // There are no networks, so there is nothing to select.
         assertSatisfiesLegacyType(TYPE_NONE, mUNM.selectPreferredUpstreamType(preferredTypes));
@@ -319,6 +321,14 @@
         NetworkRequest netReq = (NetworkRequest) mCM.requested.values().toArray()[0];
         assertTrue(netReq.networkCapabilities.hasTransport(TRANSPORT_CELLULAR));
         assertFalse(netReq.networkCapabilities.hasCapability(NET_CAPABILITY_DUN));
+        // mobile is not permitted, we should not use HIPRI.
+        when(mEntitleMgr.isCellularUpstreamPermitted()).thenReturn(false);
+        assertSatisfiesLegacyType(TYPE_NONE, mUNM.selectPreferredUpstreamType(preferredTypes));
+        assertEquals(0, mCM.requested.size());
+        // mobile change back to permitted, HIRPI should come back
+        when(mEntitleMgr.isCellularUpstreamPermitted()).thenReturn(true);
+        assertSatisfiesLegacyType(TYPE_MOBILE_HIPRI,
+                mUNM.selectPreferredUpstreamType(preferredTypes));
 
         wifiAgent.fakeConnect();
         // WiFi is up, and we should prefer it over cell.
@@ -347,11 +357,19 @@
         netReq = (NetworkRequest) mCM.requested.values().toArray()[0];
         assertTrue(netReq.networkCapabilities.hasTransport(TRANSPORT_CELLULAR));
         assertTrue(netReq.networkCapabilities.hasCapability(NET_CAPABILITY_DUN));
+        // mobile is not permitted, we should not use DUN.
+        when(mEntitleMgr.isCellularUpstreamPermitted()).thenReturn(false);
+        assertSatisfiesLegacyType(TYPE_NONE, mUNM.selectPreferredUpstreamType(preferredTypes));
+        assertEquals(0, mCM.requested.size());
+        // mobile change back to permitted, DUN should come back
+        when(mEntitleMgr.isCellularUpstreamPermitted()).thenReturn(true);
+        assertSatisfiesLegacyType(TYPE_MOBILE_DUN,
+                mUNM.selectPreferredUpstreamType(preferredTypes));
     }
 
     @Test
     public void testGetCurrentPreferredUpstream() throws Exception {
-        mUNM.startTrackDefaultNetwork(mDefaultRequest);
+        mUNM.startTrackDefaultNetwork(mDefaultRequest, mEntitleMgr);
         mUNM.startObserveAllNetworks();
         mUNM.updateMobileRequiresDun(false);
 
@@ -361,37 +379,46 @@
         mCM.makeDefaultNetwork(cellAgent);
         assertEquals(cellAgent.networkId, mUNM.getCurrentPreferredUpstream().network);
 
-        // [1] WiFi connects but not validated/promoted to default -> mobile selected.
+        // [1] Mobile connects but not permitted -> null selected
+        when(mEntitleMgr.isCellularUpstreamPermitted()).thenReturn(false);
+        assertEquals(null, mUNM.getCurrentPreferredUpstream());
+        when(mEntitleMgr.isCellularUpstreamPermitted()).thenReturn(true);
+
+        // [2] WiFi connects but not validated/promoted to default -> mobile selected.
         final TestNetworkAgent wifiAgent = new TestNetworkAgent(mCM, TRANSPORT_WIFI);
         wifiAgent.fakeConnect();
         assertEquals(cellAgent.networkId, mUNM.getCurrentPreferredUpstream().network);
 
-        // [2] WiFi validates and is promoted to the default network -> WiFi selected.
+        // [3] WiFi validates and is promoted to the default network -> WiFi selected.
         mCM.makeDefaultNetwork(wifiAgent);
         assertEquals(wifiAgent.networkId, mUNM.getCurrentPreferredUpstream().network);
 
-        // [3] DUN required, no other changes -> WiFi still selected
+        // [4] DUN required, no other changes -> WiFi still selected
         mUNM.updateMobileRequiresDun(true);
         assertEquals(wifiAgent.networkId, mUNM.getCurrentPreferredUpstream().network);
 
-        // [4] WiFi no longer validated, mobile becomes default, DUN required -> null selected.
+        // [5] WiFi no longer validated, mobile becomes default, DUN required -> null selected.
         mCM.makeDefaultNetwork(cellAgent);
         assertEquals(null, mUNM.getCurrentPreferredUpstream());
         // TODO: make sure that a DUN request has been filed. This is currently
         // triggered by code over in Tethering, but once that has been moved
         // into UNM we should test for this here.
 
-        // [5] DUN network arrives -> DUN selected
+        // [6] DUN network arrives -> DUN selected
         final TestNetworkAgent dunAgent = new TestNetworkAgent(mCM, TRANSPORT_CELLULAR);
         dunAgent.networkCapabilities.addCapability(NET_CAPABILITY_DUN);
         dunAgent.networkCapabilities.removeCapability(NET_CAPABILITY_INTERNET);
         dunAgent.fakeConnect();
         assertEquals(dunAgent.networkId, mUNM.getCurrentPreferredUpstream().network);
+
+        // [7] Mobile is not permitted -> null selected
+        when(mEntitleMgr.isCellularUpstreamPermitted()).thenReturn(false);
+        assertEquals(null, mUNM.getCurrentPreferredUpstream());
     }
 
     @Test
     public void testLocalPrefixes() throws Exception {
-        mUNM.startTrackDefaultNetwork(mDefaultRequest);
+        mUNM.startTrackDefaultNetwork(mDefaultRequest, mEntitleMgr);
         mUNM.startObserveAllNetworks();
 
         // [0] Test minimum set of local prefixes.
@@ -492,6 +519,26 @@
         assertTrue(local.isEmpty());
     }
 
+    @Test
+    public void testSelectMobileWhenMobileIsNotDefault() {
+        final Collection<Integer> preferredTypes = new ArrayList<>();
+        // Mobile has higher pirority than wifi.
+        preferredTypes.add(TYPE_MOBILE_HIPRI);
+        preferredTypes.add(TYPE_WIFI);
+        mUNM.startTrackDefaultNetwork(mDefaultRequest, mEntitleMgr);
+        mUNM.startObserveAllNetworks();
+        // Setup wifi and make wifi as default network.
+        final TestNetworkAgent wifiAgent = new TestNetworkAgent(mCM, TRANSPORT_WIFI);
+        wifiAgent.fakeConnect();
+        mCM.makeDefaultNetwork(wifiAgent);
+        // Setup mobile network.
+        final TestNetworkAgent cellAgent = new TestNetworkAgent(mCM, TRANSPORT_CELLULAR);
+        cellAgent.fakeConnect();
+
+        assertSatisfiesLegacyType(TYPE_MOBILE_HIPRI,
+                mUNM.selectPreferredUpstreamType(preferredTypes));
+        verify(mEntitleMgr, times(1)).maybeRunProvisioning();
+    }
     private void assertSatisfiesLegacyType(int legacyType, NetworkState ns) {
         if (legacyType == TYPE_NONE) {
             assertTrue(ns == null);
diff --git a/tools/incident_section_gen/main.cpp b/tools/incident_section_gen/main.cpp
index f6c9c0e..3b3fe19 100644
--- a/tools/incident_section_gen/main.cpp
+++ b/tools/incident_section_gen/main.cpp
@@ -408,10 +408,16 @@
     for (int i=0; i<descriptor->field_count(); i++) {
         const FieldDescriptor* field = descriptor->field(i);
 
-        if (field->type() != FieldDescriptor::TYPE_MESSAGE && field->type() != FieldDescriptor::TYPE_STRING) {
+        if (field->type() != FieldDescriptor::TYPE_MESSAGE
+                && field->type() != FieldDescriptor::TYPE_STRING) {
             continue;
         }
+
         const SectionFlags s = getSectionFlags(field);
+        if (s.userdebug_and_eng_only()) {
+            printf("#if ALLOW_RESTRICTED_SECTIONS\n");
+        }
+
         switch (s.type()) {
             case SECTION_NONE:
                 continue;
@@ -424,8 +430,7 @@
                 printf(" NULL),\n");
                 break;
             case SECTION_DUMPSYS:
-                printf("    new DumpsysSection(%d, %s,", field->number(),
-                       s.userdebug_and_eng_only() ? "true" : "false");
+                printf("    new DumpsysSection(%d, ", field->number());
                 splitAndPrint(s.args());
                 printf(" NULL),\n");
                 break;
@@ -438,9 +443,13 @@
                 printf(" NULL),\n");
                 break;
             case SECTION_TOMBSTONE:
-                printf("    new TombstoneSection(%d, \"%s\"),\n", field->number(), s.args().c_str());
+                printf("    new TombstoneSection(%d, \"%s\"),\n", field->number(),
+                        s.args().c_str());
                 break;
         }
+        if (s.userdebug_and_eng_only()) {
+            printf("#endif\n");
+        }
     }
     printf("    NULL };\n");
 
diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp
index daee6d6..a5b56a4 100644
--- a/tools/stats_log_api_gen/main.cpp
+++ b/tools/stats_log_api_gen/main.cpp
@@ -512,7 +512,7 @@
        fprintf(out, "      std::this_thread::sleep_for(std::chrono::milliseconds(10));\n");
        fprintf(out, "  }\n");
        fprintf(out, "  if (ret < 0) {\n");
-       fprintf(out, "      note_log_drop(ret);\n");
+       fprintf(out, "      note_log_drop(ret, code);\n");
        fprintf(out, "  }\n");
        fprintf(out, "  return ret;\n");
        fprintf(out, "}\n");
@@ -620,7 +620,7 @@
        fprintf(out, "      std::this_thread::sleep_for(std::chrono::milliseconds(10));\n");
        fprintf(out, "  }\n");
        fprintf(out, "  if (ret < 0) {\n");
-       fprintf(out, "      note_log_drop(ret);\n");
+       fprintf(out, "      note_log_drop(ret, code);\n");
        fprintf(out, "  }\n");
        fprintf(out, "  return ret;\n\n");
        fprintf(out, "}\n");