Merge "Introduce default value to fixed to user rotation."
diff --git a/apct-tests/perftests/multiuser/src/android/multiuser/BenchmarkResults.java b/apct-tests/perftests/multiuser/src/android/multiuser/BenchmarkResults.java
index e417ca7..c1362dc 100644
--- a/apct-tests/perftests/multiuser/src/android/multiuser/BenchmarkResults.java
+++ b/apct-tests/perftests/multiuser/src/android/multiuser/BenchmarkResults.java
@@ -60,11 +60,13 @@
         if (size == 0) {
             return 0f;
         }
-        Collections.sort(mResults);
+
+        final ArrayList<Long> resultsCopy = new ArrayList<>(mResults);
+        Collections.sort(resultsCopy);
         final int idx = size / 2;
         return size % 2 == 0
-                ? (double) (mResults.get(idx) + mResults.get(idx - 1)) / 2
-                : mResults.get(idx);
+                ? (double) (resultsCopy.get(idx) + resultsCopy.get(idx - 1)) / 2
+                : resultsCopy.get(idx);
     }
 
     private double standardDeviation() {
diff --git a/api/current.txt b/api/current.txt
index 9e28ada..343fbd9 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -5478,7 +5478,7 @@
     method public android.graphics.drawable.Icon getIcon();
     method public android.app.PendingIntent getIntent();
     method public boolean getSuppressInitialNotification();
-    method public CharSequence getTitle();
+    method @Deprecated public CharSequence getTitle();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.app.Notification.BubbleMetadata> CREATOR;
   }
@@ -5492,7 +5492,7 @@
     method public android.app.Notification.BubbleMetadata.Builder setIcon(android.graphics.drawable.Icon);
     method public android.app.Notification.BubbleMetadata.Builder setIntent(android.app.PendingIntent);
     method public android.app.Notification.BubbleMetadata.Builder setSuppressInitialNotification(boolean);
-    method public android.app.Notification.BubbleMetadata.Builder setTitle(CharSequence);
+    method @Deprecated public android.app.Notification.BubbleMetadata.Builder setTitle(CharSequence);
   }
 
   public static class Notification.Builder {
@@ -6664,7 +6664,7 @@
     method public int getPasswordMinimumUpperCase(@Nullable android.content.ComponentName);
     method public int getPasswordQuality(@Nullable android.content.ComponentName);
     method @Nullable public android.app.admin.SystemUpdateInfo getPendingSystemUpdate(@NonNull android.content.ComponentName);
-    method public int getPermissionGrantState(@Nullable android.content.ComponentName, String, String);
+    method public int getPermissionGrantState(@Nullable android.content.ComponentName, @NonNull String, @NonNull String);
     method public int getPermissionPolicy(android.content.ComponentName);
     method @Nullable public java.util.List<java.lang.String> getPermittedAccessibilityServices(@NonNull android.content.ComponentName);
     method @Nullable public java.util.List<java.lang.String> getPermittedCrossProfileNotificationListeners(@NonNull android.content.ComponentName);
@@ -6775,7 +6775,7 @@
     method public void setPasswordMinimumSymbols(@NonNull android.content.ComponentName, int);
     method public void setPasswordMinimumUpperCase(@NonNull android.content.ComponentName, int);
     method public void setPasswordQuality(@NonNull android.content.ComponentName, int);
-    method public boolean setPermissionGrantState(@NonNull android.content.ComponentName, String, String, int);
+    method public boolean setPermissionGrantState(@NonNull android.content.ComponentName, @NonNull String, @NonNull String, int);
     method public void setPermissionPolicy(@NonNull android.content.ComponentName, int);
     method public boolean setPermittedAccessibilityServices(@NonNull android.content.ComponentName, java.util.List<java.lang.String>);
     method public boolean setPermittedCrossProfileNotificationListeners(@NonNull android.content.ComponentName, @Nullable java.util.List<java.lang.String>);
@@ -11475,7 +11475,6 @@
     method public void setAppIcon(@Nullable android.graphics.Bitmap);
     method public void setAppLabel(@Nullable CharSequence);
     method public void setAppPackageName(@Nullable String);
-    method public void setInstallAsApex();
     method public void setInstallLocation(int);
     method public void setInstallReason(int);
     method public void setMultiPackage();
@@ -24014,8 +24013,8 @@
     method public int getMaxImages();
     method public android.view.Surface getSurface();
     method public int getWidth();
-    method public static android.media.ImageReader newInstance(int, int, int, int);
-    method public static android.media.ImageReader newInstance(int, int, int, int, long);
+    method @NonNull public static android.media.ImageReader newInstance(@IntRange(from=1) int, @IntRange(from=1) int, int, @IntRange(from=1) int);
+    method @NonNull public static android.media.ImageReader newInstance(@IntRange(from=1) int, @IntRange(from=1) int, int, @IntRange(from=1) int, long);
     method public void setOnImageAvailableListener(android.media.ImageReader.OnImageAvailableListener, android.os.Handler);
   }
 
@@ -24028,8 +24027,8 @@
     method public android.media.Image dequeueInputImage();
     method public int getFormat();
     method public int getMaxImages();
-    method public static android.media.ImageWriter newInstance(android.view.Surface, int);
-    method public static android.media.ImageWriter newInstance(android.view.Surface, int, int);
+    method @NonNull public static android.media.ImageWriter newInstance(@NonNull android.view.Surface, @IntRange(from=1) int);
+    method @NonNull public static android.media.ImageWriter newInstance(@NonNull android.view.Surface, @IntRange(from=1) int, int);
     method public void queueInputImage(android.media.Image);
     method public void setOnImageReleasedListener(android.media.ImageWriter.OnImageReleasedListener, android.os.Handler);
   }
@@ -27458,6 +27457,7 @@
     method @Nullable public CharSequence getQueueTitle();
     method public int getRatingType();
     method @Nullable public android.app.PendingIntent getSessionActivity();
+    method @Nullable public android.os.Bundle getSessionInfo();
     method @NonNull public android.media.session.MediaSession.Token getSessionToken();
     method @NonNull public android.media.session.MediaController.TransportControls getTransportControls();
     method public void registerCallback(@NonNull android.media.session.MediaController.Callback);
@@ -27517,6 +27517,7 @@
 
   public final class MediaSession {
     ctor public MediaSession(@NonNull android.content.Context, @NonNull String);
+    ctor public MediaSession(@NonNull android.content.Context, @NonNull String, @Nullable android.os.Bundle);
     method @NonNull public android.media.session.MediaController getController();
     method @NonNull public android.media.session.MediaSessionManager.RemoteUserInfo getCurrentControllerInfo();
     method @NonNull public android.media.session.MediaSession.Token getSessionToken();
@@ -29987,7 +29988,7 @@
     method @Deprecated public boolean reconnect();
     method @Deprecated public boolean removeNetwork(int);
     method @RequiresPermission(android.Manifest.permission.CHANGE_WIFI_STATE) public int removeNetworkSuggestions(@NonNull java.util.List<android.net.wifi.WifiNetworkSuggestion>);
-    method @Deprecated @RequiresPermission(anyOf={"android.permission.NETWORK_SETTINGS", "android.permission.NETWORK_SETUP_WIZARD"}) public void removePasspointConfiguration(String);
+    method @Deprecated @RequiresPermission("android.permission.NETWORK_SETTINGS") public void removePasspointConfiguration(String);
     method @Deprecated public boolean saveConfiguration();
     method public void setTdlsEnabled(java.net.InetAddress, boolean);
     method public void setTdlsEnabledWithMacAddress(String, boolean);
@@ -43339,11 +43340,11 @@
 
   public final class CallIdentification implements android.os.Parcelable {
     method public int describeContents();
-    method @NonNull public String getCallScreeningAppName();
+    method @NonNull public CharSequence getCallScreeningAppName();
     method @NonNull public String getCallScreeningPackageName();
-    method @Nullable public String getDescription();
-    method @Nullable public String getDetails();
-    method @Nullable public String getName();
+    method @Nullable public CharSequence getDescription();
+    method @Nullable public CharSequence getDetails();
+    method @Nullable public CharSequence getName();
     method public int getNuisanceConfidence();
     method @Nullable public android.graphics.drawable.Icon getPhoto();
     method public void writeToParcel(android.os.Parcel, int);
@@ -43358,9 +43359,9 @@
   public static class CallIdentification.Builder {
     ctor public CallIdentification.Builder();
     method public android.telecom.CallIdentification build();
-    method public android.telecom.CallIdentification.Builder setDescription(@Nullable String);
-    method public android.telecom.CallIdentification.Builder setDetails(@Nullable String);
-    method public android.telecom.CallIdentification.Builder setName(@Nullable String);
+    method public android.telecom.CallIdentification.Builder setDescription(@Nullable CharSequence);
+    method public android.telecom.CallIdentification.Builder setDetails(@Nullable CharSequence);
+    method public android.telecom.CallIdentification.Builder setName(@Nullable CharSequence);
     method public android.telecom.CallIdentification.Builder setNuisanceConfidence(int);
     method public android.telecom.CallIdentification.Builder setPhoto(@Nullable android.graphics.drawable.Icon);
   }
@@ -45192,6 +45193,7 @@
     method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.MODIFY_PHONE_STATE}) public boolean isDataEnabled();
     method @RequiresPermission(anyOf={android.Manifest.permission.ACCESS_NETWORK_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isDataRoamingEnabled();
     method public boolean isHearingAidCompatibilitySupported();
+    method @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE) public boolean isMultisimSupported();
     method public boolean isNetworkRoaming();
     method public boolean isRttSupported();
     method public boolean isSmsCapable();
@@ -47477,6 +47479,7 @@
     method public int getVerticalAlignment();
     field public static final int ALIGN_BASELINE = 1; // 0x1
     field public static final int ALIGN_BOTTOM = 0; // 0x0
+    field public static final int ALIGN_CENTER = 2; // 0x2
     field protected final int mVerticalAlignment;
   }
 
diff --git a/api/system-current.txt b/api/system-current.txt
index c831522..b7f435a 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -15,6 +15,7 @@
     field public static final String ACCESS_SHORTCUTS = "android.permission.ACCESS_SHORTCUTS";
     field public static final String ACCESS_SURFACE_FLINGER = "android.permission.ACCESS_SURFACE_FLINGER";
     field public static final String ACTIVITY_EMBEDDING = "android.permission.ACTIVITY_EMBEDDING";
+    field public static final String ADJUST_RUNTIME_PERMISSIONS_POLICY = "android.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY";
     field public static final String ALLOCATE_AGGRESSIVE = "android.permission.ALLOCATE_AGGRESSIVE";
     field public static final String ALLOW_ANY_CODEC_FOR_PLAYBACK = "android.permission.ALLOW_ANY_CODEC_FOR_PLAYBACK";
     field public static final String AMBIENT_WALLPAPER = "android.permission.AMBIENT_WALLPAPER";
@@ -1557,6 +1558,7 @@
     method public void setDontKillApp(boolean);
     method public void setEnableRollback();
     method @RequiresPermission(android.Manifest.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS) public void setGrantedRuntimePermissions(String[]);
+    method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setInstallAsApex();
     method public void setInstallAsInstantApp(boolean);
     method public void setInstallAsVirtualPreload();
     method @RequiresPermission(android.Manifest.permission.INSTALL_PACKAGES) public void setStaged();
@@ -1575,6 +1577,7 @@
     method @RequiresPermission("android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS") public abstract void addOnPermissionsChangeListener(android.content.pm.PackageManager.OnPermissionsChangedListener);
     method public abstract boolean arePermissionsIndividuallyControlled();
     method public abstract java.util.List<android.content.IntentFilter> getAllIntentFilters(String);
+    method public boolean getAppDetailsActivityEnabled(@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 @RequiresPermission(android.Manifest.permission.INTERACT_ACROSS_USERS_FULL) public abstract String getDefaultBrowserPackageNameAsUser(int);
@@ -1601,6 +1604,7 @@
     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(value=android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE, conditional=true) public void setAppDetailsActivityEnabled(@NonNull String, boolean);
     method @RequiresPermission(allOf={android.Manifest.permission.SET_PREFERRED_APPLICATIONS, android.Manifest.permission.INTERACT_ACROSS_USERS_FULL}) public abstract boolean setDefaultBrowserPackageNameAsUser(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);
@@ -3036,21 +3040,21 @@
     method public double getHorizontalPositionUncertaintyMeters();
     method public double getLatitudeDegrees();
     method public double getLongitudeDegrees();
-    method @Nullable public java.util.List<android.location.GnssSingleSatCorrection> getSingleSatCorrectionList();
+    method @Nullable public java.util.List<android.location.GnssSingleSatCorrection> getSingleSatelliteCorrectionList();
     method public long getToaGpsNanosecondsOfWeek();
     method public double getVerticalPositionUncertaintyMeters();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.location.GnssMeasurementCorrections> CREATOR;
   }
 
-  public static class GnssMeasurementCorrections.Builder {
+  public static final class GnssMeasurementCorrections.Builder {
     ctor public GnssMeasurementCorrections.Builder();
     method public android.location.GnssMeasurementCorrections build();
     method public android.location.GnssMeasurementCorrections.Builder setAltitudeMeters(double);
     method public android.location.GnssMeasurementCorrections.Builder setHorizontalPositionUncertaintyMeters(double);
     method public android.location.GnssMeasurementCorrections.Builder setLatitudeDegrees(double);
     method public android.location.GnssMeasurementCorrections.Builder setLongitudeDegrees(double);
-    method public android.location.GnssMeasurementCorrections.Builder setSingleSatCorrectionList(@Nullable java.util.List<android.location.GnssSingleSatCorrection>);
+    method public android.location.GnssMeasurementCorrections.Builder setSingleSatelliteCorrectionList(@Nullable java.util.List<android.location.GnssSingleSatCorrection>);
     method public android.location.GnssMeasurementCorrections.Builder setToaGpsNanosecondsOfWeek(long);
     method public android.location.GnssMeasurementCorrections.Builder setVerticalPositionUncertaintyMeters(double);
   }
@@ -3065,7 +3069,7 @@
     field public static final android.os.Parcelable.Creator<android.location.GnssReflectingPlane> CREATOR;
   }
 
-  public static class GnssReflectingPlane.Builder {
+  public static final class GnssReflectingPlane.Builder {
     ctor public GnssReflectingPlane.Builder();
     method public android.location.GnssReflectingPlane build();
     method public android.location.GnssReflectingPlane.Builder setAltitudeMeters(double);
@@ -3080,14 +3084,14 @@
     method public int getConstellationType();
     method public float getExcessPathLengthMeters();
     method public float getExcessPathLengthUncertaintyMeters();
-    method @FloatRange(from=0.0f, to=1.0f) public float getProbSatIsLos();
+    method @FloatRange(from=0.0f, to=1.0f) public float getProbabilityLineOfSight();
     method @Nullable public android.location.GnssReflectingPlane getReflectingPlane();
-    method public int getSatId();
-    method public int getSingleSatCorrectionFlags();
+    method public int getSatelliteId();
+    method public int getSingleSatelliteCorrectionFlags();
     method public boolean hasExcessPathLength();
     method public boolean hasExcessPathLengthUncertainty();
     method public boolean hasReflectingPlane();
-    method public boolean hasSatelliteLineOfSight();
+    method public boolean hasValidSatelliteLineOfSight();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.location.GnssSingleSatCorrection> CREATOR;
     field public static final int HAS_EXCESS_PATH_LENGTH_MASK = 2; // 0x2
@@ -3096,17 +3100,17 @@
     field public static final int HAS_REFLECTING_PLANE_MASK = 8; // 0x8
   }
 
-  public static class GnssSingleSatCorrection.Builder {
+  public static final class GnssSingleSatCorrection.Builder {
     ctor public GnssSingleSatCorrection.Builder();
     method public android.location.GnssSingleSatCorrection build();
     method public android.location.GnssSingleSatCorrection.Builder setCarrierFrequencyHz(float);
     method public android.location.GnssSingleSatCorrection.Builder setConstellationType(int);
     method public android.location.GnssSingleSatCorrection.Builder setExcessPathLengthMeters(float);
     method public android.location.GnssSingleSatCorrection.Builder setExcessPathLengthUncertaintyMeters(float);
-    method public android.location.GnssSingleSatCorrection.Builder setProbSatIsLos(@FloatRange(from=0.0f, to=1.0f) float);
+    method public android.location.GnssSingleSatCorrection.Builder setProbabilityLineOfSight(@FloatRange(from=0.0f, to=1.0f) float);
     method public android.location.GnssSingleSatCorrection.Builder setReflectingPlane(android.location.GnssReflectingPlane);
-    method public android.location.GnssSingleSatCorrection.Builder setSatId(int);
-    method public android.location.GnssSingleSatCorrection.Builder setSingleSatCorrectionFlags(int);
+    method public android.location.GnssSingleSatCorrection.Builder setSatelliteId(int);
+    method public android.location.GnssSingleSatCorrection.Builder setSingleSatelliteCorrectionFlags(int);
   }
 
   public class GpsClock implements android.os.Parcelable {
@@ -4664,7 +4668,10 @@
   }
 
   public class WifiInfo implements android.os.Parcelable {
+    method @Nullable public String getFqdn();
+    method @Nullable public String getProviderFriendlyName();
     method public boolean isOsuAp();
+    method public boolean isPasspointAp();
   }
 
   public class WifiManager {
@@ -5537,6 +5544,7 @@
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public android.os.PersistableBundle getSeedAccountOptions();
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public String getSeedAccountType();
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public long[] getSerialNumbersOfUsers(boolean);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public android.graphics.Bitmap getUserIcon();
     method @Deprecated @android.os.UserManager.UserRestrictionSource @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public int getUserRestrictionSource(String, android.os.UserHandle);
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public java.util.List<android.os.UserManager.EnforcingUser> getUserRestrictionSources(String, android.os.UserHandle);
     method public boolean hasRestrictedProfiles();
@@ -5547,6 +5555,8 @@
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isPrimaryUser();
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean isRestrictedProfile();
     method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public boolean removeUser(android.os.UserHandle);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void setUserIcon(android.graphics.Bitmap);
+    method @RequiresPermission(android.Manifest.permission.MANAGE_USERS) public void setUserName(String);
     field public static final String ACTION_USER_RESTRICTIONS_CHANGED = "android.os.action.USER_RESTRICTIONS_CHANGED";
     field @Deprecated public static final String DISALLOW_OEM_UNLOCK = "no_oem_unlock";
     field public static final String DISALLOW_RUN_IN_BACKGROUND = "no_run_in_background";
@@ -5623,6 +5633,7 @@
     method @BinderThread public abstract void onRestoreRuntimePermissionsBackup(@NonNull android.os.UserHandle, @NonNull java.io.InputStream);
     method public abstract void onRevokeRuntimePermission(@NonNull String, @NonNull String);
     method @NonNull public abstract java.util.Map<java.lang.String,java.util.List<java.lang.String>> onRevokeRuntimePermissions(@NonNull java.util.Map<java.lang.String,java.util.List<java.lang.String>>, boolean, int, @NonNull String);
+    method public abstract boolean onSetRuntimePermissionGrantStateByDeviceAdmin(@NonNull String, @NonNull String, @NonNull String, int);
     field public static final String SERVICE_INTERFACE = "android.permission.PermissionControllerService";
   }
 
@@ -7912,7 +7923,6 @@
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isCurrentPotentialEmergencyNumber(@NonNull String);
     method public boolean isDataConnectivityPossible();
     method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isIdle();
-    method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isMultisimCarrierRestricted();
     method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isOffhook();
     method @Deprecated @RequiresPermission(anyOf={android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, android.Manifest.permission.READ_PHONE_STATE}) public boolean isRadioOn();
     method @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE) public boolean isRebootRequiredForModemConfigChange();
diff --git a/api/test-current.txt b/api/test-current.txt
index 2a45cd3..ba497d4 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -17,6 +17,10 @@
     field public static final String WRITE_OBB = "android.permission.WRITE_OBB";
   }
 
+  public static final class R.bool {
+    field public static final int config_perDisplayFocusEnabled = 17891332; // 0x1110004
+  }
+
   public static final class R.string {
     field public static final int config_defaultAssistant = 17039393; // 0x1040021
     field public static final int config_defaultDialer = 17039395; // 0x1040023
@@ -48,6 +52,7 @@
     method public long getTotalRam();
     method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public int getUidImportance(int);
     method @RequiresPermission(android.Manifest.permission.PACKAGE_USAGE_STATS) public void removeOnUidImportanceListener(android.app.ActivityManager.OnUidImportanceListener);
+    method public static void resumeAppSwitches() throws android.os.RemoteException;
     method @RequiresPermission(android.Manifest.permission.CHANGE_CONFIGURATION) public void scheduleApplicationInfoChanged(java.util.List<java.lang.String>, int);
   }
 
@@ -94,6 +99,31 @@
     field public static final int SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT = 0; // 0x0
   }
 
+  public class ActivityView extends android.view.ViewGroup {
+    ctor public ActivityView(android.content.Context);
+    ctor public ActivityView(android.content.Context, android.util.AttributeSet);
+    ctor public ActivityView(android.content.Context, android.util.AttributeSet, int);
+    ctor public ActivityView(android.content.Context, android.util.AttributeSet, int, boolean);
+    method public void onLayout(boolean, int, int, int, int);
+    method public void onLocationChanged();
+    method public void performBackPress();
+    method public void release();
+    method public void setCallback(android.app.ActivityView.StateCallback);
+    method public void setForwardedInsets(android.graphics.Insets);
+    method public void startActivity(@NonNull android.content.Intent);
+    method public void startActivity(@NonNull android.content.Intent, android.os.UserHandle);
+    method public void startActivity(@NonNull android.app.PendingIntent);
+  }
+
+  public abstract static class ActivityView.StateCallback {
+    ctor public ActivityView.StateCallback();
+    method public abstract void onActivityViewDestroyed(android.app.ActivityView);
+    method public abstract void onActivityViewReady(android.app.ActivityView);
+    method public void onTaskCreated(int, android.content.ComponentName);
+    method public void onTaskMovedToFront(int);
+    method public void onTaskRemovalStarted(int);
+  }
+
   public class AppDetailsActivity extends android.app.Activity {
     ctor public AppDetailsActivity();
   }
@@ -483,6 +513,17 @@
 
 package android.content {
 
+  public final class AutofillOptions implements android.os.Parcelable {
+    ctor public AutofillOptions(int, boolean);
+    method public int describeContents();
+    method public static android.content.AutofillOptions forWhitelistingItself();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.content.AutofillOptions> CREATOR;
+    field public boolean augmentedEnabled;
+    field public final boolean compatModeEnabled;
+    field public final int loggingLevel;
+  }
+
   public final class ContentCaptureOptions implements android.os.Parcelable {
     ctor public ContentCaptureOptions(int, int, int, int, int, @Nullable android.util.ArraySet<android.content.ComponentName>);
     method public int describeContents();
@@ -507,12 +548,17 @@
 
   public abstract class Context {
     method public android.content.Context createPackageContextAsUser(String, int, android.os.UserHandle) throws android.content.pm.PackageManager.NameNotFoundException;
+    method public abstract android.view.Display getDisplay();
     method public android.os.UserHandle getUser();
     method public int getUserId();
-    method public void setAutofillCompatibilityEnabled(boolean);
+    method public void setAutofillOptions(@Nullable android.content.AutofillOptions);
     method public void setContentCaptureOptions(@Nullable android.content.ContentCaptureOptions);
   }
 
+  public class ContextWrapper extends android.content.Context {
+    method public android.view.Display getDisplay();
+  }
+
 }
 
 package android.content.pm {
@@ -958,6 +1004,50 @@
 
 }
 
+package android.metrics {
+
+  public class LogMaker {
+    ctor public LogMaker(int);
+    ctor public LogMaker(Object[]);
+    method public android.metrics.LogMaker addTaggedData(int, Object);
+    method public android.metrics.LogMaker clearCategory();
+    method public android.metrics.LogMaker clearPackageName();
+    method public android.metrics.LogMaker clearSubtype();
+    method public android.metrics.LogMaker clearTaggedData(int);
+    method public android.metrics.LogMaker clearType();
+    method public void deserialize(Object[]);
+    method public int getCategory();
+    method public long getCounterBucket();
+    method public String getCounterName();
+    method public int getCounterValue();
+    method public String getPackageName();
+    method public int getProcessId();
+    method public int getSubtype();
+    method public Object getTaggedData(int);
+    method public long getTimestamp();
+    method public int getType();
+    method public int getUid();
+    method public boolean isLongCounterBucket();
+    method public boolean isSubsetOf(android.metrics.LogMaker);
+    method public boolean isValidValue(Object);
+    method public Object[] serialize();
+    method public android.metrics.LogMaker setCategory(int);
+    method public android.metrics.LogMaker setPackageName(String);
+    method public android.metrics.LogMaker setSubtype(int);
+    method public android.metrics.LogMaker setType(int);
+  }
+
+  public class MetricsReader {
+    ctor public MetricsReader();
+    method public void checkpoint();
+    method public boolean hasNext();
+    method public android.metrics.LogMaker next();
+    method public void read(long);
+    method public void reset();
+  }
+
+}
+
 package android.net {
 
   public class CaptivePortal implements android.os.Parcelable {
@@ -1302,6 +1392,7 @@
 
   public class Build {
     method public static boolean is64BitAbi(String);
+    field public static final boolean IS_EMULATOR;
   }
 
   public static class Build.VERSION {
@@ -1882,6 +1973,7 @@
     field public static final String LOCATION_GLOBAL_KILL_SWITCH = "location_global_kill_switch";
     field public static final String LOW_POWER_MODE = "low_power";
     field public static final String LOW_POWER_MODE_STICKY = "low_power_sticky";
+    field public static final String OVERLAY_DISPLAY_DEVICES = "overlay_display_devices";
     field public static final String SMS_ACCESS_RESTRICTION_ENABLED = "sms_access_restriction_enabled";
     field public static final String USE_OPEN_WIFI_PACKAGE = "use_open_wifi_package";
   }
@@ -1900,6 +1992,7 @@
     field public static final String CONTENT_CAPTURE_ENABLED = "content_capture_enabled";
     field public static final String DISABLED_PRINT_SERVICES = "disabled_print_services";
     field @Deprecated public static final String ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES = "enabled_notification_policy_access_packages";
+    field public static final String ENABLED_VR_LISTENERS = "enabled_vr_listeners";
     field public static final String LOCATION_ACCESS_CHECK_DELAY_MILLIS = "location_access_check_delay_millis";
     field public static final String LOCATION_ACCESS_CHECK_INTERVAL_MILLIS = "location_access_check_interval_millis";
     field public static final String NOTIFICATION_BADGING = "notification_badging";
@@ -2380,6 +2473,10 @@
     method public E valueAtUnchecked(int);
   }
 
+  public class TimeUtils {
+    method public static String formatDuration(long);
+  }
+
 }
 
 package android.util.proto {
@@ -2601,6 +2698,10 @@
     field public static final int CALLBACK_ANIMATION = 1; // 0x1
   }
 
+  public final class Display {
+    method public boolean supportsSystemDecorations();
+  }
+
   public class FocusFinder {
     method public static void sort(android.view.View[], int, int, android.view.ViewGroup, boolean);
   }
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index e7f7af2..8d1cf33 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -355,21 +355,25 @@
 
     flushIfNeededLocked(eventTimeNs);
 
-    // Pull on condition changes.
-    bool conditionChanged = mCondition != condition;
-    bool unknownToFalse = mCondition == ConditionState::kUnknown
-            && condition == ConditionState::kFalse;
-    // We do not need to pull when we go from unknown to false.
-    if (mIsPulled && conditionChanged && !unknownToFalse) {
-        pullAndMatchEventsLocked(eventTimeNs);
-    }
+    if (mCondition != ConditionState::kUnknown) {
+        // Pull on condition changes.
+        bool conditionChanged = mCondition != condition;
+        // We do not need to pull when we go from unknown to false.
+        if (mIsPulled && conditionChanged) {
+            pullAndMatchEventsLocked(eventTimeNs);
+        }
 
-    // when condition change from true to false, clear diff base but don't
-    // reset other counters as we may accumulate more value in the bucket.
-    if (mUseDiff && mCondition == ConditionState::kTrue && condition == ConditionState::kFalse) {
-        resetBase();
+        // when condition change from true to false, clear diff base but don't
+        // reset other counters as we may accumulate more value in the bucket.
+        if (mUseDiff && mCondition == ConditionState::kTrue && condition == ConditionState::kFalse) {
+            resetBase();
+        }
+    } else {
+        // If the condition was unknown, we mark the bucket as invalid since the bucket will contain
+        // partial data. For instance, the condition change might happen close to the end of the
+        // bucket and we might miss lots of data.
+        invalidateCurrentBucket();
     }
-
     mCondition = condition ? ConditionState::kTrue : ConditionState::kFalse;
 }
 
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index 696d4fa..24e14b1 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -255,6 +255,8 @@
     FRIEND_TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onConditionChanged);
     FRIEND_TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onBucketBoundary);
     FRIEND_TEST(ValueMetricProducerTest, TestPartialResetOnBucketBoundaries);
+    FRIEND_TEST(ValueMetricProducerTest, TestBucketIncludingUnknownConditionIsInvalid);
+    friend class ValueMetricProducerTestHelper;
 };
 
 }  // namespace statsd
diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
index a9d2c88..28caede 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -52,15 +52,72 @@
 const int64_t bucket6StartTimeNs = bucketStartTimeNs + 5 * bucketSizeNs;
 double epsilon = 0.001;
 
+
+class ValueMetricProducerTestHelper {
+
+ public:
+    static sp<ValueMetricProducer> createValueProducerNoConditions(
+            sp<MockStatsPullerManager>& pullerManager, ValueMetric& metric) {
+        UidMap uidMap;
+        SimpleAtomMatcher atomMatcher;
+        atomMatcher.set_atom_id(tagId);
+        sp<EventMatcherWizard> eventMatcherWizard =
+                new EventMatcherWizard({new SimpleLogMatchingTracker(
+                        atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+        sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+        EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
+        EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
+
+        sp<ValueMetricProducer> valueProducer = new ValueMetricProducer(
+                kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+                logEventMatcherIndex, eventMatcherWizard, tagId,
+                bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+        return valueProducer;
+    }
+
+    static sp<ValueMetricProducer> createValueProducerWithCondition(
+            sp<MockStatsPullerManager>& pullerManager, ValueMetric& metric) {
+        UidMap uidMap;
+        SimpleAtomMatcher atomMatcher;
+        atomMatcher.set_atom_id(tagId);
+        sp<EventMatcherWizard> eventMatcherWizard =
+                new EventMatcherWizard({new SimpleLogMatchingTracker(
+                        atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
+        sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+        EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
+        EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
+
+        sp<ValueMetricProducer> valueProducer =
+                new ValueMetricProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
+                                        eventMatcherWizard, tagId, bucketStartTimeNs,
+                                        bucketStartTimeNs, pullerManager);
+        valueProducer->mCondition = ConditionState::kFalse;
+        return valueProducer;
+    }
+
+    static ValueMetric createMetric() {
+        ValueMetric metric;
+        metric.set_id(metricId);
+        metric.set_bucket(ONE_MINUTE);
+        metric.mutable_value_field()->set_field(tagId);
+        metric.mutable_value_field()->add_child()->set_field(2);
+        metric.set_max_pull_delay_sec(INT_MAX);
+        return metric;
+    }
+
+    static ValueMetric createMetricWithCondition() {
+        ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
+        metric.set_condition(StringToId("SCREEN_ON"));
+        return metric;
+    }
+};
+
+
 /*
  * Tests that the first bucket works correctly
  */
 TEST(ValueMetricProducerTest, TestCalcPreviousBucketEndTime) {
-    ValueMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(ONE_MINUTE);
-    metric.mutable_value_field()->set_field(tagId);
-    metric.mutable_value_field()->add_child()->set_field(2);
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
 
     int64_t startTimeBase = 11;
     UidMap uidMap;
@@ -90,11 +147,7 @@
  * Tests that the first bucket works correctly
  */
 TEST(ValueMetricProducerTest, TestFirstBucket) {
-    ValueMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(ONE_MINUTE);
-    metric.mutable_value_field()->set_field(tagId);
-    metric.mutable_value_field()->add_child()->set_field(2);
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
 
     UidMap uidMap;
     SimpleAtomMatcher atomMatcher;
@@ -120,23 +173,8 @@
  * Tests pulled atoms with no conditions
  */
 TEST(ValueMetricProducerTest, TestPulledEventsNoCondition) {
-    ValueMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(ONE_MINUTE);
-    metric.mutable_value_field()->set_field(tagId);
-    metric.mutable_value_field()->add_child()->set_field(2);
-    metric.set_max_pull_delay_sec(INT_MAX);
-
-    UidMap uidMap;
-    SimpleAtomMatcher atomMatcher;
-    atomMatcher.set_atom_id(tagId);
-    sp<EventMatcherWizard> eventMatcherWizard =
-            new EventMatcherWizard({new SimpleLogMatchingTracker(
-                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); 
     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
-    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
     EXPECT_CALL(*pullerManager, Pull(tagId, _))
             .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
                 data->clear();
@@ -148,9 +186,8 @@
                 return true;
             }));
 
-    ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
-                                      logEventMatcherIndex, eventMatcherWizard, tagId,
-                                      bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+    sp<ValueMetricProducer> valueProducer =
+            ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
 
     vector<shared_ptr<LogEvent>> allData;
     allData.clear();
@@ -160,17 +197,17 @@
     event->init();
     allData.push_back(event);
 
-    valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+    valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
     // has one slice
-    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-    ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+    ValueMetricProducer::Interval curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
 
     EXPECT_EQ(true, curInterval.hasBase);
     EXPECT_EQ(11, curInterval.base.long_value);
     EXPECT_EQ(false, curInterval.hasValue);
     EXPECT_EQ(8, curInterval.value.long_value);
-    EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
-    EXPECT_EQ(8, valueProducer.mPastBuckets.begin()->second[0].values[0].long_value);
+    EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
+    EXPECT_EQ(8, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
 
     allData.clear();
     event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 1);
@@ -178,19 +215,19 @@
     event->write(23);
     event->init();
     allData.push_back(event);
-    valueProducer.onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
+    valueProducer->onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
     // has one slice
-    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
 
     EXPECT_EQ(true, curInterval.hasBase);
     EXPECT_EQ(23, curInterval.base.long_value);
     EXPECT_EQ(false, curInterval.hasValue);
     EXPECT_EQ(12, curInterval.value.long_value);
-    EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
-    EXPECT_EQ(2UL, valueProducer.mPastBuckets.begin()->second.size());
-    EXPECT_EQ(8, valueProducer.mPastBuckets.begin()->second[0].values[0].long_value);
-    EXPECT_EQ(12, valueProducer.mPastBuckets.begin()->second.back().values[0].long_value);
+    EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
+    EXPECT_EQ(2UL, valueProducer->mPastBuckets.begin()->second.size());
+    EXPECT_EQ(8, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
+    EXPECT_EQ(12, valueProducer->mPastBuckets.begin()->second.back().values[0].long_value);
 
     allData.clear();
     event = make_shared<LogEvent>(tagId, bucket4StartTimeNs + 1);
@@ -198,39 +235,24 @@
     event->write(36);
     event->init();
     allData.push_back(event);
-    valueProducer.onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
-    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    valueProducer->onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
+    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
 
     EXPECT_EQ(true, curInterval.hasBase);
     EXPECT_EQ(36, curInterval.base.long_value);
     EXPECT_EQ(false, curInterval.hasValue);
     EXPECT_EQ(13, curInterval.value.long_value);
-    EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
-    EXPECT_EQ(3UL, valueProducer.mPastBuckets.begin()->second.size());
-    EXPECT_EQ(8, valueProducer.mPastBuckets.begin()->second[0].values[0].long_value);
-    EXPECT_EQ(12, valueProducer.mPastBuckets.begin()->second[1].values[0].long_value);
-    EXPECT_EQ(13, valueProducer.mPastBuckets.begin()->second[2].values[0].long_value);
+    EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
+    EXPECT_EQ(3UL, valueProducer->mPastBuckets.begin()->second.size());
+    EXPECT_EQ(8, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
+    EXPECT_EQ(12, valueProducer->mPastBuckets.begin()->second[1].values[0].long_value);
+    EXPECT_EQ(13, valueProducer->mPastBuckets.begin()->second[2].values[0].long_value);
 }
 
 TEST(ValueMetricProducerTest, TestPartialBucketCreated) {
-    ValueMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(ONE_MINUTE);
-    metric.mutable_value_field()->set_field(tagId);
-    metric.mutable_value_field()->add_child()->set_field(2);
-    metric.set_max_pull_delay_sec(INT_MAX);
-
-    UidMap uidMap;
-    SimpleAtomMatcher atomMatcher;
-    atomMatcher.set_atom_id(tagId);
-    sp<EventMatcherWizard> eventMatcherWizard =
-            new EventMatcherWizard({new SimpleLogMatchingTracker(
-                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); 
     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
-    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
     EXPECT_CALL(*pullerManager, Pull(tagId, _))
             // Initialize bucket.
             .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
@@ -253,9 +275,8 @@
                 return true;
             }));
 
-    ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
-                                      logEventMatcherIndex, eventMatcherWizard, tagId,
-                                      bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+    sp<ValueMetricProducer> valueProducer =
+            ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
 
     // First bucket ends.
     vector<shared_ptr<LogEvent>> allData;
@@ -265,14 +286,14 @@
     event->write(2);
     event->init();
     allData.push_back(event);
-    valueProducer.onDataPulled(allData, /** success */ true, bucket2StartTimeNs);
+    valueProducer->onDataPulled(allData, /** success */ true, bucket2StartTimeNs);
 
     // Partial buckets created in 2nd bucket.
-    valueProducer.notifyAppUpgrade(bucket2StartTimeNs + 2, "com.foo", 10000, 1);
+    valueProducer->notifyAppUpgrade(bucket2StartTimeNs + 2, "com.foo", 10000, 1);
 
     // One full bucket and one partial bucket.
-    EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
-    vector<ValueBucket> buckets = valueProducer.mPastBuckets.begin()->second;
+    EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
+    vector<ValueBucket> buckets = valueProducer->mPastBuckets.begin()->second;
     EXPECT_EQ(2UL, buckets.size());
     // Full bucket (2 - 1)
     EXPECT_EQ(1, buckets[0].values[0].long_value);
@@ -284,12 +305,7 @@
  * Tests pulled atoms with filtering
  */
 TEST(ValueMetricProducerTest, TestPulledEventsWithFiltering) {
-    ValueMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(ONE_MINUTE);
-    metric.mutable_value_field()->set_field(tagId);
-    metric.mutable_value_field()->add_child()->set_field(2);
-    metric.set_max_pull_delay_sec(INT_MAX);
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); 
 
     UidMap uidMap;
     SimpleAtomMatcher atomMatcher;
@@ -315,9 +331,10 @@
                 return true;
             }));
 
-    ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
-                                      logEventMatcherIndex, eventMatcherWizard, tagId,
-                                      bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+    sp<ValueMetricProducer> valueProducer = new ValueMetricProducer(
+            kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
+            logEventMatcherIndex, eventMatcherWizard, tagId,
+            bucketStartTimeNs, bucketStartTimeNs, pullerManager);
 
     vector<shared_ptr<LogEvent>> allData;
     allData.clear();
@@ -327,18 +344,18 @@
     event->init();
     allData.push_back(event);
 
-    valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+    valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
     // has one slice
-    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
     ValueMetricProducer::Interval curInterval =
-            valueProducer.mCurrentSlicedBucket.begin()->second[0];
+            valueProducer->mCurrentSlicedBucket.begin()->second[0];
 
     EXPECT_EQ(true, curInterval.hasBase);
     EXPECT_EQ(11, curInterval.base.long_value);
     EXPECT_EQ(false, curInterval.hasValue);
     EXPECT_EQ(8, curInterval.value.long_value);
-    EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
-    EXPECT_EQ(8, valueProducer.mPastBuckets.begin()->second[0].values[0].long_value);
+    EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
+    EXPECT_EQ(8, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
 
     allData.clear();
     event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 1);
@@ -346,16 +363,16 @@
     event->write(23);
     event->init();
     allData.push_back(event);
-    valueProducer.onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
+    valueProducer->onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
     // No new data seen, so data has been cleared.
-    EXPECT_EQ(0UL, valueProducer.mCurrentSlicedBucket.size());
+    EXPECT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
 
     EXPECT_EQ(true, curInterval.hasBase);
     EXPECT_EQ(11, curInterval.base.long_value);
     EXPECT_EQ(false, curInterval.hasValue);
     EXPECT_EQ(8, curInterval.value.long_value);
-    EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
-    EXPECT_EQ(8, valueProducer.mPastBuckets.begin()->second[0].values[0].long_value);
+    EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
+    EXPECT_EQ(8, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
 
     allData.clear();
     event = make_shared<LogEvent>(tagId, bucket4StartTimeNs + 1);
@@ -363,46 +380,30 @@
     event->write(36);
     event->init();
     allData.push_back(event);
-    valueProducer.onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
-    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    valueProducer->onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
+    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
 
     // the base was reset
     EXPECT_EQ(true, curInterval.hasBase);
     EXPECT_EQ(36, curInterval.base.long_value);
     EXPECT_EQ(false, curInterval.hasValue);
-    EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
-    EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
-    EXPECT_EQ(8, valueProducer.mPastBuckets.begin()->second.back().values[0].long_value);
+    EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
+    EXPECT_EQ(1UL, valueProducer->mPastBuckets.begin()->second.size());
+    EXPECT_EQ(8, valueProducer->mPastBuckets.begin()->second.back().values[0].long_value);
 }
 
 /*
  * Tests pulled atoms with no conditions and take absolute value after reset
  */
 TEST(ValueMetricProducerTest, TestPulledEventsTakeAbsoluteValueOnReset) {
-    ValueMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(ONE_MINUTE);
-    metric.mutable_value_field()->set_field(tagId);
-    metric.mutable_value_field()->add_child()->set_field(2);
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
     metric.set_use_absolute_value_on_reset(true);
-    metric.set_max_pull_delay_sec(INT_MAX);
 
-    UidMap uidMap;
-    SimpleAtomMatcher atomMatcher;
-    atomMatcher.set_atom_id(tagId);
-    sp<EventMatcherWizard> eventMatcherWizard =
-            new EventMatcherWizard({new SimpleLogMatchingTracker(
-                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
-    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
     EXPECT_CALL(*pullerManager, Pull(tagId, _)).WillOnce(Return(true));
-
-    ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
-                                      logEventMatcherIndex, eventMatcherWizard, tagId,
-                                      bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+    sp<ValueMetricProducer> valueProducer =
+            ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
 
     vector<shared_ptr<LogEvent>> allData;
     allData.clear();
@@ -412,15 +413,15 @@
     event->init();
     allData.push_back(event);
 
-    valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+    valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
     // has one slice
-    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-    ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+    ValueMetricProducer::Interval curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
 
     EXPECT_EQ(true, curInterval.hasBase);
     EXPECT_EQ(11, curInterval.base.long_value);
     EXPECT_EQ(false, curInterval.hasValue);
-    EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
+    EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
 
     allData.clear();
     event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 1);
@@ -428,16 +429,16 @@
     event->write(10);
     event->init();
     allData.push_back(event);
-    valueProducer.onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
+    valueProducer->onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
     // has one slice
-    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
     EXPECT_EQ(true, curInterval.hasBase);
     EXPECT_EQ(10, curInterval.base.long_value);
     EXPECT_EQ(false, curInterval.hasValue);
     EXPECT_EQ(10, curInterval.value.long_value);
-    EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
-    EXPECT_EQ(10, valueProducer.mPastBuckets.begin()->second.back().values[0].long_value);
+    EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
+    EXPECT_EQ(10, valueProducer->mPastBuckets.begin()->second.back().values[0].long_value);
 
     allData.clear();
     event = make_shared<LogEvent>(tagId, bucket4StartTimeNs + 1);
@@ -445,45 +446,28 @@
     event->write(36);
     event->init();
     allData.push_back(event);
-    valueProducer.onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
-    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    valueProducer->onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
+    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
     EXPECT_EQ(true, curInterval.hasBase);
     EXPECT_EQ(36, curInterval.base.long_value);
     EXPECT_EQ(false, curInterval.hasValue);
     EXPECT_EQ(26, curInterval.value.long_value);
-    EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
-    EXPECT_EQ(2UL, valueProducer.mPastBuckets.begin()->second.size());
-    EXPECT_EQ(10, valueProducer.mPastBuckets.begin()->second[0].values[0].long_value);
-    EXPECT_EQ(26, valueProducer.mPastBuckets.begin()->second[1].values[0].long_value);
+    EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
+    EXPECT_EQ(2UL, valueProducer->mPastBuckets.begin()->second.size());
+    EXPECT_EQ(10, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
+    EXPECT_EQ(26, valueProducer->mPastBuckets.begin()->second[1].values[0].long_value);
 }
 
 /*
  * Tests pulled atoms with no conditions and take zero value after reset
  */
 TEST(ValueMetricProducerTest, TestPulledEventsTakeZeroOnReset) {
-    ValueMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(ONE_MINUTE);
-    metric.mutable_value_field()->set_field(tagId);
-    metric.mutable_value_field()->add_child()->set_field(2);
-    metric.set_max_pull_delay_sec(INT_MAX);
-
-    UidMap uidMap;
-    SimpleAtomMatcher atomMatcher;
-    atomMatcher.set_atom_id(tagId);
-    sp<EventMatcherWizard> eventMatcherWizard =
-            new EventMatcherWizard({new SimpleLogMatchingTracker(
-                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); 
     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
-    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
     EXPECT_CALL(*pullerManager, Pull(tagId, _)).WillOnce(Return(false));
-
-    ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
-                                      logEventMatcherIndex, eventMatcherWizard, tagId,
-                                      bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+    sp<ValueMetricProducer> valueProducer =
+            ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
 
     vector<shared_ptr<LogEvent>> allData;
     allData.clear();
@@ -493,15 +477,15 @@
     event->init();
     allData.push_back(event);
 
-    valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+    valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
     // has one slice
-    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-    ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+    ValueMetricProducer::Interval curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
 
     EXPECT_EQ(true, curInterval.hasBase);
     EXPECT_EQ(11, curInterval.base.long_value);
     EXPECT_EQ(false, curInterval.hasValue);
-    EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
+    EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
 
     allData.clear();
     event = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 1);
@@ -509,14 +493,14 @@
     event->write(10);
     event->init();
     allData.push_back(event);
-    valueProducer.onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
+    valueProducer->onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
     // has one slice
-    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
     EXPECT_EQ(true, curInterval.hasBase);
     EXPECT_EQ(10, curInterval.base.long_value);
     EXPECT_EQ(false, curInterval.hasValue);
-    EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
+    EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
 
     allData.clear();
     event = make_shared<LogEvent>(tagId, bucket4StartTimeNs + 1);
@@ -524,39 +508,24 @@
     event->write(36);
     event->init();
     allData.push_back(event);
-    valueProducer.onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
-    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    valueProducer->onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
+    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
     EXPECT_EQ(true, curInterval.hasBase);
     EXPECT_EQ(36, curInterval.base.long_value);
     EXPECT_EQ(false, curInterval.hasValue);
     EXPECT_EQ(26, curInterval.value.long_value);
-    EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
-    EXPECT_EQ(26, valueProducer.mPastBuckets.begin()->second[0].values[0].long_value);
+    EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
+    EXPECT_EQ(26, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
 }
 
 /*
  * Test pulled event with non sliced condition.
  */
 TEST(ValueMetricProducerTest, TestEventsWithNonSlicedCondition) {
-    ValueMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(ONE_MINUTE);
-    metric.mutable_value_field()->set_field(tagId);
-    metric.mutable_value_field()->add_child()->set_field(2);
-    metric.set_condition(StringToId("SCREEN_ON"));
-    metric.set_max_pull_delay_sec(INT_MAX);
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
 
-    UidMap uidMap;
-    SimpleAtomMatcher atomMatcher;
-    atomMatcher.set_atom_id(tagId);
-    sp<EventMatcherWizard> eventMatcherWizard =
-            new EventMatcherWizard({new SimpleLogMatchingTracker(
-                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
-    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
 
     EXPECT_CALL(*pullerManager, Pull(tagId, _))
             .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
@@ -578,19 +547,19 @@
                 return true;
             }));
 
-    ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
-                                      eventMatcherWizard, tagId, bucketStartTimeNs,
-                                      bucketStartTimeNs, pullerManager);
-    valueProducer.onConditionChanged(true, bucketStartTimeNs + 8);
+    sp<ValueMetricProducer> valueProducer =
+            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
+
+    valueProducer->onConditionChanged(true, bucketStartTimeNs + 8);
 
     // has one slice
-    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-    ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+    ValueMetricProducer::Interval curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
     // startUpdated:false sum:0 start:100
     EXPECT_EQ(true, curInterval.hasBase);
     EXPECT_EQ(100, curInterval.base.long_value);
     EXPECT_EQ(false, curInterval.hasValue);
-    EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
+    EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
 
     vector<shared_ptr<LogEvent>> allData;
     allData.clear();
@@ -599,34 +568,30 @@
     event->write(110);
     event->init();
     allData.push_back(event);
-    valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+    valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
 
     // has one slice
-    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
     EXPECT_EQ(true, curInterval.hasBase);
     EXPECT_EQ(110, curInterval.base.long_value);
     EXPECT_EQ(false, curInterval.hasValue);
     EXPECT_EQ(10, curInterval.value.long_value);
-    EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
-    EXPECT_EQ(10, valueProducer.mPastBuckets.begin()->second[0].values[0].long_value);
+    EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
+    EXPECT_EQ(10, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
 
-    valueProducer.onConditionChanged(false, bucket2StartTimeNs + 1);
+    valueProducer->onConditionChanged(false, bucket2StartTimeNs + 1);
 
     // has one slice
-    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
     EXPECT_EQ(true, curInterval.hasValue);
     EXPECT_EQ(10, curInterval.value.long_value);
     EXPECT_EQ(false, curInterval.hasBase);
 }
 
 TEST(ValueMetricProducerTest, TestPushedEventsWithUpgrade) {
-    ValueMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(ONE_MINUTE);
-    metric.mutable_value_field()->set_field(tagId);
-    metric.mutable_value_field()->add_child()->set_field(2);
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
 
     UidMap uidMap;
     SimpleAtomMatcher atomMatcher;
@@ -670,12 +635,7 @@
 }
 
 TEST(ValueMetricProducerTest, TestPulledValueWithUpgrade) {
-    ValueMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(ONE_MINUTE);
-    metric.mutable_value_field()->set_field(tagId);
-    metric.mutable_value_field()->add_child()->set_field(2);
-    metric.set_max_pull_delay_sec(INT_MAX);
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); 
 
     UidMap uidMap;
     SimpleAtomMatcher atomMatcher;
@@ -733,12 +693,7 @@
 }
 
 TEST(ValueMetricProducerTest, TestPulledWithAppUpgradeDisabled) {
-    ValueMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(ONE_MINUTE);
-    metric.mutable_value_field()->set_field(tagId);
-    metric.mutable_value_field()->add_child()->set_field(2);
-    metric.set_max_pull_delay_sec(INT_MAX);
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); 
     metric.set_split_bucket_for_app_upgrade(false);
 
     UidMap uidMap;
@@ -773,24 +728,9 @@
 }
 
 TEST(ValueMetricProducerTest, TestPulledValueWithUpgradeWhileConditionFalse) {
-    ValueMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(ONE_MINUTE);
-    metric.mutable_value_field()->set_field(tagId);
-    metric.mutable_value_field()->add_child()->set_field(2);
-    metric.set_condition(StringToId("SCREEN_ON"));
-    metric.set_max_pull_delay_sec(INT_MAX);
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
 
-    UidMap uidMap;
-    SimpleAtomMatcher atomMatcher;
-    atomMatcher.set_atom_id(tagId);
-    sp<EventMatcherWizard> eventMatcherWizard =
-            new EventMatcherWizard({new SimpleLogMatchingTracker(
-                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
-    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
     EXPECT_CALL(*pullerManager, Pull(tagId, _))
             .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
                 data->clear();
@@ -810,29 +750,25 @@
                 data->push_back(event);
                 return true;
             }));
-    ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
-                                      eventMatcherWizard, tagId, bucketStartTimeNs,
-                                      bucketStartTimeNs, pullerManager);
-    valueProducer.onConditionChanged(true, bucketStartTimeNs + 1);
+    sp<ValueMetricProducer> valueProducer =
+            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
 
-    valueProducer.onConditionChanged(false, bucket2StartTimeNs-100);
-    EXPECT_FALSE(valueProducer.mCondition);
+    valueProducer->onConditionChanged(true, bucketStartTimeNs + 1);
 
-    valueProducer.notifyAppUpgrade(bucket2StartTimeNs-50, "ANY.APP", 1, 1);
+    valueProducer->onConditionChanged(false, bucket2StartTimeNs-100);
+    EXPECT_FALSE(valueProducer->mCondition);
+
+    valueProducer->notifyAppUpgrade(bucket2StartTimeNs-50, "ANY.APP", 1, 1);
     // Expect one full buckets already done and starting a partial bucket.
-    EXPECT_EQ(bucket2StartTimeNs-50, valueProducer.mCurrentBucketStartTimeNs);
-    EXPECT_EQ(1UL, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
-    EXPECT_EQ(bucketStartTimeNs, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketStartNs);
-    EXPECT_EQ(20L, valueProducer.mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].values[0].long_value);
-    EXPECT_FALSE(valueProducer.mCondition);
+    EXPECT_EQ(bucket2StartTimeNs-50, valueProducer->mCurrentBucketStartTimeNs);
+    EXPECT_EQ(1UL, valueProducer->mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY].size());
+    EXPECT_EQ(bucketStartTimeNs, valueProducer->mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].mBucketStartNs);
+    EXPECT_EQ(20L, valueProducer->mPastBuckets[DEFAULT_METRIC_DIMENSION_KEY][0].values[0].long_value);
+    EXPECT_FALSE(valueProducer->mCondition);
 }
 
 TEST(ValueMetricProducerTest, TestPushedEventsWithoutCondition) {
-    ValueMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(ONE_MINUTE);
-    metric.mutable_value_field()->set_field(tagId);
-    metric.mutable_value_field()->add_child()->set_field(2);
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
 
     UidMap uidMap;
     SimpleAtomMatcher atomMatcher;
@@ -876,11 +812,7 @@
 }
 
 TEST(ValueMetricProducerTest, TestPushedEventsWithCondition) {
-    ValueMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(ONE_MINUTE);
-    metric.mutable_value_field()->set_field(tagId);
-    metric.mutable_value_field()->add_child()->set_field(2);
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
 
     UidMap uidMap;
     SimpleAtomMatcher atomMatcher;
@@ -894,6 +826,7 @@
     ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
                                       eventMatcherWizard, -1, bucketStartTimeNs, bucketStartTimeNs,
                                       pullerManager);
+    valueProducer.mCondition = ConditionState::kFalse;
 
     shared_ptr<LogEvent> event1 = make_shared<LogEvent>(tagId, bucketStartTimeNs + 10);
     event1->write(1);
@@ -955,11 +888,7 @@
     const int32_t refPeriodSec = 3;
     alert.set_refractory_period_secs(refPeriodSec);
 
-    ValueMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(ONE_MINUTE);
-    metric.mutable_value_field()->set_field(tagId);
-    metric.mutable_value_field()->add_child()->set_field(2);
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
 
     UidMap uidMap;
     SimpleAtomMatcher atomMatcher;
@@ -1036,28 +965,11 @@
 
 // Test value metric no condition, the pull on bucket boundary come in time and too late
 TEST(ValueMetricProducerTest, TestBucketBoundaryNoCondition) {
-    ValueMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(ONE_MINUTE);
-    metric.mutable_value_field()->set_field(tagId);
-    metric.mutable_value_field()->add_child()->set_field(2);
-    metric.set_max_pull_delay_sec(INT_MAX);
-
-    UidMap uidMap;
-    SimpleAtomMatcher atomMatcher;
-    atomMatcher.set_atom_id(tagId);
-    sp<EventMatcherWizard> eventMatcherWizard =
-            new EventMatcherWizard({new SimpleLogMatchingTracker(
-                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); 
     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
-    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
     EXPECT_CALL(*pullerManager, Pull(tagId, _)).WillOnce(Return(true));
-
-    ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
-                                      logEventMatcherIndex, eventMatcherWizard, tagId,
-                                      bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+    sp<ValueMetricProducer> valueProducer =
+            ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
 
     vector<shared_ptr<LogEvent>> allData;
     // pull 1
@@ -1068,16 +980,16 @@
     event->init();
     allData.push_back(event);
 
-    valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+    valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
     // has one slice
-    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-    ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+    ValueMetricProducer::Interval curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
 
     // startUpdated:true sum:0 start:11
     EXPECT_EQ(true, curInterval.hasBase);
     EXPECT_EQ(11, curInterval.base.long_value);
     EXPECT_EQ(false, curInterval.hasValue);
-    EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
+    EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
 
     // pull 2 at correct time
     allData.clear();
@@ -1086,16 +998,16 @@
     event->write(23);
     event->init();
     allData.push_back(event);
-    valueProducer.onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
+    valueProducer->onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
     // has one slice
-    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
     // tartUpdated:false sum:12
     EXPECT_EQ(true, curInterval.hasBase);
     EXPECT_EQ(23, curInterval.base.long_value);
     EXPECT_EQ(false, curInterval.hasValue);
-    EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
-    EXPECT_EQ(12, valueProducer.mPastBuckets.begin()->second.back().values[0].long_value);
+    EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
+    EXPECT_EQ(12, valueProducer->mPastBuckets.begin()->second.back().values[0].long_value);
 
     // pull 3 come late.
     // The previous bucket gets closed with error. (Has start value 23, no ending)
@@ -1107,16 +1019,16 @@
     event->write(36);
     event->init();
     allData.push_back(event);
-    valueProducer.onDataPulled(allData, /** succeed */ true, bucket6StartTimeNs);
-    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    valueProducer->onDataPulled(allData, /** succeed */ true, bucket6StartTimeNs);
+    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
     // startUpdated:false sum:12
     EXPECT_EQ(true, curInterval.hasBase);
     EXPECT_EQ(36, curInterval.base.long_value);
     EXPECT_EQ(false, curInterval.hasValue);
-    EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
-    EXPECT_EQ(1UL, valueProducer.mPastBuckets.begin()->second.size());
-    EXPECT_EQ(12, valueProducer.mPastBuckets.begin()->second.back().values[0].long_value);
+    EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
+    EXPECT_EQ(1UL, valueProducer->mPastBuckets.begin()->second.size());
+    EXPECT_EQ(12, valueProducer->mPastBuckets.begin()->second.back().values[0].long_value);
 }
 
 /*
@@ -1124,25 +1036,9 @@
  * was delivered late.
  */
 TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition) {
-    ValueMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(ONE_MINUTE);
-    metric.mutable_value_field()->set_field(tagId);
-    metric.mutable_value_field()->add_child()->set_field(2);
-    metric.set_condition(StringToId("SCREEN_ON"));
-    metric.set_max_pull_delay_sec(INT_MAX);
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
 
-    UidMap uidMap;
-    SimpleAtomMatcher atomMatcher;
-    atomMatcher.set_atom_id(tagId);
-    sp<EventMatcherWizard> eventMatcherWizard =
-            new EventMatcherWizard({new SimpleLogMatchingTracker(
-                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
-    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
-
     EXPECT_CALL(*pullerManager, Pull(tagId, _))
             // condition becomes true
             .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
@@ -1164,27 +1060,26 @@
                 data->push_back(event);
                 return true;
             }));
+    sp<ValueMetricProducer> valueProducer =
+            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
 
-    ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
-                                      eventMatcherWizard, tagId, bucketStartTimeNs,
-                                      bucketStartTimeNs, pullerManager);
-    valueProducer.onConditionChanged(true, bucketStartTimeNs + 8);
+    valueProducer->onConditionChanged(true, bucketStartTimeNs + 8);
 
     // has one slice
-    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-    ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+    ValueMetricProducer::Interval curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
     EXPECT_EQ(true, curInterval.hasBase);
     EXPECT_EQ(100, curInterval.base.long_value);
     EXPECT_EQ(false, curInterval.hasValue);
-    EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
+    EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
 
     // pull on bucket boundary come late, condition change happens before it
-    valueProducer.onConditionChanged(false, bucket2StartTimeNs + 1);
-    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    valueProducer->onConditionChanged(false, bucket2StartTimeNs + 1);
+    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
     EXPECT_EQ(false, curInterval.hasBase);
     EXPECT_EQ(true, curInterval.hasValue);
     EXPECT_EQ(20, curInterval.value.long_value);
-    EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
+    EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
 
     // Now the alarm is delivered.
     // since the condition turned to off before this pull finish, it has no effect
@@ -1195,13 +1090,13 @@
     event->write(110);
     event->init();
     allData.push_back(event);
-    valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+    valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
 
-    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
     EXPECT_EQ(false, curInterval.hasBase);
     EXPECT_EQ(true, curInterval.hasValue);
     EXPECT_EQ(20, curInterval.value.long_value);
-    EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
+    EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
 }
 
 /*
@@ -1209,25 +1104,9 @@
  * change to false, and then true again. This is due to alarm delivered late.
  */
 TEST(ValueMetricProducerTest, TestBucketBoundaryWithCondition2) {
-    ValueMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(ONE_MINUTE);
-    metric.mutable_value_field()->set_field(tagId);
-    metric.mutable_value_field()->add_child()->set_field(2);
-    metric.set_condition(StringToId("SCREEN_ON"));
-    metric.set_max_pull_delay_sec(INT_MAX);
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
 
-    UidMap uidMap;
-    SimpleAtomMatcher atomMatcher;
-    atomMatcher.set_atom_id(tagId);
-    sp<EventMatcherWizard> eventMatcherWizard =
-            new EventMatcherWizard({new SimpleLogMatchingTracker(
-                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillRepeatedly(Return());
-    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
-
     EXPECT_CALL(*pullerManager, Pull(tagId, _))
             // condition becomes true
             .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
@@ -1260,36 +1139,36 @@
                 return true;
             }));
 
-    ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
-                                      eventMatcherWizard, tagId, bucketStartTimeNs,
-                                      bucketStartTimeNs, pullerManager);
-    valueProducer.onConditionChanged(true, bucketStartTimeNs + 8);
+    sp<ValueMetricProducer> valueProducer =
+            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
+
+    valueProducer->onConditionChanged(true, bucketStartTimeNs + 8);
 
     // has one slice
-    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-    ValueMetricProducer::Interval curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+    ValueMetricProducer::Interval curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
     // startUpdated:false sum:0 start:100
     EXPECT_EQ(true, curInterval.hasBase);
     EXPECT_EQ(100, curInterval.base.long_value);
     EXPECT_EQ(false, curInterval.hasValue);
-    EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
+    EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
 
     // pull on bucket boundary come late, condition change happens before it
-    valueProducer.onConditionChanged(false, bucket2StartTimeNs + 1);
-    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    valueProducer->onConditionChanged(false, bucket2StartTimeNs + 1);
+    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
     EXPECT_EQ(false, curInterval.hasBase);
     EXPECT_EQ(true, curInterval.hasValue);
     EXPECT_EQ(20, curInterval.value.long_value);
-    EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
+    EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
 
     // condition changed to true again, before the pull alarm is delivered
-    valueProducer.onConditionChanged(true, bucket2StartTimeNs + 25);
-    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    valueProducer->onConditionChanged(true, bucket2StartTimeNs + 25);
+    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
     EXPECT_EQ(true, curInterval.hasBase);
     EXPECT_EQ(130, curInterval.base.long_value);
     EXPECT_EQ(true, curInterval.hasValue);
     EXPECT_EQ(20, curInterval.value.long_value);
-    EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
+    EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
 
     // Now the alarm is delivered, but it is considered late, the bucket is invalidated.
     vector<shared_ptr<LogEvent>> allData;
@@ -1299,22 +1178,18 @@
     event->write(110);
     event->init();
     allData.push_back(event);
-    valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+    valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
 
-    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
     EXPECT_EQ(false, curInterval.hasBase);
     EXPECT_EQ(130, curInterval.base.long_value);
     EXPECT_EQ(true, curInterval.hasValue);
     EXPECT_EQ(20, curInterval.value.long_value);
-    EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
+    EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
 }
 
 TEST(ValueMetricProducerTest, TestPushedAggregateMin) {
-    ValueMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(ONE_MINUTE);
-    metric.mutable_value_field()->set_field(tagId);
-    metric.mutable_value_field()->add_child()->set_field(2);
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
     metric.set_aggregation_type(ValueMetric::MIN);
 
     UidMap uidMap;
@@ -1359,11 +1234,7 @@
 }
 
 TEST(ValueMetricProducerTest, TestPushedAggregateMax) {
-    ValueMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(ONE_MINUTE);
-    metric.mutable_value_field()->set_field(tagId);
-    metric.mutable_value_field()->add_child()->set_field(2);
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
     metric.set_aggregation_type(ValueMetric::MAX);
 
     UidMap uidMap;
@@ -1408,11 +1279,7 @@
 }
 
 TEST(ValueMetricProducerTest, TestPushedAggregateAvg) {
-    ValueMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(ONE_MINUTE);
-    metric.mutable_value_field()->set_field(tagId);
-    metric.mutable_value_field()->add_child()->set_field(2);
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
     metric.set_aggregation_type(ValueMetric::AVG);
 
     UidMap uidMap;
@@ -1460,11 +1327,7 @@
 }
 
 TEST(ValueMetricProducerTest, TestPushedAggregateSum) {
-    ValueMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(ONE_MINUTE);
-    metric.mutable_value_field()->set_field(tagId);
-    metric.mutable_value_field()->add_child()->set_field(2);
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
     metric.set_aggregation_type(ValueMetric::SUM);
 
     UidMap uidMap;
@@ -1509,11 +1372,7 @@
 }
 
 TEST(ValueMetricProducerTest, TestSkipZeroDiffOutput) {
-    ValueMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(ONE_MINUTE);
-    metric.mutable_value_field()->set_field(tagId);
-    metric.mutable_value_field()->add_child()->set_field(2);
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
     metric.set_aggregation_type(ValueMetric::MIN);
     metric.set_use_diff(true);
 
@@ -1584,11 +1443,7 @@
 }
 
 TEST(ValueMetricProducerTest, TestSkipZeroDiffOutputMultiValue) {
-    ValueMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(ONE_MINUTE);
-    metric.mutable_value_field()->set_field(tagId);
-    metric.mutable_value_field()->add_child()->set_field(2);
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
     metric.mutable_value_field()->add_child()->set_field(3);
     metric.set_aggregation_type(ValueMetric::MIN);
     metric.set_use_diff(true);
@@ -1694,26 +1549,12 @@
  * Tests zero default base.
  */
 TEST(ValueMetricProducerTest, TestUseZeroDefaultBase) {
-    ValueMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(ONE_MINUTE);
-    metric.mutable_value_field()->set_field(tagId);
-    metric.mutable_value_field()->add_child()->set_field(2);
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
     metric.mutable_dimensions_in_what()->set_field(tagId);
     metric.mutable_dimensions_in_what()->add_child()->set_field(1);
     metric.set_use_zero_default_base(true);
-    metric.set_max_pull_delay_sec(INT_MAX);
 
-    UidMap uidMap;
-    SimpleAtomMatcher atomMatcher;
-    atomMatcher.set_atom_id(tagId);
-    sp<EventMatcherWizard> eventMatcherWizard =
-            new EventMatcherWizard({new SimpleLogMatchingTracker(
-                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
-    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
     EXPECT_CALL(*pullerManager, Pull(tagId, _))
             .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
                 data->clear();
@@ -1725,19 +1566,18 @@
                 return true;
             }));
 
-    ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
-                                      logEventMatcherIndex, eventMatcherWizard, tagId,
-                                      bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+    sp<ValueMetricProducer> valueProducer =
+            ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
 
-    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-    auto iter = valueProducer.mCurrentSlicedBucket.begin();
+    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+    auto iter = valueProducer->mCurrentSlicedBucket.begin();
     auto& interval1 = iter->second[0];
     EXPECT_EQ(1, iter->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
     EXPECT_EQ(true, interval1.hasBase);
     EXPECT_EQ(3, interval1.base.long_value);
     EXPECT_EQ(false, interval1.hasValue);
-    EXPECT_EQ(true, valueProducer.mHasGlobalBase);
-    EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
+    EXPECT_EQ(true, valueProducer->mHasGlobalBase);
+    EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
     vector<shared_ptr<LogEvent>> allData;
 
     allData.clear();
@@ -1752,15 +1592,15 @@
     allData.push_back(event1);
     allData.push_back(event2);
 
-    valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
-    EXPECT_EQ(2UL, valueProducer.mCurrentSlicedBucket.size());
+    valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+    EXPECT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
     EXPECT_EQ(true, interval1.hasBase);
     EXPECT_EQ(11, interval1.base.long_value);
     EXPECT_EQ(false, interval1.hasValue);
     EXPECT_EQ(8, interval1.value.long_value);
 
-    auto it = valueProducer.mCurrentSlicedBucket.begin();
-    for (; it != valueProducer.mCurrentSlicedBucket.end(); it++) {
+    auto it = valueProducer->mCurrentSlicedBucket.begin();
+    for (; it != valueProducer->mCurrentSlicedBucket.end(); it++) {
         if (it != iter) {
             break;
         }
@@ -1773,8 +1613,8 @@
     EXPECT_EQ(false, interval2.hasValue);
     EXPECT_EQ(4, interval2.value.long_value);
 
-    EXPECT_EQ(2UL, valueProducer.mPastBuckets.size());
-    auto iterator = valueProducer.mPastBuckets.begin();
+    EXPECT_EQ(2UL, valueProducer->mPastBuckets.size());
+    auto iterator = valueProducer->mPastBuckets.begin();
     EXPECT_EQ(8, iterator->second[0].values[0].long_value);
     iterator++;
     EXPECT_EQ(4, iterator->second[0].values[0].long_value);
@@ -1784,26 +1624,12 @@
  * Tests using zero default base with failed pull.
  */
 TEST(ValueMetricProducerTest, TestUseZeroDefaultBaseWithPullFailures) {
-    ValueMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(ONE_MINUTE);
-    metric.mutable_value_field()->set_field(tagId);
-    metric.mutable_value_field()->add_child()->set_field(2);
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
     metric.mutable_dimensions_in_what()->set_field(tagId);
     metric.mutable_dimensions_in_what()->add_child()->set_field(1);
     metric.set_use_zero_default_base(true);
-    metric.set_max_pull_delay_sec(INT_MAX);
 
-    UidMap uidMap;
-    SimpleAtomMatcher atomMatcher;
-    atomMatcher.set_atom_id(tagId);
-    sp<EventMatcherWizard> eventMatcherWizard =
-            new EventMatcherWizard({new SimpleLogMatchingTracker(
-                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
-    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
     EXPECT_CALL(*pullerManager, Pull(tagId, _))
             .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
                 data->clear();
@@ -1815,19 +1641,18 @@
                 return true;
             }));
 
-    ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
-                                      logEventMatcherIndex, eventMatcherWizard, tagId,
-                                      bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+    sp<ValueMetricProducer> valueProducer =
+            ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
 
-    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-    auto iter = valueProducer.mCurrentSlicedBucket.begin();
+    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+    auto iter = valueProducer->mCurrentSlicedBucket.begin();
     auto& interval1 = iter->second[0];
     EXPECT_EQ(1, iter->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
     EXPECT_EQ(true, interval1.hasBase);
     EXPECT_EQ(3, interval1.base.long_value);
     EXPECT_EQ(false, interval1.hasValue);
-    EXPECT_EQ(true, valueProducer.mHasGlobalBase);
-    EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
+    EXPECT_EQ(true, valueProducer->mHasGlobalBase);
+    EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
     vector<shared_ptr<LogEvent>> allData;
 
     allData.clear();
@@ -1842,15 +1667,15 @@
     allData.push_back(event1);
     allData.push_back(event2);
 
-    valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
-    EXPECT_EQ(2UL, valueProducer.mCurrentSlicedBucket.size());
+    valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+    EXPECT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
     EXPECT_EQ(true, interval1.hasBase);
     EXPECT_EQ(11, interval1.base.long_value);
     EXPECT_EQ(false, interval1.hasValue);
     EXPECT_EQ(8, interval1.value.long_value);
 
-    auto it = valueProducer.mCurrentSlicedBucket.begin();
-    for (; it != valueProducer.mCurrentSlicedBucket.end(); it++) {
+    auto it = valueProducer->mCurrentSlicedBucket.begin();
+    for (; it != valueProducer->mCurrentSlicedBucket.end(); it++) {
         if (it != iter) {
             break;
         }
@@ -1862,7 +1687,7 @@
     EXPECT_EQ(4, interval2.base.long_value);
     EXPECT_EQ(false, interval2.hasValue);
     EXPECT_EQ(4, interval2.value.long_value);
-    EXPECT_EQ(2UL, valueProducer.mPastBuckets.size());
+    EXPECT_EQ(2UL, valueProducer->mPastBuckets.size());
 
     // next pull somehow did not happen, skip to end of bucket 3
     allData.clear();
@@ -1871,16 +1696,16 @@
     event1->write(5);
     event1->init();
     allData.push_back(event1);
-    valueProducer.onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
+    valueProducer->onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
 
-    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
     EXPECT_EQ(true, interval2.hasBase);
     EXPECT_EQ(4, interval2.base.long_value);
     EXPECT_EQ(false, interval2.hasValue);
     EXPECT_EQ(true, interval1.hasBase);
     EXPECT_EQ(false, interval1.hasValue);
-    EXPECT_EQ(true, valueProducer.mHasGlobalBase);
-    EXPECT_EQ(2UL, valueProducer.mPastBuckets.size());
+    EXPECT_EQ(true, valueProducer->mHasGlobalBase);
+    EXPECT_EQ(2UL, valueProducer->mPastBuckets.size());
 
     allData.clear();
     event1 = make_shared<LogEvent>(tagId, bucket5StartTimeNs + 1);
@@ -1893,9 +1718,9 @@
     event2->write(5);
     event2->init();
     allData.push_back(event2);
-    valueProducer.onDataPulled(allData, /** succeed */ true, bucket5StartTimeNs);
+    valueProducer->onDataPulled(allData, /** succeed */ true, bucket5StartTimeNs);
 
-    EXPECT_EQ(2UL, valueProducer.mCurrentSlicedBucket.size());
+    EXPECT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
     EXPECT_EQ(true, interval2.hasBase);
     EXPECT_EQ(5, interval2.base.long_value);
     EXPECT_EQ(false, interval2.hasValue);
@@ -1904,33 +1729,19 @@
     EXPECT_EQ(13, interval1.base.long_value);
     EXPECT_EQ(false, interval1.hasValue);
     EXPECT_EQ(8, interval1.value.long_value);
-    EXPECT_EQ(true, valueProducer.mHasGlobalBase);
-    EXPECT_EQ(2UL, valueProducer.mPastBuckets.size());
+    EXPECT_EQ(true, valueProducer->mHasGlobalBase);
+    EXPECT_EQ(2UL, valueProducer->mPastBuckets.size());
 }
 
 /*
  * Tests trim unused dimension key if no new data is seen in an entire bucket.
  */
 TEST(ValueMetricProducerTest, TestTrimUnusedDimensionKey) {
-    ValueMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(ONE_MINUTE);
-    metric.mutable_value_field()->set_field(tagId);
-    metric.mutable_value_field()->add_child()->set_field(2);
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
     metric.mutable_dimensions_in_what()->set_field(tagId);
     metric.mutable_dimensions_in_what()->add_child()->set_field(1);
-    metric.set_max_pull_delay_sec(INT_MAX);
 
-    UidMap uidMap;
-    SimpleAtomMatcher atomMatcher;
-    atomMatcher.set_atom_id(tagId);
-    sp<EventMatcherWizard> eventMatcherWizard =
-            new EventMatcherWizard({new SimpleLogMatchingTracker(
-                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
-    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillOnce(Return());
     EXPECT_CALL(*pullerManager, Pull(tagId, _))
             .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
                 data->clear();
@@ -1942,18 +1753,17 @@
                 return true;
             }));
 
-    ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
-                                      logEventMatcherIndex, eventMatcherWizard, tagId,
-                                      bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+    sp<ValueMetricProducer> valueProducer =
+            ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
 
-    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-    auto iter = valueProducer.mCurrentSlicedBucket.begin();
+    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+    auto iter = valueProducer->mCurrentSlicedBucket.begin();
     auto& interval1 = iter->second[0];
     EXPECT_EQ(1, iter->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
     EXPECT_EQ(true, interval1.hasBase);
     EXPECT_EQ(3, interval1.base.long_value);
     EXPECT_EQ(false, interval1.hasValue);
-    EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
+    EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
     vector<shared_ptr<LogEvent>> allData;
 
     allData.clear();
@@ -1968,18 +1778,18 @@
     allData.push_back(event1);
     allData.push_back(event2);
 
-    valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
-    EXPECT_EQ(2UL, valueProducer.mCurrentSlicedBucket.size());
+    valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+    EXPECT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
     EXPECT_EQ(true, interval1.hasBase);
     EXPECT_EQ(11, interval1.base.long_value);
     EXPECT_EQ(false, interval1.hasValue);
     EXPECT_EQ(8, interval1.value.long_value);
     EXPECT_FALSE(interval1.seenNewData);
-    EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
-    EXPECT_EQ(8, valueProducer.mPastBuckets.begin()->second[0].values[0].long_value);
+    EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
+    EXPECT_EQ(8, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
 
-    auto it = valueProducer.mCurrentSlicedBucket.begin();
-    for (; it != valueProducer.mCurrentSlicedBucket.end(); it++) {
+    auto it = valueProducer->mCurrentSlicedBucket.begin();
+    for (; it != valueProducer->mCurrentSlicedBucket.end(); it++) {
         if (it != iter) {
             break;
         }
@@ -1991,7 +1801,7 @@
     EXPECT_EQ(4, interval2.base.long_value);
     EXPECT_EQ(false, interval2.hasValue);
     EXPECT_FALSE(interval2.seenNewData);
-    EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
+    EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
 
     // next pull somehow did not happen, skip to end of bucket 3
     allData.clear();
@@ -2000,17 +1810,17 @@
     event1->write(5);
     event1->init();
     allData.push_back(event1);
-    valueProducer.onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
+    valueProducer->onDataPulled(allData, /** succeed */ true, bucket4StartTimeNs);
 
 	// Only one interval left. One was trimmed.
-    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-    interval2 = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+    interval2 = valueProducer->mCurrentSlicedBucket.begin()->second[0];
     EXPECT_EQ(2, it->first.getDimensionKeyInWhat().getValues()[0].mValue.int_value);
     EXPECT_EQ(true, interval2.hasBase);
     EXPECT_EQ(5, interval2.base.long_value);
     EXPECT_EQ(false, interval2.hasValue);
     EXPECT_FALSE(interval2.seenNewData);
-    EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
+    EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
 
     allData.clear();
     event1 = make_shared<LogEvent>(tagId, bucket5StartTimeNs + 1);
@@ -2018,40 +1828,24 @@
     event1->write(14);
     event1->init();
     allData.push_back(event1);
-    valueProducer.onDataPulled(allData, /** succeed */ true, bucket5StartTimeNs);
+    valueProducer->onDataPulled(allData, /** succeed */ true, bucket5StartTimeNs);
 
-    interval2 = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    interval2 = valueProducer->mCurrentSlicedBucket.begin()->second[0];
     EXPECT_EQ(true, interval2.hasBase);
     EXPECT_EQ(14, interval2.base.long_value);
     EXPECT_EQ(false, interval2.hasValue);
     EXPECT_FALSE(interval2.seenNewData);
-    EXPECT_EQ(2UL, valueProducer.mPastBuckets.size());
-    auto iterator = valueProducer.mPastBuckets.begin();
+    EXPECT_EQ(2UL, valueProducer->mPastBuckets.size());
+    auto iterator = valueProducer->mPastBuckets.begin();
     EXPECT_EQ(9, iterator->second[0].values[0].long_value);
     iterator++;
     EXPECT_EQ(8, iterator->second[0].values[0].long_value);
 }
 
 TEST(ValueMetricProducerTest, TestResetBaseOnPullFailAfterConditionChange_EndOfBucket) {
-    ValueMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(ONE_MINUTE);
-    metric.mutable_value_field()->set_field(tagId);
-    metric.mutable_value_field()->add_child()->set_field(2);
-    metric.set_condition(StringToId("SCREEN_ON"));
-    metric.set_max_pull_delay_sec(INT_MAX);
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
 
-    UidMap uidMap;
-    SimpleAtomMatcher atomMatcher;
-    atomMatcher.set_atom_id(tagId);
-    sp<EventMatcherWizard> eventMatcherWizard =
-            new EventMatcherWizard({new SimpleLogMatchingTracker(
-                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
-    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
-
     // Used by onConditionChanged.
     EXPECT_CALL(*pullerManager, Pull(tagId, _))
             .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
@@ -2064,47 +1858,30 @@
                 return true;
             }));
 
-    ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
-                                      eventMatcherWizard, tagId, bucketStartTimeNs,
-                                      bucketStartTimeNs, pullerManager);
+    sp<ValueMetricProducer> valueProducer =
+            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
 
-    valueProducer.onConditionChanged(true, bucketStartTimeNs + 8);
+    valueProducer->onConditionChanged(true, bucketStartTimeNs + 8);
     // has one slice
-    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
     ValueMetricProducer::Interval& curInterval =
-            valueProducer.mCurrentSlicedBucket.begin()->second[0];
+            valueProducer->mCurrentSlicedBucket.begin()->second[0];
     EXPECT_EQ(true, curInterval.hasBase);
     EXPECT_EQ(100, curInterval.base.long_value);
     EXPECT_EQ(false, curInterval.hasValue);
 
     vector<shared_ptr<LogEvent>> allData;
-    valueProducer.onDataPulled(allData, /** succeed */ false, bucket2StartTimeNs);
-    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    valueProducer->onDataPulled(allData, /** succeed */ false, bucket2StartTimeNs);
+    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
     EXPECT_EQ(false, curInterval.hasBase);
     EXPECT_EQ(false, curInterval.hasValue);
-    EXPECT_EQ(false, valueProducer.mHasGlobalBase);
+    EXPECT_EQ(false, valueProducer->mHasGlobalBase);
 }
 
 TEST(ValueMetricProducerTest, TestResetBaseOnPullFailAfterConditionChange) {
-    ValueMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(ONE_MINUTE);
-    metric.mutable_value_field()->set_field(tagId);
-    metric.mutable_value_field()->add_child()->set_field(2);
-    metric.set_condition(StringToId("SCREEN_ON"));
-    metric.set_max_pull_delay_sec(INT_MAX);
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
 
-    UidMap uidMap;
-    SimpleAtomMatcher atomMatcher;
-    atomMatcher.set_atom_id(tagId);
-    sp<EventMatcherWizard> eventMatcherWizard =
-            new EventMatcherWizard({new SimpleLogMatchingTracker(
-                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
-    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
-
     EXPECT_CALL(*pullerManager, Pull(tagId, _))
             .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
                 data->clear();
@@ -2117,50 +1894,33 @@
             }))
             .WillOnce(Return(false));
 
-    ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
-                                      eventMatcherWizard, tagId, bucketStartTimeNs,
-                                      bucketStartTimeNs, pullerManager);
+    sp<ValueMetricProducer> valueProducer =
+            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
 
-    valueProducer.onConditionChanged(true, bucketStartTimeNs + 8);
+    valueProducer->onConditionChanged(true, bucketStartTimeNs + 8);
 
     // has one slice
-    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
     ValueMetricProducer::Interval& curInterval =
-            valueProducer.mCurrentSlicedBucket.begin()->second[0];
+            valueProducer->mCurrentSlicedBucket.begin()->second[0];
     EXPECT_EQ(true, curInterval.hasBase);
     EXPECT_EQ(100, curInterval.base.long_value);
     EXPECT_EQ(false, curInterval.hasValue);
-    EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
+    EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
 
-    valueProducer.onConditionChanged(false, bucketStartTimeNs + 20);
+    valueProducer->onConditionChanged(false, bucketStartTimeNs + 20);
 
     // has one slice
-    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
     EXPECT_EQ(false, curInterval.hasValue);
     EXPECT_EQ(false, curInterval.hasBase);
-    EXPECT_EQ(false, valueProducer.mHasGlobalBase);
+    EXPECT_EQ(false, valueProducer->mHasGlobalBase);
 }
 
 TEST(ValueMetricProducerTest, TestResetBaseOnPullFailBeforeConditionChange) {
-    ValueMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(ONE_MINUTE);
-    metric.mutable_value_field()->set_field(tagId);
-    metric.mutable_value_field()->add_child()->set_field(2);
-    metric.set_condition(StringToId("SCREEN_ON"));
-    metric.set_max_pull_delay_sec(INT_MAX);
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
 
-    UidMap uidMap;
-    SimpleAtomMatcher atomMatcher;
-    atomMatcher.set_atom_id(tagId);
-    sp<EventMatcherWizard> eventMatcherWizard =
-            new EventMatcherWizard({new SimpleLogMatchingTracker(
-                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
-    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
-
     EXPECT_CALL(*pullerManager, Pull(tagId, _))
             .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
                 data->clear();
@@ -2172,45 +1932,30 @@
                 return true;
             }));
 
-    ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
-                                      eventMatcherWizard, tagId, bucketStartTimeNs,
-                                      bucketStartTimeNs, pullerManager);
+    sp<ValueMetricProducer> valueProducer =
+            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
 
-    valueProducer.mCondition = ConditionState::kTrue;
+    valueProducer->mCondition = ConditionState::kTrue;
 
     vector<shared_ptr<LogEvent>> allData;
-    valueProducer.onDataPulled(allData, /** succeed */ false, bucketStartTimeNs);
-    EXPECT_EQ(0UL, valueProducer.mCurrentSlicedBucket.size());
+    valueProducer->onDataPulled(allData, /** succeed */ false, bucketStartTimeNs);
+    EXPECT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
 
-    valueProducer.onConditionChanged(false, bucketStartTimeNs + 1);
-    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    valueProducer->onConditionChanged(false, bucketStartTimeNs + 1);
+    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
     ValueMetricProducer::Interval& curInterval =
-            valueProducer.mCurrentSlicedBucket.begin()->second[0];
+            valueProducer->mCurrentSlicedBucket.begin()->second[0];
     EXPECT_EQ(false, curInterval.hasBase);
     EXPECT_EQ(false, curInterval.hasValue);
-    EXPECT_EQ(false, valueProducer.mHasGlobalBase);
+    EXPECT_EQ(false, valueProducer->mHasGlobalBase);
 }
 
 TEST(ValueMetricProducerTest, TestResetBaseOnPullDelayExceeded) {
-    ValueMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(ONE_MINUTE);
-    metric.mutable_value_field()->set_field(tagId);
-    metric.mutable_value_field()->add_child()->set_field(2);
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
     metric.set_condition(StringToId("SCREEN_ON"));
     metric.set_max_pull_delay_sec(0);
 
-    UidMap uidMap;
-    SimpleAtomMatcher atomMatcher;
-    atomMatcher.set_atom_id(tagId);
-    sp<EventMatcherWizard> eventMatcherWizard =
-            new EventMatcherWizard({new SimpleLogMatchingTracker(
-                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
-    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
-
     EXPECT_CALL(*pullerManager, Pull(tagId, _))
             .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
                 data->clear();
@@ -2222,25 +1967,18 @@
                 return true;
             }));
 
-    ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
-                                      eventMatcherWizard, tagId, bucketStartTimeNs,
-                                      bucketStartTimeNs, pullerManager);
+    sp<ValueMetricProducer> valueProducer =
+            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
 
-    valueProducer.mCondition = ConditionState::kFalse;
+    valueProducer->mCondition = ConditionState::kFalse;
 
     // Max delay is set to 0 so pull will exceed max delay.
-    valueProducer.onConditionChanged(true, bucketStartTimeNs + 1);
-    EXPECT_EQ(0UL, valueProducer.mCurrentSlicedBucket.size());
+    valueProducer->onConditionChanged(true, bucketStartTimeNs + 1);
+    EXPECT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
 }
 
 TEST(ValueMetricProducerTest, TestResetBaseOnPullTooLate) {
-    ValueMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(ONE_MINUTE);
-    metric.mutable_value_field()->set_field(tagId);
-    metric.mutable_value_field()->add_child()->set_field(2);
-    metric.set_condition(StringToId("SCREEN_ON"));
-    metric.set_max_pull_delay_sec(INT_MAX);
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
 
     UidMap uidMap;
     SimpleAtomMatcher atomMatcher;
@@ -2266,24 +2004,9 @@
 }
 
 TEST(ValueMetricProducerTest, TestBaseSetOnConditionChange) {
-    ValueMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(ONE_MINUTE);
-    metric.mutable_value_field()->set_field(tagId);
-    metric.mutable_value_field()->add_child()->set_field(2);
-    metric.set_condition(StringToId("SCREEN_ON"));
-    metric.set_max_pull_delay_sec(INT_MAX);
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
 
-    UidMap uidMap;
-    SimpleAtomMatcher atomMatcher;
-    atomMatcher.set_atom_id(tagId);
-    sp<EventMatcherWizard> eventMatcherWizard =
-            new EventMatcherWizard({new SimpleLogMatchingTracker(
-                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
-    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
     EXPECT_CALL(*pullerManager, Pull(tagId, _))
             .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
                 data->clear();
@@ -2295,44 +2018,27 @@
                 return true;
             }));
 
-    ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
-                                      eventMatcherWizard, tagId, bucketStartTimeNs,
-                                      bucketStartTimeNs, pullerManager);
+    sp<ValueMetricProducer> valueProducer =
+            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
 
-    valueProducer.mCondition = ConditionState::kFalse;
-    valueProducer.mHasGlobalBase = false;
+    valueProducer->mCondition = ConditionState::kFalse;
+    valueProducer->mHasGlobalBase = false;
 
-    valueProducer.onConditionChanged(true, bucketStartTimeNs + 1);
-    valueProducer.mHasGlobalBase = true;
-    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    valueProducer->onConditionChanged(true, bucketStartTimeNs + 1);
+    valueProducer->mHasGlobalBase = true;
+    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
     ValueMetricProducer::Interval& curInterval =
-            valueProducer.mCurrentSlicedBucket.begin()->second[0];
+            valueProducer->mCurrentSlicedBucket.begin()->second[0];
     EXPECT_EQ(true, curInterval.hasBase);
     EXPECT_EQ(100, curInterval.base.long_value);
     EXPECT_EQ(false, curInterval.hasValue);
-    EXPECT_EQ(true, valueProducer.mHasGlobalBase);
+    EXPECT_EQ(true, valueProducer->mHasGlobalBase);
 }
 
 TEST(ValueMetricProducerTest, TestInvalidBucketWhenOneConditionFailed) {
-    ValueMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(ONE_MINUTE);
-    metric.mutable_value_field()->set_field(tagId);
-    metric.mutable_value_field()->add_child()->set_field(2);
-    metric.set_condition(StringToId("SCREEN_ON"));
-    metric.set_max_pull_delay_sec(INT_MAX);
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
 
-    UidMap uidMap;
-    SimpleAtomMatcher atomMatcher;
-    atomMatcher.set_atom_id(tagId);
-    sp<EventMatcherWizard> eventMatcherWizard =
-            new EventMatcherWizard({new SimpleLogMatchingTracker(
-                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
-    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
-
     EXPECT_CALL(*pullerManager, Pull(tagId, _))
             // First onConditionChanged
             .WillOnce(Return(false))
@@ -2347,11 +2053,10 @@
                 return true;
             }));
 
-    ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
-                                      eventMatcherWizard, tagId, bucketStartTimeNs,
-                                      bucketStartTimeNs, pullerManager);
+    sp<ValueMetricProducer> valueProducer =
+            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
 
-    valueProducer.mCondition = ConditionState::kTrue;
+    valueProducer->mCondition = ConditionState::kTrue;
 
     // Bucket start.
     vector<shared_ptr<LogEvent>> allData;
@@ -2361,12 +2066,12 @@
     event->write(110);
     event->init();
     allData.push_back(event);
-    valueProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs);
+    valueProducer->onDataPulled(allData, /** succeed */ true, bucketStartTimeNs);
 
     // This will fail and should invalidate the whole bucket since we do not have all the data
     // needed to compute the metric value when the screen was on.
-    valueProducer.onConditionChanged(false, bucketStartTimeNs + 2);
-    valueProducer.onConditionChanged(true, bucketStartTimeNs + 3);
+    valueProducer->onConditionChanged(false, bucketStartTimeNs + 2);
+    valueProducer->onConditionChanged(true, bucketStartTimeNs + 3);
 
     // Bucket end.
     allData.clear();
@@ -2375,43 +2080,28 @@
     event2->write(140);
     event2->init();
     allData.push_back(event2);
-    valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+    valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
 
-    valueProducer.flushIfNeededLocked(bucket2StartTimeNs + 1);
-    
-    EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
+    valueProducer->flushIfNeededLocked(bucket2StartTimeNs + 1);
+
+    EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
     // Contains base from last pull which was successful.
-    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
     ValueMetricProducer::Interval& curInterval =
-            valueProducer.mCurrentSlicedBucket.begin()->second[0];
+            valueProducer->mCurrentSlicedBucket.begin()->second[0];
     EXPECT_EQ(true, curInterval.hasBase);
     EXPECT_EQ(140, curInterval.base.long_value);
     EXPECT_EQ(false, curInterval.hasValue);
-    EXPECT_EQ(true, valueProducer.mHasGlobalBase);
+    EXPECT_EQ(true, valueProducer->mHasGlobalBase);
 }
 
 TEST(ValueMetricProducerTest, TestInvalidBucketWhenGuardRailHit) {
-    ValueMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(ONE_MINUTE);
-    metric.mutable_value_field()->set_field(tagId);
-    metric.mutable_value_field()->add_child()->set_field(2);
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
     metric.mutable_dimensions_in_what()->set_field(tagId);
     metric.mutable_dimensions_in_what()->add_child()->set_field(1);
     metric.set_condition(StringToId("SCREEN_ON"));
-    metric.set_max_pull_delay_sec(INT_MAX);
 
-    UidMap uidMap;
-    SimpleAtomMatcher atomMatcher;
-    atomMatcher.set_atom_id(tagId);
-    sp<EventMatcherWizard> eventMatcherWizard =
-            new EventMatcherWizard({new SimpleLogMatchingTracker(
-                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
-    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
-
     EXPECT_CALL(*pullerManager, Pull(tagId, _))
             // First onConditionChanged
             .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
@@ -2425,36 +2115,19 @@
                 return true;
             }));
 
-    ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
-                                      eventMatcherWizard, tagId, bucketStartTimeNs,
-                                      bucketStartTimeNs, pullerManager);
+    sp<ValueMetricProducer> valueProducer =
+            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
 
-    valueProducer.mCondition = ConditionState::kFalse;
-    valueProducer.onConditionChanged(true, bucket2StartTimeNs + 2);
-    EXPECT_EQ(true, valueProducer.mCurrentBucketIsInvalid);
-    EXPECT_EQ(0UL, valueProducer.mCurrentSlicedBucket.size());
+    valueProducer->mCondition = ConditionState::kFalse;
+    valueProducer->onConditionChanged(true, bucket2StartTimeNs + 2);
+    EXPECT_EQ(true, valueProducer->mCurrentBucketIsInvalid);
+    EXPECT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
 }
 
 TEST(ValueMetricProducerTest, TestInvalidBucketWhenInitialPullFailed) {
-    ValueMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(ONE_MINUTE);
-    metric.mutable_value_field()->set_field(tagId);
-    metric.mutable_value_field()->add_child()->set_field(2);
-    metric.set_condition(StringToId("SCREEN_ON"));
-    metric.set_max_pull_delay_sec(INT_MAX);
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
 
-    UidMap uidMap;
-    SimpleAtomMatcher atomMatcher;
-    atomMatcher.set_atom_id(tagId);
-    sp<EventMatcherWizard> eventMatcherWizard =
-            new EventMatcherWizard({new SimpleLogMatchingTracker(
-                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
-    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
-
     EXPECT_CALL(*pullerManager, Pull(tagId, _))
             // First onConditionChanged
             .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
@@ -2477,11 +2150,10 @@
                 return true;
             }));
 
-    ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
-                                      eventMatcherWizard, tagId, bucketStartTimeNs,
-                                      bucketStartTimeNs, pullerManager);
+    sp<ValueMetricProducer> valueProducer =
+            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
 
-    valueProducer.mCondition = ConditionState::kTrue;
+    valueProducer->mCondition = ConditionState::kTrue;
 
     // Bucket start.
     vector<shared_ptr<LogEvent>> allData;
@@ -2491,10 +2163,10 @@
     event->write(110);
     event->init();
     allData.push_back(event);
-    valueProducer.onDataPulled(allData, /** succeed */ false, bucketStartTimeNs);
+    valueProducer->onDataPulled(allData, /** succeed */ false, bucketStartTimeNs);
 
-    valueProducer.onConditionChanged(false, bucketStartTimeNs + 2);
-    valueProducer.onConditionChanged(true, bucketStartTimeNs + 3);
+    valueProducer->onConditionChanged(false, bucketStartTimeNs + 2);
+    valueProducer->onConditionChanged(true, bucketStartTimeNs + 3);
 
     // Bucket end.
     allData.clear();
@@ -2503,41 +2175,25 @@
     event2->write(140);
     event2->init();
     allData.push_back(event2);
-    valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+    valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
 
-    valueProducer.flushIfNeededLocked(bucket2StartTimeNs + 1);
-    
-    EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
+    valueProducer->flushIfNeededLocked(bucket2StartTimeNs + 1);
+
+    EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
     // Contains base from last pull which was successful.
-    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
     ValueMetricProducer::Interval& curInterval =
-            valueProducer.mCurrentSlicedBucket.begin()->second[0];
+            valueProducer->mCurrentSlicedBucket.begin()->second[0];
     EXPECT_EQ(true, curInterval.hasBase);
     EXPECT_EQ(140, curInterval.base.long_value);
     EXPECT_EQ(false, curInterval.hasValue);
-    EXPECT_EQ(true, valueProducer.mHasGlobalBase);
+    EXPECT_EQ(true, valueProducer->mHasGlobalBase);
 }
 
 TEST(ValueMetricProducerTest, TestInvalidBucketWhenLastPullFailed) {
-    ValueMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(ONE_MINUTE);
-    metric.mutable_value_field()->set_field(tagId);
-    metric.mutable_value_field()->add_child()->set_field(2);
-    metric.set_condition(StringToId("SCREEN_ON"));
-    metric.set_max_pull_delay_sec(INT_MAX);
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
 
-    UidMap uidMap;
-    SimpleAtomMatcher atomMatcher;
-    atomMatcher.set_atom_id(tagId);
-    sp<EventMatcherWizard> eventMatcherWizard =
-            new EventMatcherWizard({new SimpleLogMatchingTracker(
-                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
-    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
-
     EXPECT_CALL(*pullerManager, Pull(tagId, _))
             // First onConditionChanged
             .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
@@ -2560,11 +2216,10 @@
                 return true;
             }));
 
-    ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
-                                      eventMatcherWizard, tagId, bucketStartTimeNs,
-                                      bucketStartTimeNs, pullerManager);
+    sp<ValueMetricProducer> valueProducer =
+            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
 
-    valueProducer.mCondition = ConditionState::kTrue;
+    valueProducer->mCondition = ConditionState::kTrue;
 
     // Bucket start.
     vector<shared_ptr<LogEvent>> allData;
@@ -2574,12 +2229,12 @@
     event->write(110);
     event->init();
     allData.push_back(event);
-    valueProducer.onDataPulled(allData, /** succeed */ true, bucketStartTimeNs);
+    valueProducer->onDataPulled(allData, /** succeed */ true, bucketStartTimeNs);
 
     // This will fail and should invalidate the whole bucket since we do not have all the data
     // needed to compute the metric value when the screen was on.
-    valueProducer.onConditionChanged(false, bucketStartTimeNs + 2);
-    valueProducer.onConditionChanged(true, bucketStartTimeNs + 3);
+    valueProducer->onConditionChanged(false, bucketStartTimeNs + 2);
+    valueProducer->onConditionChanged(true, bucketStartTimeNs + 3);
 
     // Bucket end.
     allData.clear();
@@ -2588,39 +2243,23 @@
     event2->write(140);
     event2->init();
     allData.push_back(event2);
-    valueProducer.onDataPulled(allData, /** succeed */ false, bucket2StartTimeNs);
+    valueProducer->onDataPulled(allData, /** succeed */ false, bucket2StartTimeNs);
 
-    valueProducer.flushIfNeededLocked(bucket2StartTimeNs + 1);
-    
-    EXPECT_EQ(0UL, valueProducer.mPastBuckets.size());
+    valueProducer->flushIfNeededLocked(bucket2StartTimeNs + 1);
+
+    EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
     // Last pull failed so based has been reset.
-    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
     ValueMetricProducer::Interval& curInterval =
-            valueProducer.mCurrentSlicedBucket.begin()->second[0];
+            valueProducer->mCurrentSlicedBucket.begin()->second[0];
     EXPECT_EQ(false, curInterval.hasBase);
     EXPECT_EQ(false, curInterval.hasValue);
-    EXPECT_EQ(false, valueProducer.mHasGlobalBase);
+    EXPECT_EQ(false, valueProducer->mHasGlobalBase);
 }
 
 TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onDataPulled) {
-    ValueMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(ONE_MINUTE);
-    metric.mutable_value_field()->set_field(tagId);
-    metric.mutable_value_field()->add_child()->set_field(2);
-    metric.set_max_pull_delay_sec(INT_MAX);
-
-    UidMap uidMap;
-    SimpleAtomMatcher atomMatcher;
-    atomMatcher.set_atom_id(tagId);
-    sp<EventMatcherWizard> eventMatcherWizard =
-            new EventMatcherWizard({new SimpleLogMatchingTracker(
-                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); 
     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
-    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
-
     EXPECT_CALL(*pullerManager, Pull(tagId, _))
             // Start bucket.
             .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
@@ -2633,9 +2272,8 @@
                 return true;
             }));
 
-    ValueMetricProducer valueProducer(kConfigKey, metric, -1 /*-1 meaning no condition*/, wizard,
-                                      logEventMatcherIndex, eventMatcherWizard, tagId,
-                                      bucketStartTimeNs, bucketStartTimeNs, pullerManager);
+    sp<ValueMetricProducer> valueProducer =
+            ValueMetricProducerTestHelper::createValueProducerNoConditions(pullerManager, metric);
 
     // Bucket 2 start.
     vector<shared_ptr<LogEvent>> allData;
@@ -2645,41 +2283,25 @@
     event->write(110);
     event->init();
     allData.push_back(event);
-    valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
-    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-    EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
+    valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+    EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
 
     // Bucket 3 empty.
     allData.clear();
     shared_ptr<LogEvent> event2 = make_shared<LogEvent>(tagId, bucket3StartTimeNs + 1);
     event2->init();
     allData.push_back(event2);
-    valueProducer.onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
+    valueProducer->onDataPulled(allData, /** succeed */ true, bucket3StartTimeNs);
     // Data has been trimmed.
-    EXPECT_EQ(0UL, valueProducer.mCurrentSlicedBucket.size());
-    EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
+    EXPECT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size());
+    EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
 }
 
 TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onConditionChanged) {
-    ValueMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(ONE_MINUTE);
-    metric.mutable_value_field()->set_field(tagId);
-    metric.mutable_value_field()->add_child()->set_field(2);
-    metric.set_condition(StringToId("SCREEN_ON"));
-    metric.set_max_pull_delay_sec(INT_MAX);
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
 
-    UidMap uidMap;
-    SimpleAtomMatcher atomMatcher;
-    atomMatcher.set_atom_id(tagId);
-    sp<EventMatcherWizard> eventMatcherWizard =
-            new EventMatcherWizard({new SimpleLogMatchingTracker(
-                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
-    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
-
     EXPECT_CALL(*pullerManager, Pull(tagId, _))
             // First onConditionChanged
             .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
@@ -2696,47 +2318,30 @@
                 return true;
             }));
 
-    ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
-                                      eventMatcherWizard, tagId, bucketStartTimeNs,
-                                      bucketStartTimeNs, pullerManager);
+    sp<ValueMetricProducer> valueProducer =
+            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
 
-    valueProducer.onConditionChanged(true, bucketStartTimeNs + 10);
-    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    valueProducer->onConditionChanged(true, bucketStartTimeNs + 10);
+    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
     ValueMetricProducer::Interval& curInterval =
-            valueProducer.mCurrentSlicedBucket.begin()->second[0];
+            valueProducer->mCurrentSlicedBucket.begin()->second[0];
     EXPECT_EQ(true, curInterval.hasBase);
     EXPECT_EQ(false, curInterval.hasValue);
-    EXPECT_EQ(true, valueProducer.mHasGlobalBase);
+    EXPECT_EQ(true, valueProducer->mHasGlobalBase);
 
     // Empty pull.
-    valueProducer.onConditionChanged(false, bucketStartTimeNs + 10);
-    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    valueProducer->onConditionChanged(false, bucketStartTimeNs + 10);
+    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
     EXPECT_EQ(false, curInterval.hasBase);
     EXPECT_EQ(false, curInterval.hasValue);
-    EXPECT_EQ(false, valueProducer.mHasGlobalBase);
+    EXPECT_EQ(false, valueProducer->mHasGlobalBase);
 }
 
 TEST(ValueMetricProducerTest, TestEmptyDataResetsBase_onBucketBoundary) {
-    ValueMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(ONE_MINUTE);
-    metric.mutable_value_field()->set_field(tagId);
-    metric.mutable_value_field()->add_child()->set_field(2);
-    metric.set_condition(StringToId("SCREEN_ON"));
-    metric.set_max_pull_delay_sec(INT_MAX);
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition();
 
-    UidMap uidMap;
-    SimpleAtomMatcher atomMatcher;
-    atomMatcher.set_atom_id(tagId);
-    sp<EventMatcherWizard> eventMatcherWizard =
-            new EventMatcherWizard({new SimpleLogMatchingTracker(
-                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
-    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
-
     EXPECT_CALL(*pullerManager, Pull(tagId, _))
             // First onConditionChanged
             .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
@@ -2767,58 +2372,42 @@
                 return true;
             }));
 
-    ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
-                                      eventMatcherWizard, tagId, bucketStartTimeNs,
-                                      bucketStartTimeNs, pullerManager);
+    sp<ValueMetricProducer> valueProducer =
+            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
 
-    valueProducer.onConditionChanged(true, bucketStartTimeNs + 10);
-    valueProducer.onConditionChanged(false, bucketStartTimeNs + 11);
-    valueProducer.onConditionChanged(true, bucketStartTimeNs + 12);
-    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    valueProducer->onConditionChanged(true, bucketStartTimeNs + 10);
+    valueProducer->onConditionChanged(false, bucketStartTimeNs + 11);
+    valueProducer->onConditionChanged(true, bucketStartTimeNs + 12);
+    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
     ValueMetricProducer::Interval& curInterval =
-            valueProducer.mCurrentSlicedBucket.begin()->second[0];
+            valueProducer->mCurrentSlicedBucket.begin()->second[0];
     EXPECT_EQ(true, curInterval.hasBase);
     EXPECT_EQ(true, curInterval.hasValue);
-    EXPECT_EQ(true, valueProducer.mHasGlobalBase);
+    EXPECT_EQ(true, valueProducer->mHasGlobalBase);
 
     // End of bucket
     vector<shared_ptr<LogEvent>> allData;
     allData.clear();
-    valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
-    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
-    curInterval = valueProducer.mCurrentSlicedBucket.begin()->second[0];
+    valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
+    curInterval = valueProducer->mCurrentSlicedBucket.begin()->second[0];
     // Data is empty, base should be reset.
     EXPECT_EQ(false, curInterval.hasBase);
     EXPECT_EQ(5, curInterval.base.long_value);
     EXPECT_EQ(false, curInterval.hasValue);
-    EXPECT_EQ(true, valueProducer.mHasGlobalBase);
+    EXPECT_EQ(true, valueProducer->mHasGlobalBase);
 
-    EXPECT_EQ(1UL, valueProducer.mPastBuckets.size());
-    EXPECT_EQ(1, valueProducer.mPastBuckets.begin()->second[0].values[0].long_value);
+    EXPECT_EQ(1UL, valueProducer->mPastBuckets.size());
+    EXPECT_EQ(1, valueProducer->mPastBuckets.begin()->second[0].values[0].long_value);
 }
 
 TEST(ValueMetricProducerTest, TestPartialResetOnBucketBoundaries) {
-    ValueMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(ONE_MINUTE);
-    metric.mutable_value_field()->set_field(tagId);
-    metric.mutable_value_field()->add_child()->set_field(2);
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
     metric.mutable_dimensions_in_what()->set_field(tagId);
     metric.mutable_dimensions_in_what()->add_child()->set_field(1);
     metric.set_condition(StringToId("SCREEN_ON"));
-    metric.set_max_pull_delay_sec(INT_MAX);
 
-    UidMap uidMap;
-    SimpleAtomMatcher atomMatcher;
-    atomMatcher.set_atom_id(tagId);
-    sp<EventMatcherWizard> eventMatcherWizard =
-            new EventMatcherWizard({new SimpleLogMatchingTracker(
-                    atomMatcherId, logEventMatcherIndex, atomMatcher, uidMap)});
-    sp<MockConditionWizard> wizard = new NaggyMock<MockConditionWizard>();
     sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
-    EXPECT_CALL(*pullerManager, RegisterReceiver(tagId, _, _, _)).WillOnce(Return());
-    EXPECT_CALL(*pullerManager, UnRegisterReceiver(tagId, _)).WillRepeatedly(Return());
-
     EXPECT_CALL(*pullerManager, Pull(tagId, _))
             // First onConditionChanged
             .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
@@ -2832,12 +2421,11 @@
                 return true;
             }));
 
-    ValueMetricProducer valueProducer(kConfigKey, metric, 1, wizard, logEventMatcherIndex,
-                                      eventMatcherWizard, tagId, bucketStartTimeNs,
-                                      bucketStartTimeNs, pullerManager);
+    sp<ValueMetricProducer> valueProducer =
+            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
 
-    valueProducer.onConditionChanged(true, bucketStartTimeNs + 10);
-    EXPECT_EQ(1UL, valueProducer.mCurrentSlicedBucket.size());
+    valueProducer->onConditionChanged(true, bucketStartTimeNs + 10);
+    EXPECT_EQ(1UL, valueProducer->mCurrentSlicedBucket.size());
 
     // End of bucket
     vector<shared_ptr<LogEvent>> allData;
@@ -2847,11 +2435,11 @@
     event->write(2);
     event->init();
     allData.push_back(event);
-    valueProducer.onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+    valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
 
     // Key 1 should be reset since in not present in the most pull.
-    EXPECT_EQ(2UL, valueProducer.mCurrentSlicedBucket.size());
-    auto iterator = valueProducer.mCurrentSlicedBucket.begin();
+    EXPECT_EQ(2UL, valueProducer->mCurrentSlicedBucket.size());
+    auto iterator = valueProducer->mCurrentSlicedBucket.begin();
     EXPECT_EQ(true, iterator->second[0].hasBase);
     EXPECT_EQ(2, iterator->second[0].base.long_value);
     EXPECT_EQ(false, iterator->second[0].hasValue);
@@ -2860,7 +2448,49 @@
     EXPECT_EQ(1, iterator->second[0].base.long_value);
     EXPECT_EQ(false, iterator->second[0].hasValue);
 
-    EXPECT_EQ(true, valueProducer.mHasGlobalBase);
+    EXPECT_EQ(true, valueProducer->mHasGlobalBase);
+}
+
+TEST(ValueMetricProducerTest, TestBucketIncludingUnknownConditionIsInvalid) {
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetric();
+    metric.mutable_dimensions_in_what()->set_field(tagId);
+    metric.mutable_dimensions_in_what()->add_child()->set_field(1);
+    metric.set_condition(StringToId("SCREEN_ON"));
+
+    sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>();
+    EXPECT_CALL(*pullerManager, Pull(tagId, _))
+            // Second onConditionChanged.
+            .WillOnce(Invoke([](int tagId, vector<std::shared_ptr<LogEvent>>* data) {
+                data->clear();
+                shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucketStartTimeNs);
+                event->write(tagId);
+                event->write(2);
+                event->write(2);
+                event->init();
+                data->push_back(event);
+                return true;
+            }));
+
+    sp<ValueMetricProducer> valueProducer =
+            ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric);
+    valueProducer->mCondition = ConditionState::kUnknown;
+
+    valueProducer->onConditionChanged(false, bucketStartTimeNs + 10);
+    valueProducer->onConditionChanged(true, bucketStartTimeNs + 20);
+
+    // End of bucket
+    vector<shared_ptr<LogEvent>> allData;
+    allData.clear();
+    shared_ptr<LogEvent> event = make_shared<LogEvent>(tagId, bucket2StartTimeNs + 1);
+    event->write(4);
+    event->write(4);
+    event->init();
+    allData.push_back(event);
+    valueProducer->onDataPulled(allData, /** succeed */ true, bucket2StartTimeNs);
+
+    // Bucket is incomplete so it is mark as invalid, however the base is fine since the last pull
+    // succeeded.
+    EXPECT_EQ(0UL, valueProducer->mPastBuckets.size());
 }
 
 static StatsLogReport outputStreamToProto(ProtoOutputStream* proto) {
@@ -2881,12 +2511,7 @@
 }
 
 TEST(ValueMetricProducerTest, TestPullNeededFastDump) {
-    ValueMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(ONE_MINUTE);
-    metric.mutable_value_field()->set_field(tagId);
-    metric.mutable_value_field()->add_child()->set_field(2);
-    metric.set_max_pull_delay_sec(INT_MAX);
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); 
 
     UidMap uidMap;
     SimpleAtomMatcher atomMatcher;
@@ -2918,7 +2543,7 @@
 
     ProtoOutputStream output;
     std::set<string> strSet;
-    valueProducer.onDumpReport(bucketStartTimeNs + 10, 
+    valueProducer.onDumpReport(bucketStartTimeNs + 10,
                                true /* include recent buckets */, true,
                                FAST, &strSet, &output);
 
@@ -2928,12 +2553,7 @@
 }
 
 TEST(ValueMetricProducerTest, TestFastDumpWithoutCurrentBucket) {
-    ValueMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(ONE_MINUTE);
-    metric.mutable_value_field()->set_field(tagId);
-    metric.mutable_value_field()->add_child()->set_field(2);
-    metric.set_max_pull_delay_sec(INT_MAX);
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); 
 
     UidMap uidMap;
     SimpleAtomMatcher atomMatcher;
@@ -2975,7 +2595,7 @@
 
     ProtoOutputStream output;
     std::set<string> strSet;
-    valueProducer.onDumpReport(bucket4StartTimeNs, 
+    valueProducer.onDumpReport(bucket4StartTimeNs,
                                false /* include recent buckets */, true,
                                FAST, &strSet, &output);
 
@@ -2986,12 +2606,7 @@
 }
 
 TEST(ValueMetricProducerTest, TestPullNeededNoTimeConstraints) {
-    ValueMetric metric;
-    metric.set_id(metricId);
-    metric.set_bucket(ONE_MINUTE);
-    metric.mutable_value_field()->set_field(tagId);
-    metric.mutable_value_field()->add_child()->set_field(2);
-    metric.set_max_pull_delay_sec(INT_MAX);
+    ValueMetric metric = ValueMetricProducerTestHelper::createMetric(); 
 
     UidMap uidMap;
     SimpleAtomMatcher atomMatcher;
@@ -3033,7 +2648,7 @@
 
     ProtoOutputStream output;
     std::set<string> strSet;
-    valueProducer.onDumpReport(bucketStartTimeNs + 10, 
+    valueProducer.onDumpReport(bucketStartTimeNs + 10,
                                true /* include recent buckets */, true,
                                NO_TIME_CONSTRAINTS, &strSet, &output);
 
diff --git a/cmds/svc/src/com/android/commands/svc/Svc.java b/cmds/svc/src/com/android/commands/svc/Svc.java
index 62225df..68fb8e6 100644
--- a/cmds/svc/src/com/android/commands/svc/Svc.java
+++ b/cmds/svc/src/com/android/commands/svc/Svc.java
@@ -98,5 +98,6 @@
             new UsbCommand(),
             new NfcCommand(),
             new BluetoothCommand(),
+            new SystemServerCommand(),
     };
 }
diff --git a/cmds/svc/src/com/android/commands/svc/SystemServerCommand.java b/cmds/svc/src/com/android/commands/svc/SystemServerCommand.java
new file mode 100644
index 0000000..b9104d1
--- /dev/null
+++ b/cmds/svc/src/com/android/commands/svc/SystemServerCommand.java
@@ -0,0 +1,67 @@
+/*
+ * 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.commands.svc;
+
+import android.app.ActivityManager;
+import android.os.ParcelFileDescriptor;
+
+import java.io.FileInputStream;
+
+public class SystemServerCommand extends Svc.Command {
+    public SystemServerCommand() {
+        super("system-server");
+    }
+
+    @Override
+    public String shortHelp() {
+        return "System server process related command";
+    }
+
+    @Override
+    public String longHelp() {
+        return shortHelp() + "\n"
+                + "\n"
+                + "usage: system-server wait-for-crash\n"
+                + "         Wait until the system server process crashes.\n\n";
+    }
+
+    private void waitForCrash() throws Exception {
+        ParcelFileDescriptor fd = ActivityManager.getService().getLifeMonitor();
+        if (fd == null) {
+            System.err.println("Unable to get life monitor.");
+            return;
+        }
+        System.out.println("Waiting for the system server process to die...");
+        new FileInputStream(fd.getFileDescriptor()).read();
+    }
+
+    @Override
+    public void run(String[] args) {
+        try {
+            if (args.length > 1) {
+                switch (args[1]) {
+                    case "wait-for-crash":
+                        waitForCrash();
+                        return;
+                }
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        System.err.println(longHelp());
+    }
+}
diff --git a/config/hiddenapi-greylist.txt b/config/hiddenapi-greylist.txt
index a836e8e..2abb631 100644
--- a/config/hiddenapi-greylist.txt
+++ b/config/hiddenapi-greylist.txt
@@ -688,7 +688,6 @@
 Landroid/os/Build;->getLong(Ljava/lang/String;)J
 Landroid/os/Build;->getString(Ljava/lang/String;)Ljava/lang/String;
 Landroid/os/Build;->IS_DEBUGGABLE:Z
-Landroid/os/Build;->IS_EMULATOR:Z
 Landroid/os/Bundle;->filterValues()Landroid/os/Bundle;
 Landroid/os/Bundle;->forPair(Ljava/lang/String;Ljava/lang/String;)Landroid/os/Bundle;
 Landroid/os/Bundle;->getIBinder(Ljava/lang/String;)Landroid/os/IBinder;
@@ -3107,10 +3106,6 @@
 Lcom/android/internal/telephony/ISms$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/ISms;
 Lcom/android/internal/telephony/ISub$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Lcom/android/internal/telephony/ISub$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/ISub;
-Lcom/android/internal/telephony/ISub;->getActiveSubIdList()[I
-Lcom/android/internal/telephony/ISub;->getDefaultDataSubId()I
-Lcom/android/internal/telephony/ISub;->getDefaultSubId()I
-Lcom/android/internal/telephony/ISub;->setDefaultDataSubId(I)V
 Lcom/android/internal/telephony/ITelephony$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Lcom/android/internal/telephony/ITelephony$Stub$Proxy;->getDeviceId(Ljava/lang/String;)Ljava/lang/String;
 Lcom/android/internal/telephony/ITelephony$Stub$Proxy;->isRadioOn(Ljava/lang/String;)Z
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 89e848b..a63350c 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -7608,7 +7608,7 @@
 
         mWindow.setColorMode(info.colorMode);
 
-        setAutofillCompatibilityEnabled(application.isAutofillCompatibilityEnabled());
+        setAutofillOptions(application.getAutofillOptions());
         setContentCaptureOptions(application.getContentCaptureOptions());
     }
 
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 5d4f988..ee7288f 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -3925,6 +3925,14 @@
     /**
      * @hide
      */
+    @TestApi
+    public static void resumeAppSwitches() throws RemoteException {
+        getService().resumeAppSwitches();
+    }
+
+    /**
+     * @hide
+     */
     public static void noteWakeupAlarm(PendingIntent ps, WorkSource workSource, int sourceUid,
             String sourcePkg, String tag) {
         try {
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 001cd69..92302c5 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -43,6 +43,7 @@
 import android.app.servertransaction.PendingTransactionActions.StopInfo;
 import android.app.servertransaction.TransactionExecutor;
 import android.app.servertransaction.TransactionExecutorHelper;
+import android.content.AutofillOptions;
 import android.content.BroadcastReceiver;
 import android.content.ComponentCallbacks2;
 import android.content.ComponentName;
@@ -745,7 +746,7 @@
         /** Initial values for {@link Profiler}. */
         ProfilerInfo initProfilerInfo;
 
-        boolean autofillCompatibilityEnabled;
+        AutofillOptions autofillOptions;
 
         /**
          * Content capture options for the application - when null, it means ContentCapture is not
@@ -975,9 +976,8 @@
                 boolean enableBinderTracking, boolean trackAllocation,
                 boolean isRestrictedBackupMode, boolean persistent, Configuration config,
                 CompatibilityInfo compatInfo, Map services, Bundle coreSettings,
-                String buildSerial, boolean autofillCompatibilityEnabled,
+                String buildSerial, AutofillOptions autofillOptions,
                 ContentCaptureOptions contentCaptureOptions) {
-
             if (services != null) {
                 if (false) {
                     // Test code to make sure the app could see the passed-in services.
@@ -1023,7 +1023,7 @@
             data.compatInfo = compatInfo;
             data.initProfilerInfo = profilerInfo;
             data.buildSerial = buildSerial;
-            data.autofillCompatibilityEnabled = autofillCompatibilityEnabled;
+            data.autofillOptions = autofillOptions;
             data.contentCaptureOptions = contentCaptureOptions;
             sendMessage(H.BIND_APPLICATION, data);
         }
@@ -6164,7 +6164,7 @@
             app = data.info.makeApplication(data.restrictedBackupMode, null);
 
             // Propagate autofill compat state
-            app.setAutofillCompatibilityEnabled(data.autofillCompatibilityEnabled);
+            app.setAutofillOptions(data.autofillOptions);
 
             // Propagate Content Capture options
             app.setContentCaptureOptions(data.contentCaptureOptions);
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index a4b763d..2ef0856 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -21,7 +21,7 @@
 import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC;
 
 import android.annotation.NonNull;
-import android.annotation.UnsupportedAppUsage;
+import android.annotation.TestApi;
 import android.app.ActivityManager.StackInfo;
 import android.content.ComponentName;
 import android.content.Context;
@@ -59,6 +59,7 @@
  * on VirtualDisplays.
  * @hide
  */
+@TestApi
 public class ActivityView extends ViewGroup {
 
     private static final String DISPLAY_NAME = "ActivityViewVirtualDisplay";
@@ -92,7 +93,6 @@
 
     private Insets mForwardedInsets;
 
-    @UnsupportedAppUsage
     public ActivityView(Context context) {
         this(context, null /* attrs */);
     }
@@ -151,7 +151,7 @@
          * Called when a task is moved to the front of the stack inside the container.
          * This is a filtered version of {@link TaskStackListener}
          */
-        public void onTaskMovedToFront(ActivityManager.StackInfo stackInfo) { }
+        public void onTaskMovedToFront(int taskId) { }
 
         /**
          * Called when a task is about to be removed from the stack inside the container.
@@ -195,7 +195,6 @@
      * @see StateCallback
      * @see #startActivity(PendingIntent)
      */
-    @UnsupportedAppUsage
     public void startActivity(@NonNull Intent intent) {
         final ActivityOptions options = prepareActivityOptions();
         getContext().startActivity(intent, options.toBundle());
@@ -238,7 +237,6 @@
      * @see StateCallback
      * @see #startActivity(Intent)
      */
-    @UnsupportedAppUsage
     public void startActivity(@NonNull PendingIntent pendingIntent) {
         final ActivityOptions options = prepareActivityOptions();
         try {
@@ -272,7 +270,6 @@
      *
      * @see StateCallback
      */
-    @UnsupportedAppUsage
     public void release() {
         if (mVirtualDisplay == null) {
             throw new IllegalStateException(
@@ -556,7 +553,7 @@
             // notifying the callback
             if (stackInfo != null
                     && taskInfo.taskId == stackInfo.taskIds[stackInfo.taskIds.length - 1]) {
-                mActivityViewCallback.onTaskMovedToFront(stackInfo);
+                mActivityViewCallback.onTaskMovedToFront(taskInfo.taskId);
             }
         }
 
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 98032dc..d3e3507 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -696,7 +696,9 @@
             int flagMask, int flagValues, UserHandle user) {
         try {
             mPM.updatePermissionFlags(permissionName, packageName, flagMask,
-                    flagValues, user.getIdentifier());
+                    flagValues,
+                    mContext.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.Q,
+                    user.getIdentifier());
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -2467,6 +2469,33 @@
     }
 
     @Override
+    public void setAppDetailsActivityEnabled(String packageName, boolean enabled) {
+        try {
+            ComponentName componentName = new ComponentName(packageName,
+                    PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME);
+            mPM.setComponentEnabledSetting(componentName, enabled
+                    ? PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
+                    : PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+                    PackageManager.DONT_KILL_APP, getUserId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    @Override
+    public boolean getAppDetailsActivityEnabled(String packageName) {
+        try {
+            ComponentName componentName = new ComponentName(packageName,
+                    PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME);
+            int state = mPM.getComponentEnabledSetting(componentName, getUserId());
+            return state == PackageManager.COMPONENT_ENABLED_STATE_ENABLED
+                    || state == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    @Override
     public void setComponentEnabledSetting(ComponentName componentName,
                                            int newState, int flags) {
         try {
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 3a1e80d..b607f9a 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -21,6 +21,7 @@
 import android.annotation.Nullable;
 import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
+import android.content.AutofillOptions;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentCaptureOptions;
@@ -215,8 +216,8 @@
     // The name of the split this Context is representing. May be null.
     private @Nullable String mSplitName = null;
 
-    private AutofillClient mAutofillClient = null;
-    private boolean mIsAutofillCompatEnabled;
+    private @Nullable AutofillClient mAutofillClient = null;
+    private @Nullable AutofillOptions mAutofillOptions;
 
     private ContentCaptureOptions mContentCaptureOptions = null;
 
@@ -2283,8 +2284,8 @@
         return (mFlags & Context.CONTEXT_IGNORE_SECURITY) != 0;
     }
 
+    @TestApi
     @Override
-    @UnsupportedAppUsage
     public Display getDisplay() {
         if (mDisplay == null) {
             return mResourcesManager.getAdjustedDisplay(Display.DEFAULT_DISPLAY,
@@ -2376,15 +2377,14 @@
 
     /** @hide */
     @Override
-    public boolean isAutofillCompatibilityEnabled() {
-        return mIsAutofillCompatEnabled;
+    public AutofillOptions getAutofillOptions() {
+        return mAutofillOptions;
     }
 
     /** @hide */
-    @TestApi
     @Override
-    public void setAutofillCompatibilityEnabled(boolean autofillCompatEnabled) {
-        mIsAutofillCompatEnabled = autofillCompatEnabled;
+    public void setAutofillOptions(AutofillOptions options) {
+        mAutofillOptions = options;
     }
 
     /** @hide */
diff --git a/core/java/android/app/IActivityManager.aidl b/core/java/android/app/IActivityManager.aidl
index 3aa9fa7..dcef9d2 100644
--- a/core/java/android/app/IActivityManager.aidl
+++ b/core/java/android/app/IActivityManager.aidl
@@ -486,4 +486,7 @@
      * started from the shell.
      */
     void stopDelegateShellPermissionIdentity();
+
+    /** Returns a file descriptor that'll be closed when the system server process dies. */
+    ParcelFileDescriptor getLifeMonitor();
 }
diff --git a/core/java/android/app/IApplicationThread.aidl b/core/java/android/app/IApplicationThread.aidl
index b73092a..b8af898 100644
--- a/core/java/android/app/IApplicationThread.aidl
+++ b/core/java/android/app/IApplicationThread.aidl
@@ -21,6 +21,7 @@
 import android.app.ProfilerInfo;
 import android.app.ResultInfo;
 import android.app.servertransaction.ClientTransaction;
+import android.content.AutofillOptions;
 import android.content.ComponentName;
 import android.content.ContentCaptureOptions;
 import android.content.IIntentReceiver;
@@ -69,7 +70,7 @@
             int debugMode, boolean enableBinderTracking, boolean trackAllocation,
             boolean restrictedBackupMode, boolean persistent, in Configuration config,
             in CompatibilityInfo compatInfo, in Map services,
-            in Bundle coreSettings, in String buildSerial, boolean isAutofillCompatEnabled,
+            in Bundle coreSettings, in String buildSerial, in AutofillOptions autofillOptions,
             in ContentCaptureOptions contentCaptureOptions);
     void runIsolatedEntryPoint(in String entryPoint, in String[] entryPointArgs);
     void scheduleExit();
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 0166f52..2e7093d 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -8409,7 +8409,6 @@
 
         private PendingIntent mPendingIntent;
         private PendingIntent mDeleteIntent;
-        private CharSequence mTitle;
         private Icon mIcon;
         private int mDesiredHeight;
         private int mFlags;
@@ -8438,9 +8437,8 @@
         private static final int FLAG_SUPPRESS_INITIAL_NOTIFICATION = 0x00000002;
 
         private BubbleMetadata(PendingIntent expandIntent, PendingIntent deleteIntent,
-                CharSequence title, Icon icon, int height) {
+                Icon icon, int height) {
             mPendingIntent = expandIntent;
-            mTitle = title;
             mIcon = icon;
             mDesiredHeight = height;
             mDeleteIntent = deleteIntent;
@@ -8448,7 +8446,6 @@
 
         private BubbleMetadata(Parcel in) {
             mPendingIntent = PendingIntent.CREATOR.createFromParcel(in);
-            mTitle = in.readCharSequence();
             mIcon = Icon.CREATOR.createFromParcel(in);
             mDesiredHeight = in.readInt();
             mFlags = in.readInt();
@@ -8474,11 +8471,13 @@
         /**
          * @return the title that will appear along with the app content defined by
          * {@link #getIntent()} for this bubble.
+         *
+         * @deprecated titles are no longer required or shown.
          */
+        @Deprecated
         public CharSequence getTitle() {
-            return mTitle;
+            return "";
         }
-
         /**
          * @return the icon that will be displayed for this bubble when it is collapsed.
          */
@@ -8534,7 +8533,6 @@
         @Override
         public void writeToParcel(Parcel out, int flags) {
             mPendingIntent.writeToParcel(out, 0);
-            out.writeCharSequence(mTitle);
             mIcon.writeToParcel(out, 0);
             out.writeInt(mDesiredHeight);
             out.writeInt(mFlags);
@@ -8554,7 +8552,6 @@
         public static class Builder {
 
             private PendingIntent mPendingIntent;
-            private CharSequence mTitle;
             private Icon mIcon;
             private int mDesiredHeight;
             private int mFlags;
@@ -8583,12 +8580,11 @@
              *
              * <p>A title is required and should expect to fit on a single line and make sense when
              * shown with the content defined by {@link #setIntent(PendingIntent)}.</p>
+             *
+             * @deprecated titles are no longer required or shown.
              */
+            @Deprecated
             public BubbleMetadata.Builder setTitle(CharSequence title) {
-                if (TextUtils.isEmpty(title)) {
-                    throw new IllegalArgumentException("Bubbles require non-null or empty title");
-                }
-                mTitle = title;
                 return this;
             }
 
@@ -8667,13 +8663,10 @@
                 if (mPendingIntent == null) {
                     throw new IllegalStateException("Must supply pending intent to bubble");
                 }
-                if (TextUtils.isEmpty(mTitle)) {
-                    throw new IllegalStateException("Must supply a title for the bubble");
-                }
                 if (mIcon == null) {
                     throw new IllegalStateException("Must supply an icon for the bubble");
                 }
-                BubbleMetadata data = new BubbleMetadata(mPendingIntent, mDeleteIntent, mTitle,
+                BubbleMetadata data = new BubbleMetadata(mPendingIntent, mDeleteIntent,
                         mIcon, mDesiredHeight);
                 data.setFlags(mFlags);
                 return data;
diff --git a/core/java/android/app/UiAutomationConnection.java b/core/java/android/app/UiAutomationConnection.java
index 31521a3..7e07446 100644
--- a/core/java/android/app/UiAutomationConnection.java
+++ b/core/java/android/app/UiAutomationConnection.java
@@ -128,7 +128,13 @@
                 : InputManager.INJECT_INPUT_EVENT_MODE_ASYNC;
         final long identity = Binder.clearCallingIdentity();
         try {
-            return InputManager.getInstance().injectInputEvent(event, mode);
+            IWindowManager manager = IWindowManager.Stub.asInterface(
+                    ServiceManager.getService(Context.WINDOW_SERVICE));
+            try {
+                return manager.injectInputAfterTransactionsApplied(event, mode);
+            } catch (RemoteException e) {
+            }
+            return false;
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 3587c68..a32e01f 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -59,6 +59,7 @@
 import android.os.Bundle;
 import android.os.ParcelFileDescriptor;
 import android.os.Parcelable;
+import android.os.ParcelableException;
 import android.os.PersistableBundle;
 import android.os.Process;
 import android.os.RemoteCallback;
@@ -115,6 +116,8 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Set;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutionException;
 import java.util.concurrent.Executor;
 
 /**
@@ -1576,6 +1579,19 @@
     public static final int PERMISSION_POLICY_AUTO_DENY = 2;
 
     /**
+     * Possible policy values for permissions.
+     *
+     * @hide
+     */
+    @IntDef(prefix = { "PERMISSION_GRANT_STATE_" }, value = {
+            PERMISSION_GRANT_STATE_DEFAULT,
+            PERMISSION_GRANT_STATE_GRANTED,
+            PERMISSION_GRANT_STATE_DENIED
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface PermissionGrantState {}
+
+    /**
      * Runtime permission state: The user can manage the permission
      * through the UI.
      */
@@ -8667,8 +8683,15 @@
      * Setting the grant state to {@link #PERMISSION_GRANT_STATE_DEFAULT default} does not revoke
      * the permission. It retains the previous grant, if any.
      * <p/>
-     * Permissions can be granted or revoked only for applications built with a
-     * {@code targetSdkVersion} of {@link android.os.Build.VERSION_CODES#M} or later.
+     * Device admins with a {@code targetSdkVersion} &lt; {@link android.os.Build.VERSION_CODES#Q}
+     * cannot grant and revoke permissions for applications built with a {@code targetSdkVersion}
+     * &lt; {@link android.os.Build.VERSION_CODES#M}.
+     * <p/>
+     * Admins with a {@code targetSdkVersion} &ge; {@link android.os.Build.VERSION_CODES#Q} can
+     * grant and revoke permissions of all apps. Similar to the user revoking a permission from a
+     * application built with a {@code targetSdkVersion} &lt;
+     * {@link android.os.Build.VERSION_CODES#M} the app-op matching the permission is set to
+     * {@link android.app.AppOpsManager#MODE_IGNORED}, but the permission stays granted.
      *
      * @param admin Which profile or device owner this request is associated with.
      * @param packageName The application to grant or revoke a permission to.
@@ -8684,14 +8707,21 @@
      * @see #setDelegatedScopes
      * @see #DELEGATION_PERMISSION_GRANT
      */
-    public boolean setPermissionGrantState(@NonNull ComponentName admin, String packageName,
-            String permission, int grantState) {
+    public boolean setPermissionGrantState(@NonNull ComponentName admin,
+            @NonNull String packageName, @NonNull String permission,
+            @PermissionGrantState int grantState) {
         throwIfParentInstance("setPermissionGrantState");
         try {
-            return mService.setPermissionGrantState(admin, mContext.getPackageName(), packageName,
-                    permission, grantState);
+            CompletableFuture<Boolean> result = new CompletableFuture<>();
+
+            mService.setPermissionGrantState(admin, mContext.getPackageName(), packageName,
+                    permission, grantState, new RemoteCallback((b) -> result.complete(b != null)));
+
+            return result.get();
         } catch (RemoteException re) {
             throw re.rethrowFromSystemServer();
+        } catch (InterruptedException | ExecutionException e) {
+            throw new RuntimeException(e);
         }
     }
 
@@ -8719,8 +8749,8 @@
      * @see #setDelegatedScopes
      * @see #DELEGATION_PERMISSION_GRANT
      */
-    public int getPermissionGrantState(@Nullable ComponentName admin, String packageName,
-            String permission) {
+    public @PermissionGrantState int getPermissionGrantState(@Nullable ComponentName admin,
+            @NonNull String packageName, @NonNull String permission) {
         throwIfParentInstance("getPermissionGrantState");
         try {
             return mService.getPermissionGrantState(admin, mContext.getPackageName(), packageName,
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 5790fda..9478a3c 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -311,8 +311,8 @@
 
     void setPermissionPolicy(in ComponentName admin, in String callerPackage, int policy);
     int  getPermissionPolicy(in ComponentName admin);
-    boolean setPermissionGrantState(in ComponentName admin, in String callerPackage, String packageName,
-            String permission, int grantState);
+    void setPermissionGrantState(in ComponentName admin, in String callerPackage, String packageName,
+            String permission, int grantState, in RemoteCallback resultReceiver);
     int getPermissionGrantState(in ComponentName admin, in String callerPackage, String packageName, String permission);
     boolean isProvisioningAllowed(String action, String packageName);
     int checkProvisioningPreCondition(String action, String packageName);
diff --git a/core/java/android/appwidget/AppWidgetHostView.java b/core/java/android/appwidget/AppWidgetHostView.java
index 3e9dd28..85f0e23 100644
--- a/core/java/android/appwidget/AppWidgetHostView.java
+++ b/core/java/android/appwidget/AppWidgetHostView.java
@@ -30,7 +30,6 @@
 import android.content.res.Resources;
 import android.graphics.Color;
 import android.graphics.Rect;
-import android.os.Build;
 import android.os.Bundle;
 import android.os.CancellationSignal;
 import android.os.Parcelable;
@@ -178,40 +177,29 @@
      */
     public static Rect getDefaultPaddingForWidget(Context context, ComponentName component,
             Rect padding) {
-        ApplicationInfo appInfo = null;
-        try {
-            appInfo = context.getPackageManager().getApplicationInfo(component.getPackageName(), 0);
-        } catch (NameNotFoundException e) {
-            // if we can't find the package, ignore
-        }
-        return getDefaultPaddingForWidget(context, appInfo, padding);
+        return getDefaultPaddingForWidget(context, padding);
     }
 
-    @UnsupportedAppUsage
-    private static Rect getDefaultPaddingForWidget(Context context, ApplicationInfo appInfo,
-            Rect padding) {
+    private static Rect getDefaultPaddingForWidget(Context context, Rect padding) {
         if (padding == null) {
             padding = new Rect(0, 0, 0, 0);
         } else {
             padding.set(0, 0, 0, 0);
         }
-        if (appInfo != null && appInfo.targetSdkVersion >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
-            Resources r = context.getResources();
-            padding.left = r.getDimensionPixelSize(com.android.internal.
-                    R.dimen.default_app_widget_padding_left);
-            padding.right = r.getDimensionPixelSize(com.android.internal.
-                    R.dimen.default_app_widget_padding_right);
-            padding.top = r.getDimensionPixelSize(com.android.internal.
-                    R.dimen.default_app_widget_padding_top);
-            padding.bottom = r.getDimensionPixelSize(com.android.internal.
-                    R.dimen.default_app_widget_padding_bottom);
-        }
+        Resources r = context.getResources();
+        padding.left = r.getDimensionPixelSize(
+                com.android.internal.R.dimen.default_app_widget_padding_left);
+        padding.right = r.getDimensionPixelSize(
+                com.android.internal.R.dimen.default_app_widget_padding_right);
+        padding.top = r.getDimensionPixelSize(
+                com.android.internal.R.dimen.default_app_widget_padding_top);
+        padding.bottom = r.getDimensionPixelSize(
+                com.android.internal.R.dimen.default_app_widget_padding_bottom);
         return padding;
     }
 
     private Rect getDefaultPadding() {
-        return getDefaultPaddingForWidget(mContext,
-                mInfo == null ? null : mInfo.providerInfo.applicationInfo, null);
+        return getDefaultPaddingForWidget(mContext, null);
     }
 
     public int getAppWidgetId() {
diff --git a/core/java/android/content/AutofillOptions.aidl b/core/java/android/content/AutofillOptions.aidl
new file mode 100644
index 0000000..7e4fed2
--- /dev/null
+++ b/core/java/android/content/AutofillOptions.aidl
@@ -0,0 +1,19 @@
+/*
+** Copyright 2019, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+
+package android.content;
+
+parcelable AutofillOptions;
diff --git a/core/java/android/content/AutofillOptions.java b/core/java/android/content/AutofillOptions.java
new file mode 100644
index 0000000..fd7e52a
--- /dev/null
+++ b/core/java/android/content/AutofillOptions.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.content;
+
+import android.annotation.NonNull;
+import android.annotation.TestApi;
+import android.app.ActivityThread;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+import android.view.autofill.AutofillManager;
+
+import java.io.PrintWriter;
+
+/**
+ * Autofill options for a given package.
+ *
+ * <p>This object is created by the Autofill System Service and passed back to the app when the
+ * application is created.
+ *
+ * @hide
+ */
+@TestApi
+public final class AutofillOptions implements Parcelable {
+
+    private static final String TAG = AutofillOptions.class.getSimpleName();
+
+    /**
+     * Logging level for {@code logcat} statements.
+     */
+    public final int loggingLevel;
+
+    /**
+     * Whether compatibility mode is enabled for the package.
+     */
+    public final boolean compatModeEnabled;
+
+    /**
+     * Whether package is whitelisted for augmented autofill.
+     */
+    public boolean augmentedEnabled;
+    // TODO(b/123100824): add (optional) list of activities
+
+    public AutofillOptions(int loggingLevel, boolean compatModeEnabled) {
+        this.loggingLevel = loggingLevel;
+        this.compatModeEnabled = compatModeEnabled;
+    }
+
+    /**
+     * @hide
+     */
+    @TestApi
+    public static AutofillOptions forWhitelistingItself() {
+        final ActivityThread at = ActivityThread.currentActivityThread();
+        if (at == null) {
+            throw new IllegalStateException("No ActivityThread");
+        }
+
+        final String packageName = at.getApplication().getPackageName();
+
+        if (!"android.autofillservice.cts".equals(packageName)) {
+            Log.e(TAG, "forWhitelistingItself(): called by " + packageName);
+            throw new SecurityException("Thou shall not pass!");
+        }
+
+        final AutofillOptions options = new AutofillOptions(
+                AutofillManager.FLAG_ADD_CLIENT_VERBOSE, /* compatModeAllowed= */ true);
+        options.augmentedEnabled = true;
+        // Always log, as it's used by test only
+        Log.i(TAG, "forWhitelistingItself(" + packageName + "): " + options);
+
+        return options;
+    }
+
+    @Override
+    public String toString() {
+        return "AutofillOptions [loggingLevel=" + loggingLevel + ", compatMode="
+                + compatModeEnabled + ", augmentedEnabled=" + augmentedEnabled + "]";
+    }
+
+    /** @hide */
+    public void dumpShort(@NonNull PrintWriter pw) {
+        pw.print("logLvl="); pw.print(loggingLevel);
+        pw.print(", compatMode="); pw.print(compatModeEnabled);
+        pw.print(", augmented="); pw.print(augmentedEnabled);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel parcel, int flags) {
+        parcel.writeInt(loggingLevel);
+        parcel.writeBoolean(compatModeEnabled);
+        parcel.writeBoolean(augmentedEnabled);
+    }
+
+    public static final Parcelable.Creator<AutofillOptions> CREATOR =
+            new Parcelable.Creator<AutofillOptions>() {
+
+                @Override
+                public AutofillOptions createFromParcel(Parcel parcel) {
+                    final int loggingLevel = parcel.readInt();
+                    final boolean compatMode = parcel.readBoolean();
+                    final AutofillOptions options = new AutofillOptions(loggingLevel, compatMode);
+                    options.augmentedEnabled = parcel.readBoolean();
+                    return options;
+                }
+
+                @Override
+                public AutofillOptions[] newArray(int size) {
+                    return new AutofillOptions[size];
+                }
+    };
+}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index fdb0041..29added 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -5241,9 +5241,10 @@
     public abstract DisplayAdjustments getDisplayAdjustments(int displayId);
 
     /**
+     * @return Returns the {@link Display} object this context is associated with.
      * @hide
      */
-    @UnsupportedAppUsage
+    @TestApi
     public abstract Display getDisplay();
 
     /**
@@ -5340,16 +5341,24 @@
     /**
      * @hide
      */
-    public boolean isAutofillCompatibilityEnabled() {
-        return false;
+    public final boolean isAutofillCompatibilityEnabled() {
+        final AutofillOptions options = getAutofillOptions();
+        return options != null && options.compatModeEnabled;
+    }
+
+    /**
+     * @hide
+     */
+    @Nullable
+    public AutofillOptions getAutofillOptions() {
+        return null;
     }
 
     /**
      * @hide
      */
     @TestApi
-    public void setAutofillCompatibilityEnabled(
-            @SuppressWarnings("unused") boolean autofillCompatEnabled) {
+    public void setAutofillOptions(@SuppressWarnings("unused") @Nullable AutofillOptions options) {
     }
 
     /**
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index 68b4320..40559d3 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -919,11 +919,9 @@
         return mBase.getDisplayAdjustments(displayId);
     }
 
-    /**
-     * @hide
-     */
+    /** @hide */
+    @TestApi
     @Override
-    @UnsupportedAppUsage
     public Display getDisplay() {
         return mBase.getDisplay();
     }
@@ -1031,22 +1029,17 @@
         mBase.setAutofillClient(client);
     }
 
-    /**
-     * @hide
-     */
+    /** @hide */
     @Override
-    public boolean isAutofillCompatibilityEnabled() {
-        return mBase != null && mBase.isAutofillCompatibilityEnabled();
+    public AutofillOptions getAutofillOptions() {
+        return mBase == null ? null : mBase.getAutofillOptions();
     }
 
-    /**
-     * @hide
-     */
-    @TestApi
+    /** @hide */
     @Override
-    public void setAutofillCompatibilityEnabled(boolean autofillCompatEnabled) {
+    public void setAutofillOptions(AutofillOptions options) {
         if (mBase != null) {
-            mBase.setAutofillCompatibilityEnabled(autofillCompatEnabled);
+            mBase.setAutofillOptions(options);
         }
     }
 
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 14e7725..dcbb4ac 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -111,7 +111,7 @@
     int getPermissionFlags(String permissionName, String packageName, int userId);
 
     void updatePermissionFlags(String permissionName, String packageName, int flagMask,
-            int flagValues, int userId);
+            int flagValues, boolean checkAdjustPolicyFlagPermission, int userId);
 
     void updatePermissionFlagsForAllApps(int flagMask, int flagValues, int userId);
 
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java
index 8095473..badd48f 100644
--- a/core/java/android/content/pm/PackageInstaller.java
+++ b/core/java/android/content/pm/PackageInstaller.java
@@ -1545,7 +1545,11 @@
 
         /**
          * Set this session to be installing an APEX package.
+         *
+         * {@hide}
          */
+        @SystemApi
+        @RequiresPermission(Manifest.permission.INSTALL_PACKAGES)
         public void setInstallAsApex() {
             installFlags |= PackageManager.INSTALL_APEX;
         }
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 0041921..6b2442f 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -33,6 +33,7 @@
 import android.annotation.UserIdInt;
 import android.annotation.XmlRes;
 import android.app.ActivityManager;
+import android.app.AppDetailsActivity;
 import android.app.PackageDeleteObserver;
 import android.app.PackageInstallObserver;
 import android.app.admin.DevicePolicyManager;
@@ -3030,6 +3031,13 @@
     public static final int MASK_PERMISSION_FLAGS = 0xFF;
 
     /**
+     * Injected activity in app that forwards user to setting activity of that app.
+     *
+     * @hide
+     */
+    public static final String APP_DETAILS_ACTIVITY_CLASS_NAME = AppDetailsActivity.class.getName();
+
+    /**
      * This is a library that contains components apps can invoke. For
      * example, a services for apps to bind to, or standard chooser UI,
      * etc. This library is versioned and backwards compatible. Clients
@@ -5792,6 +5800,37 @@
             @NonNull ComponentName componentName);
 
     /**
+     * Set the enabled setting for a package app settings activity.
+     *
+     * @param packageName The package name of the app
+     * @param enabled The new enabled state for app details activity
+     *
+     * @hide
+     */
+    @RequiresPermission(value = android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE,
+            conditional = true)
+    @SystemApi
+    public void setAppDetailsActivityEnabled(@NonNull String packageName, boolean enabled) {
+        throw new UnsupportedOperationException(
+                "setAppDetailsActivityEnabled not implemented");
+    }
+
+
+    /**
+     * Return the enabled setting for a package app settings activity.
+     *
+     * @param packageName The package name of the app
+     * @return Returns the current enabled state for app settings activity.
+     *
+     * @hide
+     */
+    @SystemApi
+    public boolean getAppDetailsActivityEnabled(@NonNull String packageName) {
+        throw new UnsupportedOperationException(
+                "getAppDetailsActivityEnabled not implemented");
+    }
+
+    /**
      * Set the enabled setting for an application
      * This setting will override any enabled state which may have been set by the application in
      * its manifest.  It also overrides the enabled state set in the manifest for any of the
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 0f67262..d7ca757 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -48,7 +48,6 @@
 import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
 import android.app.ActivityTaskManager;
-import android.app.AppDetailsActivity;
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.IntentFilter;
@@ -4311,7 +4310,7 @@
         } else {
             String outInfoName
                 = buildClassName(owner.applicationInfo.packageName, name, outError);
-            if (AppDetailsActivity.class.getName().equals(outInfoName)) {
+            if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(outInfoName)) {
                 outError[0] = tag + " invalid android:name";
                 return false;
             }
@@ -4364,13 +4363,14 @@
             boolean hardwareAccelerated) {
 
         // Build custom App Details activity info instead of parsing it from xml
-        Activity a = new Activity(owner, AppDetailsActivity.class.getName(), new ActivityInfo());
+        Activity a = new Activity(owner, PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME,
+                new ActivityInfo());
         a.owner = owner;
         a.setPackageName(owner.packageName);
 
         a.info.theme = android.R.style.Theme_NoDisplay;
         a.info.exported = true;
-        a.info.name = AppDetailsActivity.class.getName();
+        a.info.name = PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME;
         a.info.processName = owner.applicationInfo.processName;
         a.info.uiOptions = a.info.applicationInfo.uiOptions;
         a.info.taskAffinity = buildTaskAffinityName(owner.packageName, owner.packageName,
diff --git a/core/java/android/metrics/LogMaker.java b/core/java/android/metrics/LogMaker.java
index 19848ee..5496e17 100644
--- a/core/java/android/metrics/LogMaker.java
+++ b/core/java/android/metrics/LogMaker.java
@@ -16,6 +16,7 @@
 package android.metrics;
 
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.content.ComponentName;
 import android.util.Log;
 import android.util.SparseArray;
@@ -31,6 +32,7 @@
  * @hide
  */
 @SystemApi
+@TestApi
 public class LogMaker {
     private static final String TAG = "LogBuilder";
 
diff --git a/core/java/android/metrics/MetricsReader.java b/core/java/android/metrics/MetricsReader.java
index 5f356ca..27f9a5d 100644
--- a/core/java/android/metrics/MetricsReader.java
+++ b/core/java/android/metrics/MetricsReader.java
@@ -16,6 +16,7 @@
 package android.metrics;
 
 import android.annotation.SystemApi;
+import android.annotation.TestApi;
 import android.util.EventLog;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -35,6 +36,7 @@
  * @hide
  */
 @SystemApi
+@TestApi
 public class MetricsReader {
     private Queue<LogMaker> mPendingQueue = new LinkedList<>();
     private Queue<LogMaker> mSeenQueue = new LinkedList<>();
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 6d195ae..c1bce5e 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -3147,9 +3147,9 @@
 
         /**
          * Called if no network is found in the timeout time specified in
-         * {@link #requestNetwork(NetworkRequest, NetworkCallback, int)} call. This callback is not
-         * called for the version of {@link #requestNetwork(NetworkRequest, NetworkCallback)}
-         * without timeout. When this callback is invoked the associated
+         * {@link #requestNetwork(NetworkRequest, NetworkCallback, int)} call or if the
+         * requested network request cannot be fulfilled (whether or not a timeout was
+         * specified). When this callback is invoked the associated
          * {@link NetworkRequest} will have already been removed and released, as if
          * {@link #unregisterNetworkCallback(NetworkCallback)} had been called.
          */
diff --git a/core/java/android/net/NetworkFactory.java b/core/java/android/net/NetworkFactory.java
index 0dfe7a4..5b1d12c 100644
--- a/core/java/android/net/NetworkFactory.java
+++ b/core/java/android/net/NetworkFactory.java
@@ -27,11 +27,13 @@
 import android.util.SparseArray;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.AsyncChannel;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.Protocol;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.util.ArrayList;
 import java.util.concurrent.atomic.AtomicInteger;
 
 /**
@@ -113,7 +115,16 @@
      */
     private static final int CMD_SET_FILTER = BASE + 3;
 
+    /**
+     * Sent by NetworkFactory to ConnectivityService to indicate that a request is
+     * unfulfillable.
+     * @see #releaseRequestAsUnfulfillableByAnyFactory(NetworkRequest).
+     */
+    public static final int EVENT_UNFULFILLABLE_REQUEST = BASE + 4;
+
     private final Context mContext;
+    private final ArrayList<Message> mPreConnectedQueue = new ArrayList<Message>();
+    private AsyncChannel mAsyncChannel;
     private final String LOG_TAG;
 
     private final SparseArray<NetworkRequestInfo> mNetworkRequests =
@@ -155,6 +166,36 @@
     @Override
     public void handleMessage(Message msg) {
         switch (msg.what) {
+            case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION: {
+                if (mAsyncChannel != null) {
+                    log("Received new connection while already connected!");
+                    break;
+                }
+                if (VDBG) log("NetworkFactory fully connected");
+                AsyncChannel ac = new AsyncChannel();
+                ac.connected(null, this, msg.replyTo);
+                ac.replyToMessage(msg, AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED,
+                        AsyncChannel.STATUS_SUCCESSFUL);
+                mAsyncChannel = ac;
+                for (Message m : mPreConnectedQueue) {
+                    ac.sendMessage(m);
+                }
+                mPreConnectedQueue.clear();
+                break;
+            }
+            case AsyncChannel.CMD_CHANNEL_DISCONNECT: {
+                if (VDBG) log("CMD_CHANNEL_DISCONNECT");
+                if (mAsyncChannel != null) {
+                    mAsyncChannel.disconnect();
+                    mAsyncChannel = null;
+                }
+                break;
+            }
+            case AsyncChannel.CMD_CHANNEL_DISCONNECTED: {
+                if (DBG) log("NetworkFactory channel lost");
+                mAsyncChannel = null;
+                break;
+            }
             case CMD_REQUEST_NETWORK: {
                 handleAddRequest((NetworkRequest) msg.obj, msg.arg1, msg.arg2);
                 break;
@@ -355,6 +396,27 @@
         });
     }
 
+    /**
+     * Can be called by a factory to release a request as unfulfillable: the request will be
+     * removed, and the caller will get a
+     * {@link ConnectivityManager.NetworkCallback#onUnavailable()} callback after this function
+     * returns.
+     *
+     * Note: this should only be called by factory which KNOWS that it is the ONLY factory which
+     * is able to fulfill this request!
+     */
+    protected void releaseRequestAsUnfulfillableByAnyFactory(NetworkRequest r) {
+        post(() -> {
+            if (DBG) log("releaseRequestAsUnfulfillableByAnyFactory: " + r);
+            Message msg = obtainMessage(EVENT_UNFULFILLABLE_REQUEST, r);
+            if (mAsyncChannel != null) {
+                mAsyncChannel.sendMessage(msg);
+            } else {
+                mPreConnectedQueue.add(msg);
+            }
+        });
+    }
+
     // override to do simple mode (request independent)
     protected void startNetwork() { }
     protected void stopNetwork() { }
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index 83a7654..0425c62 100755
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -107,6 +107,7 @@
      * Whether this build was for an emulator device.
      * @hide
      */
+    @TestApi
     public static final boolean IS_EMULATOR = getString("ro.kernel.qemu").equals("1");
 
     /**
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index e2b5730..0673755 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -2697,6 +2697,19 @@
     }
 
     /**
+     * Updates the calling user's name.
+     * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
+     *
+     * @param name the new name for the user
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+    public void setUserName(String name) {
+        setUserName(getUserHandle(), name);
+    }
+
+    /**
      * Sets the user's photo.
      * @param userHandle the user for whom to change the photo.
      * @param icon the bitmap to set as the photo.
@@ -2711,6 +2724,19 @@
     }
 
     /**
+     * Sets the calling user's photo.
+     * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
+     *
+     * @param icon the bitmap to set as the photo.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+    public void setUserIcon(Bitmap icon) {
+        setUserIcon(getUserHandle(), icon);
+    }
+
+    /**
      * Returns a file descriptor for the user's photo. PNG data can be read from this file.
      * @param userHandle the user whose photo we want to read.
      * @return a {@link Bitmap} of the user's photo, or null if there's no photo.
@@ -2737,6 +2763,20 @@
     }
 
     /**
+     * Returns a Bitmap for the calling user's photo.
+     * Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
+     *
+     * @return a {@link Bitmap} of the user's photo, or null if there's no photo.
+     * @see com.android.internal.util.UserIcons#getDefaultUserIcon for a default.
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.MANAGE_USERS)
+    public Bitmap getUserIcon() {
+        return getUserIcon(getUserHandle());
+    }
+
+    /**
      * Returns the maximum number of users that can be created on this device. A return value
      * of 1 means that it is a single user device.
      * @hide
diff --git a/core/java/android/permission/IPermissionController.aidl b/core/java/android/permission/IPermissionController.aidl
index 7e9ba5d..cb2517e 100644
--- a/core/java/android/permission/IPermissionController.aidl
+++ b/core/java/android/permission/IPermissionController.aidl
@@ -40,4 +40,6 @@
     void getPermissionUsages(boolean countSystem, long numMillis, in RemoteCallback callback);
     void isApplicationQualifiedForRole(String roleName, String packageName,
             in RemoteCallback callback);
+    void setRuntimePermissionGrantStateByDeviceAdmin(String callerPackageName, String packageName,
+            String permission, int grantState, in RemoteCallback callback);
 }
diff --git a/core/java/android/permission/PermissionControllerManager.java b/core/java/android/permission/PermissionControllerManager.java
index d62bc6c5..cd7bbfd 100644
--- a/core/java/android/permission/PermissionControllerManager.java
+++ b/core/java/android/permission/PermissionControllerManager.java
@@ -16,8 +16,12 @@
 
 package android.permission;
 
+import static android.app.admin.DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT;
+import static android.app.admin.DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED;
+import static android.app.admin.DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED;
 import static android.permission.PermissionControllerService.SERVICE_INTERFACE;
 
+import static com.android.internal.util.Preconditions.checkArgument;
 import static com.android.internal.util.Preconditions.checkArgumentNonnegative;
 import static com.android.internal.util.Preconditions.checkCollectionElementsNotNull;
 import static com.android.internal.util.Preconditions.checkFlagsArgument;
@@ -35,6 +39,7 @@
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
+import android.app.admin.DevicePolicyManager.PermissionGrantState;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -268,6 +273,40 @@
     }
 
     /**
+     * Set the runtime permission state from a device admin.
+     *
+     * @param callerPackageName The package name of the admin requesting the change
+     * @param packageName Package the permission belongs to
+     * @param permission Permission to change
+     * @param grantState State to set the permission into
+     * @param executor Executor to run the {@code callback} on
+     * @param callback The callback
+     *
+     * @hide
+     */
+    @RequiresPermission(allOf = {Manifest.permission.GRANT_RUNTIME_PERMISSIONS,
+            Manifest.permission.REVOKE_RUNTIME_PERMISSIONS,
+            Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY},
+            conditional = true)
+    public void setRuntimePermissionGrantStateByDeviceAdmin(@NonNull String callerPackageName,
+            @NonNull String packageName, @NonNull String permission,
+            @PermissionGrantState int grantState, @NonNull @CallbackExecutor Executor executor,
+            @NonNull Consumer<Boolean> callback) {
+        checkStringNotEmpty(callerPackageName);
+        checkStringNotEmpty(packageName);
+        checkStringNotEmpty(permission);
+        checkArgument(grantState == PERMISSION_GRANT_STATE_GRANTED
+                || grantState == PERMISSION_GRANT_STATE_DENIED
+                || grantState == PERMISSION_GRANT_STATE_DEFAULT);
+        checkNotNull(executor);
+        checkNotNull(callback);
+
+        mRemoteService.scheduleRequest(new PendingSetRuntimePermissionGrantStateByDeviceAdmin(
+                mRemoteService, callerPackageName, packageName, permission, grantState, executor,
+                callback));
+    }
+
+    /**
      * Create a backup of the runtime permissions.
      *
      * @param user The user to be backed up
@@ -797,6 +836,67 @@
     }
 
     /**
+     * Request for {@link #getRuntimePermissionBackup}
+     */
+    private static final class PendingSetRuntimePermissionGrantStateByDeviceAdmin extends
+            AbstractRemoteService.PendingRequest<RemoteService, IPermissionController> {
+        private final @NonNull String mCallerPackageName;
+        private final @NonNull String mPackageName;
+        private final @NonNull String mPermission;
+        private final @PermissionGrantState int mGrantState;
+
+        private final @NonNull Executor mExecutor;
+        private final @NonNull Consumer<Boolean> mCallback;
+        private final @NonNull RemoteCallback mRemoteCallback;
+
+        private PendingSetRuntimePermissionGrantStateByDeviceAdmin(@NonNull RemoteService service,
+                @NonNull String callerPackageName, @NonNull String packageName,
+                @NonNull String permission, @PermissionGrantState int grantState,
+                @NonNull @CallbackExecutor Executor executor, @NonNull Consumer<Boolean> callback) {
+            super(service);
+
+            mCallerPackageName = callerPackageName;
+            mPackageName = packageName;
+            mPermission = permission;
+            mGrantState = grantState;
+            mExecutor = executor;
+            mCallback = callback;
+
+            mRemoteCallback = new RemoteCallback(result -> executor.execute(() -> {
+                long token = Binder.clearCallingIdentity();
+                try {
+                    callback.accept(result.getBoolean(KEY_RESULT, false));
+                } finally {
+                    Binder.restoreCallingIdentity(token);
+
+                    finish();
+                }
+            }), null);
+        }
+
+        @Override
+        protected void onTimeout(RemoteService remoteService) {
+            long token = Binder.clearCallingIdentity();
+            try {
+                mExecutor.execute(() -> mCallback.accept(false));
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+        }
+
+        @Override
+        public void run() {
+            try {
+                getService().getServiceInterface().setRuntimePermissionGrantStateByDeviceAdmin(
+                        mCallerPackageName, mPackageName, mPermission, mGrantState, mRemoteCallback);
+            } catch (RemoteException e) {
+                Log.e(TAG, "Error setting permissions state for device admin " + mPackageName,
+                        e);
+            }
+        }
+    }
+
+    /**
      * Request for {@link #restoreRuntimePermissionBackup}
      */
     private static final class PendingRestoreRuntimePermissionBackup implements
diff --git a/core/java/android/permission/PermissionControllerService.java b/core/java/android/permission/PermissionControllerService.java
index fb6c061..e883d25 100644
--- a/core/java/android/permission/PermissionControllerService.java
+++ b/core/java/android/permission/PermissionControllerService.java
@@ -16,6 +16,9 @@
 
 package android.permission;
 
+import static android.app.admin.DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT;
+import static android.app.admin.DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED;
+import static android.app.admin.DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED;
 import static android.permission.PermissionControllerManager.COUNT_ONLY_WHEN_GRANTED;
 import static android.permission.PermissionControllerManager.COUNT_WHEN_SYSTEM;
 
@@ -32,6 +35,7 @@
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
 import android.app.Service;
+import android.app.admin.DevicePolicyManager.PermissionGrantState;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageInfo;
@@ -180,6 +184,18 @@
     public abstract boolean onIsApplicationQualifiedForRole(@NonNull String roleName,
             @NonNull String packageName);
 
+    /**
+     * Set the runtime permission state from a device admin.
+     *
+     * @param callerPackageName The package name of the admin requesting the change
+     * @param packageName Package the permission belongs to
+     * @param permission Permission to change
+     * @param grantState State to set the permission into
+     */
+    public abstract boolean onSetRuntimePermissionGrantStateByDeviceAdmin(
+            @NonNull String callerPackageName, @NonNull String packageName,
+            @NonNull String permission, @PermissionGrantState int grantState);
+
     @Override
     public final IBinder onBind(Intent intent) {
         return new IPermissionController.Stub() {
@@ -326,6 +342,35 @@
                         PermissionControllerService::isApplicationQualifiedForRole,
                         PermissionControllerService.this, roleName, packageName, callback));
             }
+
+            @Override
+            public void setRuntimePermissionGrantStateByDeviceAdmin(String callerPackageName,
+                    String packageName, String permission, int grantState,
+                    RemoteCallback callback) {
+                checkStringNotEmpty(callerPackageName);
+                checkStringNotEmpty(packageName);
+                checkStringNotEmpty(permission);
+                checkArgument(grantState == PERMISSION_GRANT_STATE_GRANTED
+                        || grantState == PERMISSION_GRANT_STATE_DENIED
+                        || grantState == PERMISSION_GRANT_STATE_DEFAULT);
+                checkNotNull(callback);
+
+                if (grantState == PERMISSION_GRANT_STATE_DENIED) {
+                    enforceCallingPermission(Manifest.permission.GRANT_RUNTIME_PERMISSIONS, null);
+                }
+
+                if (grantState == PERMISSION_GRANT_STATE_DENIED) {
+                    enforceCallingPermission(Manifest.permission.REVOKE_RUNTIME_PERMISSIONS, null);
+                }
+
+                enforceCallingPermission(Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY,
+                        null);
+
+                mHandler.sendMessage(obtainMessage(
+                        PermissionControllerService::setRuntimePermissionGrantStateByDeviceAdmin,
+                        PermissionControllerService.this, callerPackageName, packageName,
+                        permission, grantState, callback));
+            }
         };
     }
 
@@ -399,4 +444,15 @@
         result.putBoolean(PermissionControllerManager.KEY_RESULT, qualified);
         callback.sendResult(result);
     }
+
+    private void setRuntimePermissionGrantStateByDeviceAdmin(@NonNull String callerPackageName,
+            @NonNull String packageName, @NonNull String permission,
+            @PermissionGrantState int grantState, @NonNull RemoteCallback callback) {
+        boolean wasSet = onSetRuntimePermissionGrantStateByDeviceAdmin(callerPackageName,
+                packageName, permission, grantState);
+
+        Bundle result = new Bundle();
+        result.putBoolean(PermissionControllerManager.KEY_RESULT, wasSet);
+        callback.sendResult(result);
+    }
 }
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index f63c0adb..44adc1c 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -783,7 +783,7 @@
                 String postDialDigits, String viaNumber, int presentation, int callType,
                 int features, PhoneAccountHandle accountHandle, long start, int duration,
                 Long dataUsage, boolean addForAllUsers, UserHandle userToBeInsertedTo,
-                boolean isRead, int callBlockReason, String callScreeningAppName,
+                boolean isRead, int callBlockReason, CharSequence callScreeningAppName,
                 String callScreeningComponentName, CallIdentification callIdentification) {
             if (VERBOSE_LOG) {
                 Log.v(LOG_TAG, String.format("Add call: number=%s, user=%s, for all=%s",
@@ -836,15 +836,19 @@
             }
 
             values.put(BLOCK_REASON, callBlockReason);
-            values.put(CALL_SCREENING_APP_NAME, callScreeningAppName);
+            values.put(CALL_SCREENING_APP_NAME, charSequenceToString(callScreeningAppName));
             values.put(CALL_SCREENING_COMPONENT_NAME, callScreeningComponentName);
 
             if (callIdentification != null) {
                 values.put(CALL_ID_PACKAGE_NAME, callIdentification.getCallScreeningPackageName());
-                values.put(CALL_ID_APP_NAME, callIdentification.getCallScreeningAppName());
-                values.put(CALL_ID_NAME, callIdentification.getName());
-                values.put(CALL_ID_DESCRIPTION, callIdentification.getDescription());
-                values.put(CALL_ID_DETAILS, callIdentification.getDetails());
+                values.put(CALL_ID_APP_NAME,
+                        charSequenceToString(callIdentification.getCallScreeningAppName()));
+                values.put(CALL_ID_NAME,
+                        charSequenceToString(callIdentification.getName()));
+                values.put(CALL_ID_DESCRIPTION,
+                        charSequenceToString(callIdentification.getDescription()));
+                values.put(CALL_ID_DETAILS,
+                        charSequenceToString(callIdentification.getDetails()));
                 values.put(CALL_ID_NUISANCE_CONFIDENCE, callIdentification.getNuisanceConfidence());
             } else {
                 values.putNull(CALL_ID_PACKAGE_NAME);
@@ -987,6 +991,10 @@
             return result;
         }
 
+        private static String charSequenceToString(CharSequence sequence) {
+            return sequence == null ? null : sequence.toString();
+        }
+
         /** @hide */
         public static boolean shouldHaveSharedCallLogEntries(Context context,
                 UserManager userManager, int userId) {
diff --git a/core/java/android/provider/DeviceConfig.java b/core/java/android/provider/DeviceConfig.java
index f6a8388..868a36b 100644
--- a/core/java/android/provider/DeviceConfig.java
+++ b/core/java/android/provider/DeviceConfig.java
@@ -169,7 +169,7 @@
          *
          * @hide for internal use only
          */
-        String BLASTULA_POOL_SIZE_MIN = "blastula_pool_size_max";
+        String BLASTULA_POOL_SIZE_MIN = "blastula_pool_size_min";
 
         /**
          * The threshold used to determine if the pool should be refilled.
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index a465b32..1530626 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -8131,6 +8131,7 @@
          *
          * @hide
          */
+        @TestApi
         public static final String ENABLED_VR_LISTENERS = "enabled_vr_listeners";
 
         private static final Validator ENABLED_VR_LISTENERS_VALIDATOR =
@@ -10780,6 +10781,7 @@
         *
         * @hide
         */
+       @TestApi
        public static final String OVERLAY_DISPLAY_DEVICES = "overlay_display_devices";
 
         /**
@@ -14096,18 +14098,17 @@
         public static final String SHOW_TEMPERATURE_WARNING = "show_temperature_warning";
 
         /**
+         * Whether to show the usb high temperature alarm notification.
+         * @hide
+         */
+        public static final String SHOW_USB_TEMPERATURE_ALARM = "show_usb_temperature_alarm";
+
+        /**
          * Temperature at which the high temperature warning notification should be shown.
          * @hide
          */
         public static final String WARNING_TEMPERATURE = "warning_temperature";
 
-
-        /**
-         * USB Temperature at which the high temperature alarm notification should be shown.
-         * @hide
-         */
-        public static final String USB_ALARM_TEMPERATURE = "usb_alarm_temperature";
-
         /**
          * Whether the diskstats logging task is enabled/disabled.
          * @hide
diff --git a/core/java/android/text/style/DynamicDrawableSpan.java b/core/java/android/text/style/DynamicDrawableSpan.java
index 5754014..1a508a1 100644
--- a/core/java/android/text/style/DynamicDrawableSpan.java
+++ b/core/java/android/text/style/DynamicDrawableSpan.java
@@ -16,6 +16,9 @@
 
 package android.text.style;
 
+import static java.lang.annotation.RetentionPolicy.SOURCE;
+
+import android.annotation.IntDef;
 import android.annotation.IntRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -25,6 +28,7 @@
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 
+import java.lang.annotation.Retention;
 import java.lang.ref.WeakReference;
 
 /**
@@ -80,10 +84,21 @@
     /**
      * A constant indicating that this span should be vertically centered between
      * the top and the lowest descender.
-     * @hide
      */
     public static final int ALIGN_CENTER = 2;
 
+    /**
+     * Defines acceptable alignment types.
+     * @hide
+     */
+    @Retention(SOURCE)
+    @IntDef(prefix = { "ALIGN_" }, value = {
+            ALIGN_BOTTOM,
+            ALIGN_BASELINE,
+            ALIGN_CENTER
+    })
+    public @interface AlignmentType {}
+
     protected final int mVerticalAlignment;
 
     @UnsupportedAppUsage
@@ -100,17 +115,18 @@
     /**
      * Creates a {@link DynamicDrawableSpan} based on a vertical alignment.\
      *
-     * @param verticalAlignment one of {@link #ALIGN_BOTTOM} or {@link #ALIGN_BASELINE}
+     * @param verticalAlignment one of {@link #ALIGN_BOTTOM}, {@link #ALIGN_BASELINE} or
+     *                          {@link #ALIGN_CENTER}
      */
-    protected DynamicDrawableSpan(int verticalAlignment) {
+    protected DynamicDrawableSpan(@AlignmentType int verticalAlignment) {
         mVerticalAlignment = verticalAlignment;
     }
 
     /**
-     * Returns the vertical alignment of this span, one of {@link #ALIGN_BOTTOM} or
-     * {@link #ALIGN_BASELINE}.
+     * Returns the vertical alignment of this span, one of {@link #ALIGN_BOTTOM},
+     * {@link #ALIGN_BASELINE} or {@link #ALIGN_CENTER}.
      */
-    public int getVerticalAlignment() {
+    public @AlignmentType int getVerticalAlignment() {
         return mVerticalAlignment;
     }
 
diff --git a/core/java/android/util/TimeUtils.java b/core/java/android/util/TimeUtils.java
index e4c8eeb..f8b38e9 100644
--- a/core/java/android/util/TimeUtils.java
+++ b/core/java/android/util/TimeUtils.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
 import android.os.Build;
 import android.os.SystemClock;
@@ -302,6 +303,7 @@
     }
 
     /** @hide Just for debugging; not internationalized. */
+    @TestApi
     public static String formatDuration(long duration) {
         synchronized (sFormatSync) {
             int len = formatDurationLocked(duration, 0);
diff --git a/core/java/android/view/Display.java b/core/java/android/view/Display.java
index cb5100a..94a9a1c 100644
--- a/core/java/android/view/Display.java
+++ b/core/java/android/view/Display.java
@@ -21,6 +21,7 @@
 import android.annotation.IntDef;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
+import android.annotation.TestApi;
 import android.annotation.UnsupportedAppUsage;
 import android.app.KeyguardManager;
 import android.content.res.CompatibilityInfo;
@@ -911,6 +912,7 @@
      * @see #FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS
      * @hide
      */
+    @TestApi
     // TODO (b/114338689): Remove the method and use IWindowManager#shouldShowSystemDecors
     public boolean supportsSystemDecorations() {
         return (mDisplayInfo.flags & FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS) != 0;
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 2ef7c4b..5dc54a5 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -582,4 +582,13 @@
      *        display should be re-parented to.
      */
     void reparentDisplayContent(int displayId, in SurfaceControl sc);
+
+    /**
+     * Waits for transactions to get applied before injecting input.
+     * This includes waiting for the input windows to get sent to InputManager.
+     *
+     * This is needed for testing since the system add windows and injects input
+     * quick enough that the windows don't have time to get sent to InputManager.
+     */
+     boolean injectInputAfterTransactionsApplied(in InputEvent ev, int mode);
 }
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index e5db44e..aaf85af 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -189,6 +189,7 @@
             IBinder toToken);
     private static native boolean nativeGetProtectedContentSupport();
     private static native void nativeSetMetadata(long transactionObj, int key, Parcel data);
+    private static native void nativeSyncInputWindows(long transactionObj);
 
     private final CloseGuard mCloseGuard = CloseGuard.get();
     private String mName;
@@ -2109,6 +2110,17 @@
         }
 
         /**
+         * Waits until any changes to input windows have been sent from SurfaceFlinger to
+         * InputFlinger before returning.
+         *
+         * @hide
+         */
+        public Transaction syncInputWindows() {
+            nativeSyncInputWindows(mNativeObject);
+            return this;
+        }
+
+        /**
          * Specify how the buffer assosciated with this Surface is mapped in to the
          * parent coordinate space. The source frame will be scaled to fit the destination
          * frame, after being rotated according to the orientation parameter.
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index ab4847d..89c6703 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -29,6 +29,7 @@
 
 import android.Manifest;
 import android.animation.LayoutTransition;
+import android.annotation.AnyThread;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.UnsupportedAppUsage;
@@ -1041,10 +1042,22 @@
         return mHeight;
     }
 
+    /**
+     * Destroys hardware rendering resources for this ViewRootImpl
+     *
+     * May be called on any thread
+     */
+    @AnyThread
     void destroyHardwareResources() {
-        if (mAttachInfo.mThreadedRenderer != null) {
-            mAttachInfo.mThreadedRenderer.destroyHardwareResources(mView);
-            mAttachInfo.mThreadedRenderer.destroy();
+        final ThreadedRenderer renderer = mAttachInfo.mThreadedRenderer;
+        if (renderer != null) {
+            // This is called by WindowManagerGlobal which may or may not be on the right thread
+            if (Looper.myLooper() != mAttachInfo.mHandler.getLooper()) {
+                mAttachInfo.mHandler.postAtFrontOfQueue(this::destroyHardwareResources);
+                return;
+            }
+            renderer.destroyHardwareResources(mView);
+            renderer.destroy();
         }
     }
 
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index e9b1683..9dcbe05 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -28,6 +28,7 @@
 import android.annotation.SystemApi;
 import android.annotation.SystemService;
 import android.annotation.TestApi;
+import android.content.AutofillOptions;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
@@ -482,6 +483,9 @@
     @GuardedBy("mLock")
     private CompatibilityBridge mCompatibilityBridge;
 
+    @Nullable
+    private final AutofillOptions mOptions;
+
     /** @hide */
     public interface AutofillClient {
         /**
@@ -618,6 +622,12 @@
     public AutofillManager(Context context, IAutoFillManager service) {
         mContext = Preconditions.checkNotNull(context, "context cannot be null");
         mService = service;
+        mOptions = context.getAutofillOptions();
+
+        if (mOptions != null) {
+            sDebug = (mOptions.loggingLevel & FLAG_ADD_CLIENT_DEBUG) != 0;
+            sVerbose = (mOptions.loggingLevel & FLAG_ADD_CLIENT_VERBOSE) != 0;
+        }
     }
 
     /**
@@ -2352,6 +2362,9 @@
         pw.print(pfx); pw.print("entered ids: "); pw.println(mEnteredIds);
         pw.print(pfx); pw.print("save trigger id: "); pw.println(mSaveTriggerId);
         pw.print(pfx); pw.print("save on finish(): "); pw.println(mSaveOnFinish);
+        if (mOptions != null) {
+            pw.print(pfx); pw.print("options: "); mOptions.dumpShort(pw); pw.println();
+        }
         pw.print(pfx); pw.print("compat mode enabled: ");
         synchronized (mLock) {
             if (mCompatibilityBridge != null) {
diff --git a/core/java/android/view/autofill/AutofillManagerInternal.java b/core/java/android/view/autofill/AutofillManagerInternal.java
index 155fe72..d5862bd 100644
--- a/core/java/android/view/autofill/AutofillManagerInternal.java
+++ b/core/java/android/view/autofill/AutofillManagerInternal.java
@@ -16,7 +16,9 @@
 package android.view.autofill;
 
 import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.annotation.UserIdInt;
+import android.content.AutofillOptions;
 
 /**
  * Autofill Manager local system service interface.
@@ -31,12 +33,13 @@
     public abstract void onBackKeyPressed();
 
     /**
-     * Gets whether compatibility mode is enabled for a package
+     * Gets autofill options for a package
      *
      * @param packageName The package for which to query.
      * @param versionCode The package version code.
      * @param userId The user id for which to query.
      */
-    public abstract boolean isCompatibilityModeRequested(@NonNull String packageName,
+    @Nullable
+    public abstract AutofillOptions getAutofillOptions(@NonNull String packageName,
             long versionCode, @UserIdInt int userId);
 }
diff --git a/core/java/android/view/textclassifier/ExtrasUtils.java b/core/java/android/view/textclassifier/ExtrasUtils.java
index b0e7ad5..2ad17a8 100644
--- a/core/java/android/view/textclassifier/ExtrasUtils.java
+++ b/core/java/android/view/textclassifier/ExtrasUtils.java
@@ -94,7 +94,8 @@
         if (actionIntents != null) {
             final int size = actionIntents.size();
             for (int i = 0; i < size; i++) {
-                if (intentAction.equals(actionIntents.get(i).getAction())) {
+                final Intent intent = actionIntents.get(i);
+                if (intent != null && intentAction.equals(intent.getAction())) {
                     return classification.getActions().get(i);
                 }
             }
diff --git a/core/java/android/view/textclassifier/TextClassification.java b/core/java/android/view/textclassifier/TextClassification.java
index a059209..052ee95 100644
--- a/core/java/android/view/textclassifier/TextClassification.java
+++ b/core/java/android/view/textclassifier/TextClassification.java
@@ -54,6 +54,7 @@
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+import java.util.Objects;
 
 /**
  * Information for generating a widget to handle classified text.
@@ -276,8 +277,8 @@
     @Override
     public String toString() {
         return String.format(Locale.US,
-                "TextClassification {text=%s, entities=%s, actions=%s, id=%s}",
-                mText, mEntityConfidence, mActions, mId);
+                "TextClassification {text=%s, entities=%s, actions=%s, id=%s, extras=%s}",
+                mText, mEntityConfidence, mActions, mId, mExtras);
     }
 
     /**
@@ -532,7 +533,7 @@
 
         private Bundle buildExtras() {
             final Bundle extras = mExtras == null ? new Bundle() : mExtras.deepCopy();
-            if (!mActionIntents.isEmpty()) {
+            if (mActionIntents.stream().anyMatch(Objects::nonNull)) {
                 ExtrasUtils.putActionsIntents(extras, mActionIntents);
             }
             if (mForeignLanguageExtra != null) {
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index 295c8b7..e628f19 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -240,9 +240,7 @@
                                                 refTime.getZone().getId(),
                                                 localesString),
                                         mContext,
-                                        // TODO: Pass the locale list once it is supported in
-                                        //  native side.
-                                        LocaleList.getDefault().get(0).toLanguageTag()
+                                        getResourceLocaleString()
                                 );
                 if (results.length > 0) {
                     return createClassificationResult(
@@ -403,8 +401,7 @@
                             nativeConversation,
                             null,
                             mContext,
-                            // TODO: Pass the locale list once it is supported in native side.
-                            LocaleList.getDefault().get(0).toLanguageTag());
+                            getResourceLocaleString());
             return createConversationActionResult(request, nativeSuggestions);
         } catch (Throwable t) {
             // Avoid throwing from this method. Log the error.
@@ -456,10 +453,9 @@
         TextLanguage textLanguage = detectLanguage(request);
         int localeHypothesisCount = textLanguage.getLocaleHypothesisCount();
         List<String> languageTags = new ArrayList<>();
-        // TODO: Reconsider this and probably make the score threshold configurable.
         for (int i = 0; i < localeHypothesisCount; i++) {
             ULocale locale = textLanguage.getLocale(i);
-            if (textLanguage.getConfidenceScore(locale) < 0.5) {
+            if (textLanguage.getConfidenceScore(locale) < getForeignLanguageThreshold()) {
                 break;
             }
             languageTags.add(locale.toLanguageTag());
@@ -587,15 +583,10 @@
             }
         }
 
-        final float foreignTextThreshold = mSettings.getLangIdThresholdOverride() >= 0
-                ? mSettings.getLangIdThresholdOverride()
-                : 0.5f /* TODO: Load this from the langId model. */;
-        final Bundle foreignLanguageBundle =
-                detectForeignLanguage(classifiedText, foreignTextThreshold);
+        final Bundle foreignLanguageBundle = detectForeignLanguage(classifiedText);
         builder.setForeignLanguageExtra(foreignLanguageBundle);
 
         boolean isPrimaryAction = true;
-        final ArrayList<Intent> sourceIntents = new ArrayList<>();
         List<LabeledIntent> labeledIntents = mIntentFactory.create(
                 mContext,
                 classifiedText,
@@ -626,16 +617,20 @@
 
     /**
      * Returns a bundle with the language and confidence score if it finds the text to be
-     * in a foreign language. Otherwise returns null.
+     * in a foreign language. Otherwise returns null. This algorithm defines what the system thinks
+     * is a foreign language.
      */
+    // TODO: Revisit this algorithm.
+    // TODO: Consider making this public API.
     @Nullable
-    private Bundle detectForeignLanguage(String text, float threshold) {
-        if (threshold > 1) {
-            return null;
-        }
-
-        // TODO: Revisit this algorithm.
+    private Bundle detectForeignLanguage(String text) {
         try {
+            final float threshold = getForeignLanguageThreshold();
+            if (threshold > 1) {
+                Log.v(LOG_TAG, "Foreign language detection disabled.");
+                return null;
+            }
+
             final LangIdModel langId = getLangIdImpl();
             final LangIdModel.LanguageResult[] langResults = langId.detectLanguages(text);
             if (langResults.length <= 0) {
@@ -651,8 +646,8 @@
             if (highestScoringResult.getScore() < threshold) {
                 return null;
             }
-            // TODO: Remove
-            Log.d(LOG_TAG, String.format("Language detected: <%s:%s>",
+
+            Log.v(LOG_TAG, String.format("Language detected: <%s:%s>",
                     highestScoringResult.getLanguage(), highestScoringResult.getScore()));
 
             final Locale detected = new Locale(highestScoringResult.getLanguage());
@@ -671,6 +666,18 @@
         return null;
     }
 
+    private float getForeignLanguageThreshold() {
+        try {
+            return mSettings.getLangIdThresholdOverride() >= 0
+                    ? mSettings.getLangIdThresholdOverride()
+                    : getLangIdImpl().getTranslateThreshold();
+        } catch (FileNotFoundException e) {
+            final float defaultThreshold = 0.5f;
+            Log.v(LOG_TAG, "Using default foreign language threshold: " + defaultThreshold);
+            return defaultThreshold;
+        }
+    }
+
     @Override
     public void dump(@NonNull IndentingPrintWriter printWriter) {
         synchronized (mLock) {
@@ -719,6 +726,19 @@
     }
 
     /**
+     * Returns the locale string for the current resources configuration.
+     */
+    private String getResourceLocaleString() {
+        // TODO: Pass the locale list once it is supported in native side.
+        try {
+            return mContext.getResources().getConfiguration().getLocales().get(0).toLanguageTag();
+        } catch (NullPointerException e) {
+            // NPE is unexpected. Erring on the side of caution.
+            return LocaleList.getDefault().get(0).toLanguageTag();
+        }
+    }
+
+    /**
      * Helper class to store the information from which RemoteActions are built.
      */
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 0fbd4dc..89e3d6b 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -381,6 +381,8 @@
         final long systemCost = mChooserShownTime - intentReceivedTime;
 
         getMetricsLogger().write(new LogMaker(MetricsEvent.ACTION_ACTIVITY_CHOOSER_SHOWN)
+                .setSubtype(isWorkProfile() ? MetricsEvent.MANAGED_PROFILE :
+                        MetricsEvent.PARENT_PROFILE)
                 .addTaggedData(MetricsEvent.FIELD_SHARESHEET_MIMETYPE, target.getType())
                 .addTaggedData(MetricsEvent.FIELD_TIME_TO_APP_TARGETS, systemCost));
 
@@ -418,6 +420,16 @@
     }
 
     /**
+     * Check if the profile currently used is a work profile.
+     * @return true if it is work profile, false if it is parent profile (or no work profile is
+     * set up)
+     */
+    protected boolean isWorkProfile() {
+        return ((UserManager) getSystemService(Context.USER_SERVICE))
+                .getUserInfo(UserHandle.myUserId()).isManagedProfile();
+    }
+
+    /**
      * Override method to add content preview area, specific to the chooser activity.
      */
     @Override
diff --git a/core/java/com/android/internal/app/IntentForwarderActivity.java b/core/java/com/android/internal/app/IntentForwarderActivity.java
index d13bcf2..64f0010 100644
--- a/core/java/com/android/internal/app/IntentForwarderActivity.java
+++ b/core/java/com/android/internal/app/IntentForwarderActivity.java
@@ -31,6 +31,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.pm.UserInfo;
+import android.metrics.LogMaker;
 import android.os.Bundle;
 import android.os.RemoteException;
 import android.os.UserHandle;
@@ -39,6 +40,8 @@
 import android.widget.Toast;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 
 import java.util.Arrays;
 import java.util.HashSet;
@@ -66,6 +69,8 @@
 
     private Injector mInjector;
 
+    private MetricsLogger mMetricsLogger;
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -78,9 +83,17 @@
         if (className.equals(FORWARD_INTENT_TO_PARENT)) {
             userMessageId = com.android.internal.R.string.forward_intent_to_owner;
             targetUserId = getProfileParent();
+
+            getMetricsLogger().write(
+                    new LogMaker(MetricsEvent.ACTION_SWITCH_SHARE_PROFILE)
+                    .setSubtype(MetricsEvent.PARENT_PROFILE));
         } else if (className.equals(FORWARD_INTENT_TO_MANAGED_PROFILE)) {
             userMessageId = com.android.internal.R.string.forward_intent_to_work;
             targetUserId = getManagedProfile();
+
+            getMetricsLogger().write(
+                    new LogMaker(MetricsEvent.ACTION_SWITCH_SHARE_PROFILE)
+                    .setSubtype(MetricsEvent.MANAGED_PROFILE));
         } else {
             Slog.wtf(TAG, IntentForwarderActivity.class.getName() + " cannot be called directly");
             userMessageId = -1;
@@ -257,6 +270,13 @@
         intent.setComponent(null);
     }
 
+    protected MetricsLogger getMetricsLogger() {
+        if (mMetricsLogger == null) {
+            mMetricsLogger = new MetricsLogger();
+        }
+        return mMetricsLogger;
+    }
+
     @VisibleForTesting
     protected Injector createInjector() {
         return new InjectorImpl();
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 6b8d8b1..003ee37 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -406,6 +406,11 @@
     transaction->transferTouchFocus(fromToken, toToken);
 }
 
+static void nativeSyncInputWindows(JNIEnv* env, jclass clazz, jlong transactionObj) {
+    auto transaction = reinterpret_cast<SurfaceComposerClient::Transaction*>(transactionObj);
+    transaction->syncInputWindows();
+}
+
 static void nativeSetMetadata(JNIEnv* env, jclass clazz, jlong transactionObj,
         jlong nativeObject, jint id, jobject parcelObj) {
     Parcel* parcel = parcelForJavaObject(env, parcelObj);
@@ -1246,7 +1251,9 @@
             "(Landroid/os/IBinder;JJ)Landroid/hardware/display/DisplayedContentSample;",
             (void*)nativeGetDisplayedContentSample },
     {"nativeSetGeometry", "(JJLandroid/graphics/Rect;Landroid/graphics/Rect;J)V",
-            (void*)nativeSetGeometry }
+            (void*)nativeSetGeometry },
+    {"nativeSyncInputWindows", "(J)V",
+            (void*)nativeSyncInputWindows }
 };
 
 int register_android_view_SurfaceControl(JNIEnv* env)
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index cccb40d..c1cbd52 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -920,8 +920,7 @@
         // Temperature at which the high temperature warning notification should
         // be shown.
         optional SettingProto warning_temperature_level = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
-        // USB temperature at which the high temperature alarm notification should be shown.
-        optional SettingProto usb_alarm_temperature_level = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
+        optional SettingProto show_usb_temperature_alarm = 3 [ (android.privacy).dest = DEST_AUTOMATIC ];
     }
     optional TemperatureWarning temperature_warning = 119;
 
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index fc896cf..0149365 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3418,6 +3418,11 @@
     <permission android:name="android.permission.GET_RUNTIME_PERMISSIONS"
                 android:protectionLevel="signature" />
 
+    <!-- @SystemApi Allows an application to change policy_fixed permissions.
+    @hide -->
+    <permission android:name="android.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY"
+                android:protectionLevel="signature|installer" />
+
     <!-- @hide Allows an application to observe permission changes. -->
     <permission android:name="android.permission.OBSERVE_GRANT_REVOKE_PERMISSIONS"
         android:protectionLevel="signature|privileged" />
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index e1ce2f6..5a3c536 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2998,6 +2998,8 @@
       <public name="config_showDefaultEmergency" />
       <!-- @hide @SystemApi -->
       <public name="config_showDefaultHome" />
+      <!-- @hide @TestApi -->
+      <public name="config_perDisplayFocusEnabled" />
     </public-group>
 
     <public-group type="dimen" first-id="0x01050007">
diff --git a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
index 9fabe44..d73c174 100644
--- a/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
+++ b/core/tests/coretests/src/android/app/servertransaction/TransactionParcelTests.java
@@ -28,6 +28,7 @@
 import android.app.IInstrumentationWatcher;
 import android.app.IUiAutomationConnection;
 import android.app.ProfilerInfo;
+import android.content.AutofillOptions;
 import android.content.ComponentName;
 import android.content.ContentCaptureOptions;
 import android.content.IIntentReceiver;
@@ -407,7 +408,7 @@
                 IUiAutomationConnection iUiAutomationConnection, int i, boolean b, boolean b1,
                 boolean b2, boolean b3, Configuration configuration,
                 CompatibilityInfo compatibilityInfo, Map map, Bundle bundle1, String s1,
-                boolean autofillCompatEnabled, ContentCaptureOptions o) throws RemoteException {
+                AutofillOptions ao, ContentCaptureOptions co) throws RemoteException {
         }
 
         @Override
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index 46cac7a..3a1a4fc 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -429,6 +429,7 @@
                     Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS,
                     Settings.Global.SHOW_RESTART_IN_CRASH_DIALOG,
                     Settings.Global.SHOW_TEMPERATURE_WARNING,
+                    Settings.Global.SHOW_USB_TEMPERATURE_ALARM,
                     Settings.Global.SIGNED_CONFIG_VERSION,
                     Settings.Global.SMART_SELECTION_UPDATE_CONTENT_URL,
                     Settings.Global.SMART_SELECTION_UPDATE_METADATA_URL,
@@ -504,7 +505,6 @@
                     Settings.Global.USER_SWITCHER_ENABLED,
                     Settings.Global.NETWORK_ACCESS_TIMEOUT_MS,
                     Settings.Global.WARNING_TEMPERATURE,
-                    Settings.Global.USB_ALARM_TEMPERATURE,
                     Settings.Global.WEBVIEW_DATA_REDUCTION_PROXY_KEY,
                     Settings.Global.WEBVIEW_FALLBACK_LOGIC_ENABLED,
                     Settings.Global.WEBVIEW_MULTIPROCESS,
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java
index 99c959e..d544029 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationTest.java
@@ -93,8 +93,8 @@
         final String id = "id";
         final TextClassification reference = new TextClassification.Builder()
                 .setText(text)
-                .addAction(remoteAction0)
-                .addAction(remoteAction1)
+                .addAction(remoteAction0)  // Action intent not included.
+                .addAction(remoteAction1)  // Action intent not included.
                 .setEntityType(TextClassifier.TYPE_ADDRESS, 0.3f)
                 .setEntityType(TextClassifier.TYPE_PHONE, 0.7f)
                 .setId(id)
@@ -132,6 +132,7 @@
 
         // Extras
         assertEquals(BUNDLE_VALUE, result.getExtras().getString(BUNDLE_KEY));
+        assertNull(ExtrasUtils.getActionsIntents(result));
     }
 
     @Test
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 f27f3f9..9fbc166 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
@@ -57,7 +57,7 @@
 import com.android.internal.R;
 import com.android.internal.app.ResolverActivity.ResolvedComponentInfo;
 import com.android.internal.logging.MetricsLogger;
-import com.android.internal.logging.nano.MetricsProto;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -524,15 +524,45 @@
         waitForIdle();
         verify(mockLogger, atLeastOnce()).write(logMakerCaptor.capture());
         assertThat(logMakerCaptor.getAllValues().get(0).getCategory(),
-                is(MetricsProto.MetricsEvent.ACTION_ACTIVITY_CHOOSER_SHOWN));
+                is(MetricsEvent.ACTION_ACTIVITY_CHOOSER_SHOWN));
         assertThat(logMakerCaptor
                 .getAllValues().get(0)
-                .getTaggedData(MetricsProto.MetricsEvent.FIELD_TIME_TO_APP_TARGETS),
+                .getTaggedData(MetricsEvent.FIELD_TIME_TO_APP_TARGETS),
                 is(notNullValue()));
         assertThat(logMakerCaptor
                 .getAllValues().get(0)
-                .getTaggedData(MetricsProto.MetricsEvent.FIELD_SHARESHEET_MIMETYPE),
+                .getTaggedData(MetricsEvent.FIELD_SHARESHEET_MIMETYPE),
                 is("TestType"));
+        assertThat(logMakerCaptor
+                        .getAllValues().get(0)
+                        .getSubtype(),
+                is(MetricsEvent.PARENT_PROFILE));
+    }
+
+    @Test
+    public void testOnCreateLoggingFromWorkProfile() {
+        Intent sendIntent = createSendTextIntent();
+        sendIntent.setType("TestType");
+        sOverrides.alternateProfileSetting = MetricsEvent.MANAGED_PROFILE;
+        MetricsLogger mockLogger = sOverrides.metricsLogger;
+        ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class);
+        mActivityRule.launchActivity(Intent.createChooser(sendIntent, "logger test"));
+        waitForIdle();
+        verify(mockLogger, atLeastOnce()).write(logMakerCaptor.capture());
+        assertThat(logMakerCaptor.getAllValues().get(0).getCategory(),
+                is(MetricsEvent.ACTION_ACTIVITY_CHOOSER_SHOWN));
+        assertThat(logMakerCaptor
+                        .getAllValues().get(0)
+                        .getTaggedData(MetricsEvent.FIELD_TIME_TO_APP_TARGETS),
+                is(notNullValue()));
+        assertThat(logMakerCaptor
+                        .getAllValues().get(0)
+                        .getTaggedData(MetricsEvent.FIELD_SHARESHEET_MIMETYPE),
+                is("TestType"));
+        assertThat(logMakerCaptor
+                        .getAllValues().get(0)
+                        .getSubtype(),
+                is(MetricsEvent.MANAGED_PROFILE));
     }
 
     @Test
@@ -547,7 +577,7 @@
         verify(mockLogger, Mockito.times(1)).write(logMakerCaptor.capture());
         // First invocation is from onCreate
         assertThat(logMakerCaptor.getAllValues().get(0).getCategory(),
-                is(MetricsProto.MetricsEvent.ACTION_ACTIVITY_CHOOSER_SHOWN));
+                is(MetricsEvent.ACTION_ACTIVITY_CHOOSER_SHOWN));
     }
 
     @Test
@@ -569,7 +599,7 @@
         verify(mockLogger, Mockito.times(3)).write(logMakerCaptor.capture());
         // First invocation is from onCreate
         assertThat(logMakerCaptor.getAllValues().get(1).getCategory(),
-                is(MetricsProto.MetricsEvent.ACTION_SHARE_WITH_PREVIEW));
+                is(MetricsEvent.ACTION_SHARE_WITH_PREVIEW));
         assertThat(logMakerCaptor.getAllValues().get(1).getSubtype(),
                 is(CONTENT_PREVIEW_TEXT));
     }
@@ -599,11 +629,11 @@
         verify(mockLogger, Mockito.times(3)).write(logMakerCaptor.capture());
         // First invocation is from onCreate
         assertThat(logMakerCaptor.getAllValues().get(1).getCategory(),
-                is(MetricsProto.MetricsEvent.ACTION_SHARE_WITH_PREVIEW));
+                is(MetricsEvent.ACTION_SHARE_WITH_PREVIEW));
         assertThat(logMakerCaptor.getAllValues().get(1).getSubtype(),
                 is(CONTENT_PREVIEW_IMAGE));
         assertThat(logMakerCaptor.getAllValues().get(2).getCategory(),
-                is(MetricsProto.MetricsEvent.ACTION_SHARE_WITH_PREVIEW));
+                is(MetricsEvent.ACTION_SHARE_WITH_PREVIEW));
         assertThat(logMakerCaptor.getAllValues().get(2).getSubtype(),
                 is(CONTENT_PREVIEW_IMAGE));
     }
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
index 57c84ff..a8dd69a 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java
@@ -28,6 +28,7 @@
 import android.util.Size;
 
 import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 
 import java.util.function.Function;
 
@@ -112,6 +113,14 @@
         return super.queryResolver(resolver, uri);
     }
 
+    @Override
+    protected boolean isWorkProfile() {
+        if (sOverrides.alternateProfileSetting != 0) {
+            return sOverrides.alternateProfileSetting == MetricsEvent.MANAGED_PROFILE;
+        }
+        return super.isWorkProfile();
+    }
+
     /**
      * We cannot directly mock the activity created since instrumentation creates it.
      * <p>
@@ -128,6 +137,7 @@
         public boolean resolverForceException;
         public Bitmap previewThumbnail;
         public MetricsLogger metricsLogger;
+        public int alternateProfileSetting;
 
         public void reset() {
             onSafelyStartCallback = null;
@@ -139,6 +149,7 @@
             resolverForceException = false;
             resolverListController = mock(ResolverListController.class);
             metricsLogger = mock(MetricsLogger.class);
+            alternateProfileSetting = 0;
         }
     }
 }
diff --git a/core/tests/coretests/src/com/android/internal/app/IntentForwarderActivityTest.java b/core/tests/coretests/src/com/android/internal/app/IntentForwarderActivityTest.java
index 9b13af2..abfb4fb 100644
--- a/core/tests/coretests/src/com/android/internal/app/IntentForwarderActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/IntentForwarderActivityTest.java
@@ -25,6 +25,7 @@
 import static org.mockito.ArgumentMatchers.anyString;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.ArgumentMatchers.nullable;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.spy;
 import static org.mockito.Mockito.verify;
@@ -40,6 +41,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
 import android.content.pm.UserInfo;
+import android.metrics.LogMaker;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.IBinder;
@@ -51,6 +53,9 @@
 import androidx.test.rule.ActivityTestRule;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -70,6 +75,11 @@
                     "android",
                     IntentForwarderActivity.FORWARD_INTENT_TO_MANAGED_PROFILE
             );
+    private static final ComponentName FORWARD_TO_PARENT_COMPONENT_NAME =
+            new ComponentName(
+                    "android",
+                    IntentForwarderActivity.FORWARD_INTENT_TO_PARENT
+            );
     private static final String TYPE_PLAIN_TEXT = "text/plain";
 
     private static UserInfo MANAGED_PROFILE_INFO = new UserInfo();
@@ -522,6 +532,60 @@
         verify(sInjector).showToast(anyInt(), anyInt());
     }
 
+    @Test
+    public void forwardToManagedProfile_LoggingTest() throws Exception {
+        sComponentName = FORWARD_TO_MANAGED_PROFILE_COMPONENT_NAME;
+
+        // Intent can be forwarded.
+        when(mIPm.canForwardTo(
+                any(Intent.class), nullable(String.class), anyInt(), anyInt())).thenReturn(true);
+
+        // Managed profile exists.
+        List<UserInfo> profiles = new ArrayList<>();
+        profiles.add(CURRENT_USER_INFO);
+        profiles.add(MANAGED_PROFILE_INFO);
+        when(mUserManager.getProfiles(anyInt())).thenReturn(profiles);
+
+        Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class);
+        intent.setAction(Intent.ACTION_SEND);
+        intent.setType(TYPE_PLAIN_TEXT);
+        IntentForwarderWrapperActivity activity = mActivityRule.launchActivity(intent);
+
+        ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class);
+        verify(activity.getMetricsLogger()).write(logMakerCaptor.capture());
+        assertEquals(MetricsEvent.ACTION_SWITCH_SHARE_PROFILE,
+                logMakerCaptor.getValue().getCategory());
+        assertEquals(MetricsEvent.MANAGED_PROFILE,
+                logMakerCaptor.getValue().getSubtype());
+    }
+
+    @Test
+    public void forwardToParent_LoggingTest() throws Exception {
+        sComponentName = FORWARD_TO_PARENT_COMPONENT_NAME;
+
+        // Intent can be forwarded.
+        when(mIPm.canForwardTo(
+                any(Intent.class), nullable(String.class), anyInt(), anyInt())).thenReturn(true);
+
+        // Managed profile exists.
+        List<UserInfo> profiles = new ArrayList<>();
+        profiles.add(CURRENT_USER_INFO);
+        profiles.add(MANAGED_PROFILE_INFO);
+        when(mUserManager.getProfiles(anyInt())).thenReturn(profiles);
+
+        Intent intent = new Intent(mContext, IntentForwarderWrapperActivity.class);
+        intent.setAction(Intent.ACTION_SEND);
+        intent.setType(TYPE_PLAIN_TEXT);
+        IntentForwarderWrapperActivity activity = mActivityRule.launchActivity(intent);
+
+        ArgumentCaptor<LogMaker> logMakerCaptor = ArgumentCaptor.forClass(LogMaker.class);
+        verify(activity.getMetricsLogger()).write(logMakerCaptor.capture());
+        assertEquals(MetricsEvent.ACTION_SWITCH_SHARE_PROFILE,
+                logMakerCaptor.getValue().getCategory());
+        assertEquals(MetricsEvent.PARENT_PROFILE,
+                logMakerCaptor.getValue().getSubtype());
+    }
+
     private void setupShouldSkipDisclosureTest() throws RemoteException {
         sComponentName = FORWARD_TO_MANAGED_PROFILE_COMPONENT_NAME;
         sActivityName = "MyTestActivity";
@@ -541,6 +605,7 @@
 
         private Intent mStartActivityIntent;
         private int mUserIdActivityLaunchedIn;
+        private MetricsLogger mMetricsLogger = mock(MetricsLogger.class);
 
         @Override
         public void onCreate(@Nullable Bundle savedInstanceState) {
@@ -559,6 +624,11 @@
             mStartActivityIntent = intent;
             mUserIdActivityLaunchedIn = userId;
         }
+
+        @Override
+        protected MetricsLogger getMetricsLogger() {
+            return mMetricsLogger;
+        }
     }
 
     public class TestInjector implements IntentForwarderActivity.Injector {
diff --git a/graphics/java/android/graphics/ImageFormat.java b/graphics/java/android/graphics/ImageFormat.java
index 6264774..15d855e 100644
--- a/graphics/java/android/graphics/ImageFormat.java
+++ b/graphics/java/android/graphics/ImageFormat.java
@@ -16,7 +16,43 @@
 
 package android.graphics;
 
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 public class ImageFormat {
+     /** @hide */
+     @Retention(RetentionPolicy.SOURCE)
+     @IntDef(value = {
+             UNKNOWN,
+             RGB_565,
+             YV12,
+             Y8,
+             Y16,
+             NV16,
+             NV21,
+             YUY2,
+             JPEG,
+             DEPTH_JPEG,
+             YUV_420_888,
+             YUV_422_888,
+             YUV_444_888,
+             FLEX_RGB_888,
+             FLEX_RGBA_8888,
+             RAW_SENSOR,
+             RAW_PRIVATE,
+             RAW10,
+             RAW12,
+             DEPTH16,
+             DEPTH_POINT_CLOUD,
+             RAW_DEPTH,
+             PRIVATE,
+             HEIC
+     })
+     public @interface Format {
+     }
+
     /*
      * these constants are chosen to be binary compatible with their previous
      * location in PixelFormat.java
@@ -731,7 +767,7 @@
      * @return the number of bits per pixel of the given format or -1 if the
      *         format doesn't exist or is not supported.
      */
-    public static int getBitsPerPixel(int format) {
+    public static int getBitsPerPixel(@Format int format) {
         switch (format) {
             case RGB_565:
                 return 16;
@@ -781,7 +817,7 @@
      *
      * @hide
      */
-    public static boolean isPublicFormat(int format) {
+    public static boolean isPublicFormat(@Format int format) {
         switch (format) {
             case RGB_565:
             case NV16:
diff --git a/location/java/android/location/GnssMeasurementCorrections.java b/location/java/android/location/GnssMeasurementCorrections.java
index 3ce48b4..9d3211d 100644
--- a/location/java/android/location/GnssMeasurementCorrections.java
+++ b/location/java/android/location/GnssMeasurementCorrections.java
@@ -124,7 +124,7 @@
      * Gets a set of {@link GnssSingleSatCorrection} each containing measurement corrections for a
      * satellite in view
      */
-    public @Nullable List<GnssSingleSatCorrection> getSingleSatCorrectionList() {
+    public @Nullable List<GnssSingleSatCorrection> getSingleSatelliteCorrectionList() {
         return mSingleSatCorrectionList;
     }
 
@@ -137,7 +137,7 @@
             new Creator<GnssMeasurementCorrections>() {
                 @Override
                 public GnssMeasurementCorrections createFromParcel(Parcel parcel) {
-                    GnssMeasurementCorrections.Builder gnssMeasurementCorrectons =
+                    final GnssMeasurementCorrections.Builder gnssMeasurementCorrectons =
                             new Builder()
                                     .setLatitudeDegrees(parcel.readDouble())
                                     .setLongitudeDegrees(parcel.readDouble())
@@ -147,7 +147,7 @@
                                     .setToaGpsNanosecondsOfWeek(parcel.readLong());
                     List<GnssSingleSatCorrection> singleSatCorrectionList = new ArrayList<>();
                     parcel.readTypedList(singleSatCorrectionList, GnssSingleSatCorrection.CREATOR);
-                    gnssMeasurementCorrectons.setSingleSatCorrectionList(
+                    gnssMeasurementCorrectons.setSingleSatelliteCorrectionList(
                             singleSatCorrectionList.isEmpty() ? null : singleSatCorrectionList);
                     return gnssMeasurementCorrectons.build();
                 }
@@ -188,7 +188,7 @@
     }
 
     /** Builder for {@link GnssMeasurementCorrections} */
-    public static class Builder {
+    public static final class Builder {
         /**
          * For documentation of below fields, see corresponding fields in {@link
          * GnssMeasurementCorrections}.
@@ -253,7 +253,7 @@
          * Sets a the list of {@link GnssSingleSatCorrection} containing measurement corrections for
          * a satellite in view
          */
-        public Builder setSingleSatCorrectionList(
+        public Builder setSingleSatelliteCorrectionList(
                 @Nullable List<GnssSingleSatCorrection> singleSatCorrectionList) {
             if (singleSatCorrectionList == null) {
                 mSingleSatCorrectionList = null;
diff --git a/location/java/android/location/GnssReflectingPlane.java b/location/java/android/location/GnssReflectingPlane.java
index 64b3752..9a106a7 100644
--- a/location/java/android/location/GnssReflectingPlane.java
+++ b/location/java/android/location/GnssReflectingPlane.java
@@ -116,7 +116,7 @@
     }
 
     /** Builder for {@link GnssReflectingPlane} */
-    public static class Builder {
+    public static final class Builder {
         /** For documentation, see corresponding fields in {@link GnssReflectingPlane}. */
         private double mLatitudeDegrees;
 
diff --git a/location/java/android/location/GnssSingleSatCorrection.java b/location/java/android/location/GnssSingleSatCorrection.java
index 4d5303f..f719e1a 100644
--- a/location/java/android/location/GnssSingleSatCorrection.java
+++ b/location/java/android/location/GnssSingleSatCorrection.java
@@ -60,6 +60,7 @@
     private int mSingleSatCorrectionFlags;
 
     /** Defines the constellation of the given satellite as defined in {@link GnssStatus}. */
+    @GnssStatus.ConstellationType
     private int mConstellationType;
 
     /**
@@ -115,7 +116,7 @@
     }
 
     /** Gets a bitmask of fields present in this object */
-    public int getSingleSatCorrectionFlags() {
+    public int getSingleSatelliteCorrectionFlags() {
         return mSingleSatCorrectionFlags;
     }
 
@@ -136,7 +137,7 @@
      * <p>Interpretation depends on {@link #getConstellationType()}. See {@link
      * GnssStatus#getSvid(int)}.
      */
-    public int getSatId() {
+    public int getSatelliteId() {
         return mSatId;
     }
 
@@ -162,7 +163,7 @@
      * location.
      */
     @FloatRange(from = 0f, to = 1f)
-    public float getProbSatIsLos() {
+    public float getProbabilityLineOfSight() {
         return mProbSatIsLos;
     }
 
@@ -189,8 +190,8 @@
         return mReflectingPlane;
     }
 
-    /** Returns {@code true} if {@link #getProbSatIsLos()} is valid. */
-    public boolean hasSatelliteLineOfSight() {
+    /** Returns {@code true} if {@link #getProbabilityLineOfSight()} is valid. */
+    public boolean hasValidSatelliteLineOfSight() {
         return (mSingleSatCorrectionFlags & HAS_PROB_SAT_IS_LOS_MASK) != 0;
     }
 
@@ -220,11 +221,11 @@
                 public GnssSingleSatCorrection createFromParcel(Parcel parcel) {
                     GnssSingleSatCorrection singleSatCorrection =
                             new Builder()
-                                    .setSingleSatCorrectionFlags(parcel.readInt())
+                                    .setSingleSatelliteCorrectionFlags(parcel.readInt())
                                     .setConstellationType(parcel.readInt())
-                                    .setSatId(parcel.readInt())
+                                    .setSatelliteId(parcel.readInt())
                                     .setCarrierFrequencyHz(parcel.readFloat())
-                                    .setProbSatIsLos(parcel.readFloat())
+                                    .setProbabilityLineOfSight(parcel.readFloat())
                                     .setExcessPathLengthMeters(parcel.readFloat())
                                     .setExcessPathLengthUncertaintyMeters(parcel.readFloat())
                                     .setReflectingPlane(
@@ -272,7 +273,7 @@
     }
 
     /** Builder for {@link GnssSingleSatCorrection} */
-    public static class Builder {
+    public static final class Builder {
 
         /**
          * For documentation of below fields, see corresponding fields in {@link
@@ -289,19 +290,19 @@
         private GnssReflectingPlane mReflectingPlane;
 
         /** Sets a bitmask of fields present in this object */
-        public Builder setSingleSatCorrectionFlags(int singleSatCorrectionFlags) {
+        public Builder setSingleSatelliteCorrectionFlags(int singleSatCorrectionFlags) {
             mSingleSatCorrectionFlags = singleSatCorrectionFlags;
             return this;
         }
 
         /** Sets the constellation type. */
-        public Builder setConstellationType(int constellationType) {
+        public Builder setConstellationType(@GnssStatus.ConstellationType int constellationType) {
             mConstellationType = constellationType;
             return this;
         }
 
-        /** Sets the Satellite ID. */
-        public Builder setSatId(int satId) {
+        /** Sets the Satellite ID defined in the ICD of the given constellation. */
+        public Builder setSatelliteId(int satId) {
             mSatId = satId;
             return this;
         }
@@ -316,7 +317,8 @@
          * Sets the line-of-sight probability of the satellite at the given location in the range
          * between 0 and 1.
          */
-        public Builder setProbSatIsLos(@FloatRange(from = 0f, to = 1f) float probSatIsLos) {
+        public Builder setProbabilityLineOfSight(
+                @FloatRange(from = 0f, to = 1f) float probSatIsLos) {
             Preconditions.checkArgumentInRange(
                     probSatIsLos, 0, 1, "probSatIsLos should be between 0 and 1.");
             mProbSatIsLos = probSatIsLos;
diff --git a/location/tests/locationtests/src/android/location/GnssMeasurementCorrectionsTest.java b/location/tests/locationtests/src/android/location/GnssMeasurementCorrectionsTest.java
index 8f46e84..ae5ca40 100644
--- a/location/tests/locationtests/src/android/location/GnssMeasurementCorrectionsTest.java
+++ b/location/tests/locationtests/src/android/location/GnssMeasurementCorrectionsTest.java
@@ -53,15 +53,15 @@
         assertEquals(604000000000000L, measurementCorrections.getToaGpsNanosecondsOfWeek());
 
         GnssSingleSatCorrection singleSatCorrection =
-                measurementCorrections.getSingleSatCorrectionList().get(0);
+                measurementCorrections.getSingleSatelliteCorrectionList().get(0);
         GnssSingleSatCorrectionsTest.verifyTestValues(singleSatCorrection);
 
-        singleSatCorrection = measurementCorrections.getSingleSatCorrectionList().get(1);
-        assertEquals(15, singleSatCorrection.getSingleSatCorrectionFlags());
+        singleSatCorrection = measurementCorrections.getSingleSatelliteCorrectionList().get(1);
+        assertEquals(15, singleSatCorrection.getSingleSatelliteCorrectionFlags());
         assertEquals(GnssStatus.CONSTELLATION_GPS, singleSatCorrection.getConstellationType());
-        assertEquals(11, singleSatCorrection.getSatId());
+        assertEquals(11, singleSatCorrection.getSatelliteId());
         assertEquals(1575430000f, singleSatCorrection.getCarrierFrequencyHz());
-        assertEquals(0.9f, singleSatCorrection.getProbSatIsLos());
+        assertEquals(0.9f, singleSatCorrection.getProbabilityLineOfSight());
         assertEquals(50.0f, singleSatCorrection.getExcessPathLengthMeters());
         assertEquals(55.0f, singleSatCorrection.getExcessPathLengthUncertaintyMeters());
         GnssReflectingPlane reflectingPlane = singleSatCorrection.getReflectingPlane();
@@ -82,17 +82,17 @@
         List<GnssSingleSatCorrection> singleSatCorrectionList = new ArrayList<>();
         singleSatCorrectionList.add(GnssSingleSatCorrectionsTest.generateTestSingleSatCorrection());
         singleSatCorrectionList.add(generateTestSingleSatCorrection());
-        measurementCorrections.setSingleSatCorrectionList(singleSatCorrectionList);
+        measurementCorrections.setSingleSatelliteCorrectionList(singleSatCorrectionList);
     }
 
     private static GnssSingleSatCorrection generateTestSingleSatCorrection() {
         GnssSingleSatCorrection.Builder singleSatCorrection = new GnssSingleSatCorrection.Builder();
         singleSatCorrection
-                .setSingleSatCorrectionFlags(8)
+                .setSingleSatelliteCorrectionFlags(8)
                 .setConstellationType(GnssStatus.CONSTELLATION_GPS)
-                .setSatId(11)
+                .setSatelliteId(11)
                 .setCarrierFrequencyHz(1575430000f)
-                .setProbSatIsLos(0.9f)
+                .setProbabilityLineOfSight(0.9f)
                 .setExcessPathLengthMeters(50.0f)
                 .setExcessPathLengthUncertaintyMeters(55.0f)
                 .setReflectingPlane(generateTestReflectingPlane());
diff --git a/location/tests/locationtests/src/android/location/GnssSingleSatCorrectionsTest.java b/location/tests/locationtests/src/android/location/GnssSingleSatCorrectionsTest.java
index f358806..60f33f0 100644
--- a/location/tests/locationtests/src/android/location/GnssSingleSatCorrectionsTest.java
+++ b/location/tests/locationtests/src/android/location/GnssSingleSatCorrectionsTest.java
@@ -40,11 +40,11 @@
     }
 
     public static void verifyTestValues(GnssSingleSatCorrection singleSatCorrection) {
-        assertEquals(15, singleSatCorrection.getSingleSatCorrectionFlags());
+        assertEquals(15, singleSatCorrection.getSingleSatelliteCorrectionFlags());
         assertEquals(GnssStatus.CONSTELLATION_GALILEO, singleSatCorrection.getConstellationType());
-        assertEquals(12, singleSatCorrection.getSatId());
+        assertEquals(12, singleSatCorrection.getSatelliteId());
         assertEquals(1575420000f, singleSatCorrection.getCarrierFrequencyHz());
-        assertEquals(0.1f, singleSatCorrection.getProbSatIsLos());
+        assertEquals(0.1f, singleSatCorrection.getProbabilityLineOfSight());
         assertEquals(10.0f, singleSatCorrection.getExcessPathLengthMeters());
         assertEquals(5.0f, singleSatCorrection.getExcessPathLengthUncertaintyMeters());
         GnssReflectingPlane reflectingPlane = singleSatCorrection.getReflectingPlane();
@@ -52,27 +52,27 @@
     }
 
     private static void setTestValues(GnssSingleSatCorrection.Builder singleSatCorrection) {
-        GnssSingleSatCorrection singleSatCorr = generateTestSingleSatCorrection();
+        GnssSingleSatCorrection singleSatCor = generateTestSingleSatCorrection();
         singleSatCorrection
-                .setSingleSatCorrectionFlags(singleSatCorr.getSingleSatCorrectionFlags())
-                .setConstellationType(singleSatCorr.getConstellationType())
-                .setSatId(singleSatCorr.getSatId())
-                .setCarrierFrequencyHz(singleSatCorr.getCarrierFrequencyHz())
-                .setProbSatIsLos(singleSatCorr.getProbSatIsLos())
-                .setExcessPathLengthMeters(singleSatCorr.getExcessPathLengthMeters())
+                .setSingleSatelliteCorrectionFlags(singleSatCor.getSingleSatelliteCorrectionFlags())
+                .setConstellationType(singleSatCor.getConstellationType())
+                .setSatelliteId(singleSatCor.getSatelliteId())
+                .setCarrierFrequencyHz(singleSatCor.getCarrierFrequencyHz())
+                .setProbabilityLineOfSight(singleSatCor.getProbabilityLineOfSight())
+                .setExcessPathLengthMeters(singleSatCor.getExcessPathLengthMeters())
                 .setExcessPathLengthUncertaintyMeters(
-                        singleSatCorr.getExcessPathLengthUncertaintyMeters())
-                .setReflectingPlane(singleSatCorr.getReflectingPlane());
+                        singleSatCor.getExcessPathLengthUncertaintyMeters())
+                .setReflectingPlane(singleSatCor.getReflectingPlane());
     }
 
     public static GnssSingleSatCorrection generateTestSingleSatCorrection() {
         GnssSingleSatCorrection.Builder singleSatCorrection =
                 new GnssSingleSatCorrection.Builder()
-                        .setSingleSatCorrectionFlags(15)
+                        .setSingleSatelliteCorrectionFlags(15)
                         .setConstellationType(GnssStatus.CONSTELLATION_GALILEO)
-                        .setSatId(12)
+                        .setSatelliteId(12)
                         .setCarrierFrequencyHz(1575420000f)
-                        .setProbSatIsLos(0.1f)
+                        .setProbabilityLineOfSight(0.1f)
                         .setExcessPathLengthMeters(10.0f)
                         .setExcessPathLengthUncertaintyMeters(5.0f)
                         .setReflectingPlane(GnssReflectingPlaneTest.generateTestReflectingPlane());
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 10accf2..4f2de23 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -401,7 +401,7 @@
         int initResult = native_setup( new WeakReference<AudioRecord>(this),
                 mAudioAttributes, sampleRate, mChannelMask, mChannelIndexMask,
                 mAudioFormat, mNativeBufferSizeInBytes,
-                session, ActivityThread.currentOpPackageName(), 0 /*nativeRecordInJavaObj*/);
+                session, getCurrentOpPackageName(), 0 /*nativeRecordInJavaObj*/);
         if (initResult != SUCCESS) {
             loge("Error code "+initResult+" when initializing native AudioRecord object.");
             return; // with mState == STATE_UNINITIALIZED
@@ -413,6 +413,15 @@
         mState = STATE_INITIALIZED;
     }
 
+    private String getCurrentOpPackageName() {
+        String opPackageName = ActivityThread.currentOpPackageName();
+        if (opPackageName != null) {
+            return opPackageName;
+        }
+        // Command line utility
+        return "uid:" + Binder.getCallingUid();
+    }
+
     /**
      * A constructor which explicitly connects a Native (C++) AudioRecord. For use by
      * the AudioRecordRoutingProxy subclass.
diff --git a/media/java/android/media/ImageReader.java b/media/java/android/media/ImageReader.java
index 6116429..ba87f2b 100644
--- a/media/java/android/media/ImageReader.java
+++ b/media/java/android/media/ImageReader.java
@@ -16,8 +16,12 @@
 
 package android.media;
 
+import android.annotation.IntRange;
+import android.annotation.NonNull;
 import android.graphics.ImageFormat;
+import android.graphics.ImageFormat.Format;
 import android.hardware.HardwareBuffer;
+import android.hardware.HardwareBuffer.Usage;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -120,7 +124,11 @@
      *            Must be greater than 0.
      * @see Image
      */
-    public static ImageReader newInstance(int width, int height, int format, int maxImages) {
+    public static @NonNull ImageReader newInstance(
+            @IntRange(from = 1) int width,
+            @IntRange(from = 1) int height,
+            @Format             int format,
+            @IntRange(from = 1) int maxImages) {
         // If the format is private don't default to USAGE_CPU_READ_OFTEN since it may not
         // work, and is inscrutable anyway
         return new ImageReader(width, height, format, maxImages,
@@ -210,8 +218,12 @@
      * @see Image
      * @see HardwareBuffer
      */
-    public static ImageReader newInstance(int width, int height, int format, int maxImages,
-            long usage) {
+    public static @NonNull ImageReader newInstance(
+            @IntRange(from = 1) int width,
+            @IntRange(from = 1) int height,
+            @Format             int format,
+            @IntRange(from = 1) int maxImages,
+            @Usage              long usage) {
         // TODO: Check this - can't do it just yet because format support is different
         // Unify formats! The only reliable way to validate usage is to just try it and see.
 
diff --git a/media/java/android/media/ImageWriter.java b/media/java/android/media/ImageWriter.java
index dd09afc..f813d1b 100644
--- a/media/java/android/media/ImageWriter.java
+++ b/media/java/android/media/ImageWriter.java
@@ -16,7 +16,10 @@
 
 package android.media;
 
+import android.annotation.IntRange;
+import android.annotation.NonNull;
 import android.graphics.ImageFormat;
+import android.graphics.ImageFormat.Format;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.hardware.camera2.utils.SurfaceUtils;
@@ -124,7 +127,8 @@
      *            {@link #dequeueInputImage()}.
      * @return a new ImageWriter instance.
      */
-    public static ImageWriter newInstance(Surface surface, int maxImages) {
+    public static @NonNull ImageWriter newInstance(@NonNull Surface surface,
+            @IntRange(from = 1) int maxImages) {
         return new ImageWriter(surface, maxImages, ImageFormat.UNKNOWN);
     }
 
@@ -169,7 +173,8 @@
      *
      * @return a new ImageWriter instance.
      */
-    public static ImageWriter newInstance(Surface surface, int maxImages, int format) {
+    public static @NonNull ImageWriter newInstance(@NonNull Surface surface,
+            @IntRange(from = 1) int maxImages, @Format int format) {
         if (!ImageFormat.isPublicFormat(format) && !PixelFormat.isPublicFormat(format)) {
             throw new IllegalArgumentException("Invalid format is specified: " + format);
         }
diff --git a/media/java/android/media/MediaCas.java b/media/java/android/media/MediaCas.java
index cf5711d..a9e33fd 100644
--- a/media/java/android/media/MediaCas.java
+++ b/media/java/android/media/MediaCas.java
@@ -19,9 +19,9 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.hardware.cas.V1_0.HidlCasPluginDescriptor;
-import android.hardware.cas.V1_1.ICas;
+import android.hardware.cas.V1_0.ICas;
+import android.hardware.cas.V1_0.IMediaCasService;
 import android.hardware.cas.V1_1.ICasListener;
-import android.hardware.cas.V1_1.IMediaCasService;
 import android.media.MediaCasException.*;
 import android.os.Bundle;
 import android.os.Handler;
@@ -99,23 +99,35 @@
 public final class MediaCas implements AutoCloseable {
     private static final String TAG = "MediaCas";
     private ICas mICas;
+    private android.hardware.cas.V1_1.ICas mICasV11;
     private EventListener mListener;
     private HandlerThread mHandlerThread;
     private EventHandler mEventHandler;
 
-    private static final Singleton<IMediaCasService> gDefault =
-            new Singleton<IMediaCasService>() {
+    private static final Singleton<IMediaCasService> sService = new Singleton<IMediaCasService>() {
         @Override
         protected IMediaCasService create() {
             try {
-                return IMediaCasService.getService(true /*wait*/);
-            } catch (RemoteException e) {}
+                Log.d(TAG, "Tried to get cas@1.1 service");
+                android.hardware.cas.V1_1.IMediaCasService serviceV11 =
+                        android.hardware.cas.V1_1.IMediaCasService.getService(true /*wait*/);
+                if (serviceV11 != null) {
+                    return serviceV11;
+                }
+            } catch (Exception eV1_1) {
+                try {
+                    Log.d(TAG, "Tried to get cas@1.0 service");
+                    return IMediaCasService.getService(true /*wait*/);
+                } catch (Exception eV1_0) {
+                    Log.d(TAG, "Failed to get cas@1.0 service");
+                }
+            }
             return null;
         }
     };
 
     static IMediaCasService getService() {
-        return gDefault.get();
+        return sService.get();
     }
 
     private void validateInternalStates() {
@@ -126,11 +138,12 @@
 
     private void cleanupAndRethrowIllegalState() {
         mICas = null;
+        mICasV11 = null;
         throw new IllegalStateException();
     }
 
-    private class EventHandler extends Handler
-    {
+    private class EventHandler extends Handler {
+
         private static final int MSG_CAS_EVENT = 0;
         private static final int MSG_CAS_SESSION_EVENT = 1;
         private static final String SESSION_KEY = "sessionId";
@@ -164,7 +177,7 @@
         }
         @Override
         public void onSessionEvent(@NonNull ArrayList<Byte> sessionId,
-                        int event, int arg, @Nullable ArrayList<Byte> data)
+                int event, int arg, @Nullable ArrayList<Byte> data)
                 throws RemoteException {
             Message msg = mEventHandler.obtainMessage();
             msg.what = EventHandler.MSG_CAS_SESSION_EVENT;
@@ -177,7 +190,6 @@
             mEventHandler.sendMessage(msg);
         }
     };
-
     /**
      * Describe a CAS plugin with its CA_system_ID and string name.
      *
@@ -338,9 +350,14 @@
                 throws MediaCasException {
             validateInternalStates();
 
+            if (mICasV11 == null) {
+                Log.d(TAG, "Send Session Event isn't supported by cas@1.0 interface");
+                throw new UnsupportedCasException("Send Session Event is not supported");
+            }
+
             try {
                 MediaCasException.throwExceptionIfNeeded(
-                        mICas.sendSessionEvent(mSessionId, event, arg, toByteArray(data)));
+                        mICasV11.sendSessionEvent(mSessionId, event, arg, toByteArray(data)));
             } catch (RemoteException e) {
                 cleanupAndRethrowIllegalState();
             }
@@ -427,7 +444,16 @@
      */
     public MediaCas(int CA_system_id) throws UnsupportedCasException {
         try {
-            mICas = getService().createPluginExt(CA_system_id, mBinder);
+            IMediaCasService service = getService();
+            android.hardware.cas.V1_1.IMediaCasService serviceV11 =
+                    android.hardware.cas.V1_1.IMediaCasService.castFrom(service);
+            if (serviceV11 == null) {
+                Log.d(TAG, "Used cas@1_0 interface to create plugin");
+                mICas = service.createPlugin(CA_system_id, mBinder);
+            } else {
+                Log.d(TAG, "Used cas@1.1 interface to create plugin");
+                mICas = mICasV11 = serviceV11.createPluginExt(CA_system_id, mBinder);
+            }
         } catch(Exception e) {
             Log.e(TAG, "Failed to create plugin: " + e);
             mICas = null;
@@ -528,7 +554,7 @@
         }
     }
 
-    private class OpenSessionCallback implements ICas.openSessionCallback {
+    private class OpenSessionCallback implements android.hardware.cas.V1_1.ICas.openSessionCallback{
         public Session mSession;
         public int mStatus;
         @Override
diff --git a/media/java/android/media/audiopolicy/AudioPolicy.java b/media/java/android/media/audiopolicy/AudioPolicy.java
index 65f3294..49867ab 100644
--- a/media/java/android/media/audiopolicy/AudioPolicy.java
+++ b/media/java/android/media/audiopolicy/AudioPolicy.java
@@ -19,6 +19,7 @@
 import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.SystemApi;
+import android.app.ActivityManager;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.media.AudioAttributes;
@@ -417,16 +418,12 @@
                 Log.e(TAG, "Cannot use unregistered AudioPolicy");
                 return false;
             }
-            if (mContext == null) {
-                Log.e(TAG, "Cannot use AudioPolicy without context");
-                return false;
-            }
             if (mRegistrationId == null) {
                 Log.e(TAG, "Cannot use unregistered AudioPolicy");
                 return false;
             }
         }
-        if (!(PackageManager.PERMISSION_GRANTED == mContext.checkCallingOrSelfPermission(
+        if (!(PackageManager.PERMISSION_GRANTED == checkCallingOrSelfPermission(
                         android.Manifest.permission.MODIFY_AUDIO_ROUTING))) {
             Slog.w(TAG, "Cannot use AudioPolicy for pid " + Binder.getCallingPid() + " / uid "
                     + Binder.getCallingUid() + ", needs MODIFY_AUDIO_ROUTING");
@@ -435,6 +432,23 @@
         return true;
     }
 
+    /**
+     * Returns {@link PackageManager#PERMISSION_GRANTED} if the caller has the given permission.
+     */
+    private @PackageManager.PermissionResult int checkCallingOrSelfPermission(String permission) {
+        if (mContext != null) {
+            return mContext.checkCallingOrSelfPermission(permission);
+        }
+        Slog.v(TAG, "Null context, checking permission via ActivityManager");
+        int pid = Binder.getCallingPid();
+        int uid = Binder.getCallingUid();
+        try {
+            return ActivityManager.getService().checkPermission(permission, pid, uid);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
     private void checkMixReadyToUse(AudioMix mix, boolean forTrack)
             throws IllegalArgumentException{
         if (mix == null) {
diff --git a/media/java/android/media/audiopolicy/AudioPolicyConfig.java b/media/java/android/media/audiopolicy/AudioPolicyConfig.java
index f725cac..a56fd31 100644
--- a/media/java/android/media/audiopolicy/AudioPolicyConfig.java
+++ b/media/java/android/media/audiopolicy/AudioPolicyConfig.java
@@ -18,8 +18,6 @@
 
 import android.annotation.NonNull;
 import android.media.AudioFormat;
-import android.media.AudioManager;
-import android.media.AudioPatch;
 import android.media.audiopolicy.AudioMixingRule.AudioMixMatchCriterion;
 import android.os.Parcel;
 import android.os.Parcelable;
diff --git a/media/java/android/media/session/ControllerLink.java b/media/java/android/media/session/ControllerLink.java
index 40c7166..5828fbd 100644
--- a/media/java/android/media/session/ControllerLink.java
+++ b/media/java/android/media/session/ControllerLink.java
@@ -158,6 +158,18 @@
     }
 
     /**
+     * Gets the session info of the connected session.
+     */
+    @Nullable
+    Bundle getSessionInfo() {
+        try {
+            return mISessionController.getSessionInfo();
+        } catch (RemoteException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
      * Gets the {@link PendingIntent} for launching UI of the connected session.
      */
     @Nullable
@@ -666,6 +678,12 @@
             return null;
         }
 
+        /** Stub method for ISessionController.getSessionInfo */
+        @Nullable
+        public Bundle getSessionInfo() {
+            return null;
+        }
+
         /** Stub method for ISessionController.getLaunchPendingIntent */
         @Nullable
         public PendingIntent getLaunchPendingIntent() {
@@ -856,6 +874,11 @@
         }
 
         @Override
+        public Bundle getSessionInfo() {
+            return mControllerStub.getSessionInfo();
+        }
+
+        @Override
         public PendingIntent getLaunchPendingIntent() {
             return mControllerStub.getLaunchPendingIntent();
         }
diff --git a/media/java/android/media/session/ISessionController.aidl b/media/java/android/media/session/ISessionController.aidl
index 3e7b4fb..298085f 100644
--- a/media/java/android/media/session/ISessionController.aidl
+++ b/media/java/android/media/session/ISessionController.aidl
@@ -44,6 +44,7 @@
     void unregisterCallback(in ControllerCallbackLink cb);
     String getPackageName();
     String getTag();
+    Bundle getSessionInfo();
     PendingIntent getLaunchPendingIntent();
     long getFlags();
     MediaController.PlaybackInfo getVolumeAttributes();
diff --git a/media/java/android/media/session/ISessionManager.aidl b/media/java/android/media/session/ISessionManager.aidl
index 8143bfa..e85461f 100644
--- a/media/java/android/media/session/ISessionManager.aidl
+++ b/media/java/android/media/session/ISessionManager.aidl
@@ -35,7 +35,7 @@
  */
 interface ISessionManager {
     SessionLink createSession(String packageName, in SessionCallbackLink sessionCb, String tag,
-            int userId);
+            in Bundle sessionInfo, int userId);
     void notifySession2Created(in Session2Token sessionToken);
     List<MediaSession.Token> getSessions(in ComponentName compName, int userId);
     List<Session2Token> getSession2Tokens(int userId);
diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java
index 9e4199c..fb21f69 100644
--- a/media/java/android/media/session/MediaController.java
+++ b/media/java/android/media/session/MediaController.java
@@ -79,6 +79,7 @@
     private boolean mCbRegistered = false;
     private String mPackageName;
     private String mTag;
+    private Bundle mSessionInfo;
 
     private final TransportControls mTransportControls;
 
@@ -410,6 +411,23 @@
     }
 
     /**
+     * Gets the additional session information which was set when the session was created.
+     *
+     * @return The additional session information
+     */
+    @Nullable
+    public Bundle getSessionInfo() {
+        if (mSessionInfo == null) {
+            try {
+                mSessionInfo = mSessionBinder.getSessionInfo();
+            } catch (RuntimeException e) {
+                Log.d(TAG, "Dead object in getSessionInfo.", e);
+            }
+        }
+        return mSessionInfo;
+    }
+
+    /**
      * Get the session's tag for debugging purposes.
      *
      * @return The session's tag.
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index 8ab893b..9fdefa6 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -132,6 +132,27 @@
      * @param tag A short name for debugging purposes.
      */
     public MediaSession(@NonNull Context context, @NonNull String tag) {
+        this(context, tag, null);
+    }
+
+    /**
+     * Creates a new session. The session will automatically be registered with
+     * the system but will not be published until {@link #setActive(boolean)
+     * setActive(true)} is called. You must call {@link #release()} when
+     * finished with the session.
+     * <p>
+     * The {@code sessionInfo} can include additional unchanging information about this session.
+     * For example, it can include the version of the application, or the list of the custom
+     * commands that this session supports.
+     *
+     * @param context The context to use to create the session.
+     * @param tag A short name for debugging purposes.
+     * @param sessionInfo A bundle for additional information about this session.
+     *                    Controllers can get this information by calling
+     *                    {@link MediaController#getSessionInfo()}.
+     */
+    public MediaSession(@NonNull Context context, @NonNull String tag,
+            @Nullable Bundle sessionInfo) {
         if (context == null) {
             throw new IllegalArgumentException("context cannot be null.");
         }
@@ -142,7 +163,7 @@
                 .getSystemService(Context.MEDIA_SESSION_SERVICE);
         try {
             SessionCallbackLink cbLink = new SessionCallbackLink(context);
-            SessionLink sessionLink = manager.createSession(cbLink, tag);
+            SessionLink sessionLink = manager.createSession(cbLink, tag, sessionInfo);
             mImpl = new MediaSessionEngine(context, sessionLink, cbLink);
             mMaxBitmapSize = context.getResources().getDimensionPixelSize(
                     android.R.dimen.config_mediaMetadataBitmapMaxSize);
diff --git a/media/java/android/media/session/MediaSessionManager.java b/media/java/android/media/session/MediaSessionManager.java
index 46f6c71..fde4f88 100644
--- a/media/java/android/media/session/MediaSessionManager.java
+++ b/media/java/android/media/session/MediaSessionManager.java
@@ -28,6 +28,7 @@
 import android.media.IRemoteVolumeController;
 import android.media.MediaSession2;
 import android.media.Session2Token;
+import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.RemoteException;
@@ -101,13 +102,15 @@
      * Create a new session in the system and get the binder for it.
      *
      * @param tag A short name for debugging purposes.
+     * @param sessionInfo A bundle for additional information about this session.
      * @return The binder object from the system
      * @hide
      */
     @NonNull
-    public SessionLink createSession(@NonNull SessionCallbackLink cbStub, @NonNull String tag) {
+    public SessionLink createSession(@NonNull SessionCallbackLink cbStub, @NonNull String tag,
+            @Nullable Bundle sessionInfo) {
         try {
-            return mService.createSession(mContext.getPackageName(), cbStub, tag,
+            return mService.createSession(mContext.getPackageName(), cbStub, tag, sessionInfo,
                     UserHandle.myUserId());
         } catch (RemoteException e) {
             throw new RuntimeException(e);
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index f865563..68f1e6f 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -136,8 +136,7 @@
     <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string>
     <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"আঁতৰোৱা এপ্‌সমূহ"</string>
     <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"আঁতৰোৱা এপ্‌ আৰু ব্যৱহাৰকাৰীসমূহ"</string>
-    <!-- no translation found for data_usage_ota (5377889154805560860) -->
-    <skip />
+    <string name="data_usage_ota" msgid="5377889154805560860">"ছিষ্টেম আপডে’ট"</string>
     <string name="tether_settings_title_usb" msgid="6688416425801386511">"ইউএছবি টেডাৰিং"</string>
     <string name="tether_settings_title_wifi" msgid="3277144155960302049">"প\'ৰ্টেবল হটস্পট"</string>
     <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"ব্লুটুথ টেডাৰিং"</string>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index ef8dd3d..4f29131 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -136,8 +136,7 @@
     <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string>
     <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"সরানো অ্যাপ্লিকেশানগুলি"</string>
     <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"সরানো অ্যাপ্লিকেশানগুলি এবং ব্যবহারকারীগণ"</string>
-    <!-- no translation found for data_usage_ota (5377889154805560860) -->
-    <skip />
+    <string name="data_usage_ota" msgid="5377889154805560860">"সিস্টেম আপডেট"</string>
     <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB টিথারিং"</string>
     <string name="tether_settings_title_wifi" msgid="3277144155960302049">"পোর্টেবল হটস্পট"</string>
     <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"ব্লুটুথ টিথারিং"</string>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index 97b9036..36e04bb 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -136,8 +136,7 @@
     <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string>
     <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"દૂર કરેલી ઍપ્લિકેશનો"</string>
     <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"દૂર કરેલી ઍપ્લિકેશનો અને વપરાશકર્તાઓ"</string>
-    <!-- no translation found for data_usage_ota (5377889154805560860) -->
-    <skip />
+    <string name="data_usage_ota" msgid="5377889154805560860">"સિસ્ટમ અપડેટ"</string>
     <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB ટિથરિંગ"</string>
     <string name="tether_settings_title_wifi" msgid="3277144155960302049">"પોર્ટેબલ હૉટસ્પૉટ"</string>
     <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"બ્લૂટૂથ ટિથરિંગ"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index 6e37c9a..89d6361 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -136,8 +136,7 @@
     <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string>
     <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"אפליקציות שהוסרו"</string>
     <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"אפליקציות ומשתמשים שהוסרו"</string>
-    <!-- no translation found for data_usage_ota (5377889154805560860) -->
-    <skip />
+    <string name="data_usage_ota" msgid="5377889154805560860">"עדכוני מערכת"</string>
     <string name="tether_settings_title_usb" msgid="6688416425801386511">"‏שיתוף אינטרנט דרך USB"</string>
     <string name="tether_settings_title_wifi" msgid="3277144155960302049">"נקודה לשיתוף אינטרנט"</string>
     <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"‏שיתוף אינטרנט דרך Bluetooth"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index 41b0fbd..1e9a0d5 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -136,8 +136,7 @@
     <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string>
     <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"ತೆಗೆದುಹಾಕಲಾದ ಅಪ್ಲಿಕೇಶನ್‌ಗಳು"</string>
     <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"ಅಪ್ಲಿಕೇಶನ್‌ಗಳು ಮತ್ತು ಬಳಕೆದಾರರನ್ನು ತೆಗೆದುಹಾಕಲಾಗಿದೆ"</string>
-    <!-- no translation found for data_usage_ota (5377889154805560860) -->
-    <skip />
+    <string name="data_usage_ota" msgid="5377889154805560860">"ಸಿಸ್ಟಂ ಅಪ್‌ಡೇಟ್‌ಗಳು"</string>
     <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB ಟೆಥರಿಂಗ್"</string>
     <string name="tether_settings_title_wifi" msgid="3277144155960302049">"ಪೋರ್ಟಬಲ್ ಹಾಟ್‌ಸ್ಪಾಟ್"</string>
     <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"ಬ್ಲೂಟೂತ್‌‌ ಟೆಥರಿಂಗ್‌"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index 0292cab..ae97fb2 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -136,8 +136,7 @@
     <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string>
     <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"നീക്കംചെയ്‌ത അപ്ലിക്കേഷനുകൾ"</string>
     <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"നീക്കംചെയ്‌ത അപ്ലിക്കേഷനുകളും ഉപയോക്താക്കളും"</string>
-    <!-- no translation found for data_usage_ota (5377889154805560860) -->
-    <skip />
+    <string name="data_usage_ota" msgid="5377889154805560860">"സിസ്‌റ്റം അപ്‌ഡേറ്റുകൾ"</string>
     <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB ടെതറിംഗ്"</string>
     <string name="tether_settings_title_wifi" msgid="3277144155960302049">"പോർട്ടബിൾ ഹോട്ട്സ്‌പോട്ട്"</string>
     <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"ബ്ലൂടൂത്ത് ടെതറിംഗ്"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index 0c2f0ee..88de8f4 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -136,8 +136,7 @@
     <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string>
     <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"काढलेले अॅप्स"</string>
     <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"काढलेले अॅप्स आणि वापरकर्ते"</string>
-    <!-- no translation found for data_usage_ota (5377889154805560860) -->
-    <skip />
+    <string name="data_usage_ota" msgid="5377889154805560860">"सिस्टम अपडेट"</string>
     <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB टेदरिंग"</string>
     <string name="tether_settings_title_wifi" msgid="3277144155960302049">"पोर्टेबल हॉटस्पॉट"</string>
     <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"ब्लूटूथ टेदरिंग"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index 7daf956..ac15f1b 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -136,8 +136,7 @@
     <string name="process_kernel_label" msgid="3916858646836739323">"एन्ड्रोइड OS"</string>
     <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"हटाइएका अनुप्रयोगहरू"</string>
     <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"अनुप्रयोगहरू र प्रयोगकर्ताहरू हटाइयो।"</string>
-    <!-- no translation found for data_usage_ota (5377889154805560860) -->
-    <skip />
+    <string name="data_usage_ota" msgid="5377889154805560860">"प्रणालीसम्बन्धी अद्यावधिकहरू"</string>
     <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB टेथर गर्दै"</string>
     <string name="tether_settings_title_wifi" msgid="3277144155960302049">"पोर्टेबल हटस्पट"</string>
     <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"ब्लुटुथ टेथर गर्दै"</string>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index 54ddf84..847586e 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -136,8 +136,7 @@
     <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string>
     <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"କଢ଼ାଯାଇଥିବା ଆପ୍‌ଗୁଡ଼ିକ"</string>
     <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"ଆପ୍‌ ଏବଂ ଉପଯୋଗକର୍ତ୍ତା ବାହାର କରାଗଲା"</string>
-    <!-- no translation found for data_usage_ota (5377889154805560860) -->
-    <skip />
+    <string name="data_usage_ota" msgid="5377889154805560860">"ସିଷ୍ଟମ୍ ଅପ୍‌ଡେଟ୍"</string>
     <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB ଟିଥରିଙ୍ଗ"</string>
     <string name="tether_settings_title_wifi" msgid="3277144155960302049">"ପୋର୍ଟବଲ୍‌ ହଟସ୍ପଟ୍‌"</string>
     <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"ବ୍ଲୁଟୂଥ ଟିଥରିଙ୍ଗ"</string>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index dcf3e3c..0675b6b 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -136,8 +136,7 @@
     <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string>
     <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"ਹਟਾਏ ਗਏ ਐਪਸ"</string>
     <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"ਹਟਾਏ ਗਏ ਐਪਸ ਅਤੇ ਉਪਭੋਗਤਾ"</string>
-    <!-- no translation found for data_usage_ota (5377889154805560860) -->
-    <skip />
+    <string name="data_usage_ota" msgid="5377889154805560860">"ਸਿਸਟਮ ਅੱਪਡੇਟ"</string>
     <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB ਟੈਦਰਿੰਗ"</string>
     <string name="tether_settings_title_wifi" msgid="3277144155960302049">"ਪੋਰਟੇਬਲ ਹੌਟਸਪੌਟ"</string>
     <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"ਬਲੂਟੁੱਥ ਟੈਦਰਿੰਗ"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 71716ce..3cf43c8 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -136,8 +136,7 @@
     <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string>
     <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"அகற்றப்பட்ட பயன்பாடுகள்"</string>
     <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"அகற்றப்பட்ட பயன்பாடுகள் மற்றும் பயனர்கள்"</string>
-    <!-- no translation found for data_usage_ota (5377889154805560860) -->
-    <skip />
+    <string name="data_usage_ota" msgid="5377889154805560860">"சிஸ்டம் புதுப்பிப்புகள்"</string>
     <string name="tether_settings_title_usb" msgid="6688416425801386511">"USB டெதெரிங்"</string>
     <string name="tether_settings_title_wifi" msgid="3277144155960302049">"போர்ட்டபிள் ஹாட்ஸ்பாட்"</string>
     <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"புளூடூத் டெதெரிங்"</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index 65ed110..c223629 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -136,8 +136,7 @@
     <string name="process_kernel_label" msgid="3916858646836739323">"Android OS"</string>
     <string name="data_usage_uninstalled_apps" msgid="614263770923231598">"ہٹائی گئی ایپس"</string>
     <string name="data_usage_uninstalled_apps_users" msgid="7986294489899813194">"ہٹائی گئی ایپس اور صارفین"</string>
-    <!-- no translation found for data_usage_ota (5377889154805560860) -->
-    <skip />
+    <string name="data_usage_ota" msgid="5377889154805560860">"سسٹم اپ ڈیٹس"</string>
     <string name="tether_settings_title_usb" msgid="6688416425801386511">"‏USB ٹیدرنگ"</string>
     <string name="tether_settings_title_wifi" msgid="3277144155960302049">"پورٹیبل ہاٹ اسپاٹ"</string>
     <string name="tether_settings_title_bluetooth" msgid="355855408317564420">"بلوٹوتھ ٹیدرنگ"</string>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 81b304d..0f8fd92 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -1353,11 +1353,11 @@
                 Settings.Global.SHOW_TEMPERATURE_WARNING,
                 GlobalSettingsProto.TemperatureWarning.SHOW_TEMPERATURE_WARNING);
         dumpSetting(s, p,
+                Settings.Global.SHOW_USB_TEMPERATURE_ALARM,
+                GlobalSettingsProto.TemperatureWarning.SHOW_USB_TEMPERATURE_ALARM);
+        dumpSetting(s, p,
                 Settings.Global.WARNING_TEMPERATURE,
                 GlobalSettingsProto.TemperatureWarning.WARNING_TEMPERATURE_LEVEL);
-        dumpSetting(s, p,
-                Settings.Global.USB_ALARM_TEMPERATURE,
-                GlobalSettingsProto.TemperatureWarning.USB_ALARM_TEMPERATURE_LEVEL);
         p.end(tempWarningToken);
 
         final long tetherToken = p.start(GlobalSettingsProto.TETHER);
diff --git a/packages/SystemUI/res/layout-sw600dp/navigation_layout_rot90.xml b/packages/SystemUI/res/layout-sw600dp/navigation_layout_rot90.xml
deleted file mode 100644
index 78304fd..0000000
--- a/packages/SystemUI/res/layout-sw600dp/navigation_layout_rot90.xml
+++ /dev/null
@@ -1,44 +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.
--->
-<FrameLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:systemui="http://schemas.android.com/apk/res-auto"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent">
-
-    <FrameLayout
-        android:id="@+id/nav_buttons"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent">
-
-        <LinearLayout
-            android:id="@+id/ends_group"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:orientation="horizontal"
-            android:clipChildren="false" />
-
-        <LinearLayout
-            android:id="@+id/center_group"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent"
-            android:gravity="center"
-            android:orientation="horizontal"
-            android:clipChildren="false" />
-
-    </FrameLayout>
-
-</FrameLayout>
diff --git a/packages/SystemUI/res/layout/nav_bar_tuner_inflater.xml b/packages/SystemUI/res/layout/nav_bar_tuner_inflater.xml
index b237633..133b215 100644
--- a/packages/SystemUI/res/layout/nav_bar_tuner_inflater.xml
+++ b/packages/SystemUI/res/layout/nav_bar_tuner_inflater.xml
@@ -20,8 +20,8 @@
     android:layout_width="match_parent"
     android:layout_height="@dimen/navigation_bar_size">
 
-    <include android:id="@+id/rot0" layout="@layout/navigation_layout" />
+    <include android:id="@+id/horizontal" layout="@layout/navigation_layout" />
 
-    <include android:id="@+id/rot90" layout="@layout/navigation_layout_rot90" />
+    <include android:id="@+id/vertical" layout="@layout/navigation_layout_vertical" />
 
 </com.android.systemui.tuner.PreviewNavInflater>
diff --git a/packages/SystemUI/res/layout/navigation_layout.xml b/packages/SystemUI/res/layout/navigation_layout.xml
index d72021e..db1c79d 100644
--- a/packages/SystemUI/res/layout/navigation_layout.xml
+++ b/packages/SystemUI/res/layout/navigation_layout.xml
@@ -22,7 +22,8 @@
     android:layout_marginStart="@dimen/rounded_corner_content_padding"
     android:layout_marginEnd="@dimen/rounded_corner_content_padding"
     android:paddingStart="@dimen/nav_content_padding"
-    android:paddingEnd="@dimen/nav_content_padding">
+    android:paddingEnd="@dimen/nav_content_padding"
+    android:id="@+id/horizontal">
 
     <com.android.systemui.statusbar.phone.NearestTouchFrame
         android:id="@+id/nav_buttons"
diff --git a/packages/SystemUI/res/layout/navigation_layout_rot90.xml b/packages/SystemUI/res/layout/navigation_layout_vertical.xml
similarity index 95%
rename from packages/SystemUI/res/layout/navigation_layout_rot90.xml
rename to packages/SystemUI/res/layout/navigation_layout_vertical.xml
index 24a0c71..285c5c4 100644
--- a/packages/SystemUI/res/layout/navigation_layout_rot90.xml
+++ b/packages/SystemUI/res/layout/navigation_layout_vertical.xml
@@ -22,7 +22,8 @@
     android:layout_marginTop="@dimen/rounded_corner_content_padding"
     android:layout_marginBottom="@dimen/rounded_corner_content_padding"
     android:paddingTop="@dimen/nav_content_padding"
-    android:paddingBottom="@dimen/nav_content_padding">
+    android:paddingBottom="@dimen/nav_content_padding"
+    android:id="@+id/vertical">
 
     <com.android.systemui.statusbar.phone.NearestTouchFrame
         android:id="@+id/nav_buttons"
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 4396a42..b4dc0eff 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -329,16 +329,11 @@
 
     <bool name="quick_settings_show_full_alarm">false</bool>
 
-    <!-- Whether to show a warning notification when the device reaches a certain temperature. -->
+    <!-- Whether to show a warning notification when device's skin temperature is high. -->
     <integer name="config_showTemperatureWarning">0</integer>
 
-    <!-- Temp at which to show a warning notification if config_showTemperatureWarning is true.
-         If < 0, uses the skin temperature sensor shutdown value from
-         HardwarePropertiesManager#getDeviceTemperatures - config_warningTemperatureTolerance. -->
-    <integer name="config_warningTemperature">-1</integer>
-
-    <!-- Fudge factor for how much below the shutdown temp to show the warning. -->
-    <integer name="config_warningTemperatureTolerance">2</integer>
+    <!-- Whether to show a alarm dialog when device's usb port is overheating. -->
+    <integer name="config_showUsbPortAlarm">0</integer>
 
     <!-- Accessibility actions -->
     <item type="id" name="action_split_task_to_left" />
@@ -485,4 +480,5 @@
     </string-array>
 
     <integer name="ongoing_appops_dialog_max_apps">5</integer>
+
 </resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 0fde2de..4905e57 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -2118,6 +2118,14 @@
     <string name="high_temp_notif_message">Some features limited while phone cools down</string>
     <!-- Text body for dialog alerting user that their phone has reached a certain temperature and may start to slow down in order to cool down. [CHAR LIMIT=300] -->
     <string name="high_temp_dialog_message">Your phone will automatically try to cool down. You can still use your phone, but it may run slower.\n\nOnce your phone has cooled down, it will run normally.</string>
+    <!-- Title for alarm dialog alerting user the usb adapter has reached a certain temperature that should disconnect charging cable immediately. [CHAR LIMIT=30] -->
+    <string name="high_temp_alarm_title">Unplug charger</string>
+    <!-- Text body for dialog alerting user the usb adapter has reached a certain temperature that should disconnect charging cable immediately. [CHAR LIMIT=300] -->
+    <string name="high_temp_alarm_notify_message">There\u2019s an issue charging this device. Unplug the power adapter, and take care as the cable may be warm.</string>
+    <!-- Text for See care steps button [CHAR LIMIT=300] -->
+    <string name="high_temp_alarm_help_care_steps">See care steps</string>
+    <!-- Text link directs to usb overheat help page. -->
+    <string name="high_temp_alarm_help_url" translatable="false">help_uri_usb_warm</string>
 
     <!-- SysUI Tuner: Button to select lock screen shortcut [CHAR LIMIT=60] -->
     <string name="lockscreen_shortcut_left">Left shortcut</string>
@@ -2378,5 +2386,4 @@
     <string name="no_bubbles">Block</string>
     <!-- Text used for button allowing user to approve / enable bubbles [CHAR LIMIT=20] -->
     <string name="yes_bubbles">Allow</string>
-
 </resources>
diff --git a/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java b/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
index c5dc324..3827e44 100644
--- a/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/clock/ClockManager.java
@@ -34,6 +34,7 @@
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.View.MeasureSpec;
+import android.view.ViewGroup;
 
 import androidx.annotation.VisibleForTesting;
 
@@ -241,6 +242,7 @@
         // Draw clock view hierarchy to canvas.
         Bitmap bitmap = Bitmap.createBitmap(mWidth, mHeight, Config.ARGB_8888);
         Canvas canvas = new Canvas(bitmap);
+        dispatchVisibilityAggregated(clockView, true);
         clockView.measure(MeasureSpec.makeMeasureSpec(mWidth, MeasureSpec.EXACTLY),
                 MeasureSpec.makeMeasureSpec(mHeight, MeasureSpec.EXACTLY));
         clockView.layout(0, 0, mWidth, mHeight);
@@ -250,6 +252,24 @@
         return bitmap;
     }
 
+    private void dispatchVisibilityAggregated(View view, boolean isVisible) {
+        // Similar to View.dispatchVisibilityAggregated implementation.
+        final boolean thisVisible = view.getVisibility() == View.VISIBLE;
+        if (thisVisible || !isVisible) {
+            view.onVisibilityAggregated(isVisible);
+        }
+
+        if (view instanceof ViewGroup) {
+            isVisible = thisVisible && isVisible;
+            ViewGroup vg = (ViewGroup) view;
+            int count = vg.getChildCount();
+
+            for (int i = 0; i < count; i++) {
+                dispatchVisibilityAggregated(vg.getChildAt(i), isVisible);
+            }
+        }
+    }
+
     private void notifyClockChanged(ClockPlugin plugin) {
         for (int i = 0; i < mListeners.size(); i++) {
             // It probably doesn't make sense to supply the same plugin instances to multiple
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 9efa656..60e6083 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -474,8 +474,6 @@
         if (anim == null) {
             return;
         }
-        int duration = SNAP_ANIM_LEN;
-        anim.setDuration(duration);
         anim.addListener(new AnimatorListenerAdapter() {
             boolean wasCancelled = false;
 
@@ -495,6 +493,9 @@
         });
         prepareSnapBackAnimation(animView, anim);
         mSnappingChild = true;
+        float maxDistance = Math.abs(targetLeft - getTranslation(animView));
+        mFlingAnimationUtils.apply(anim, getTranslation(animView), targetLeft, velocity,
+                maxDistance);
         anim.start();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
index 50dda1c..fdb0b36 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerNotificationWarnings.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.power;
 
+import android.app.KeyguardManager;
 import android.app.Notification;
 import android.app.NotificationManager;
 import android.app.PendingIntent;
@@ -41,6 +42,7 @@
 import android.util.Log;
 import android.util.Slog;
 import android.view.View;
+import android.view.WindowManager;
 
 import androidx.annotation.VisibleForTesting;
 
@@ -48,10 +50,13 @@
 import com.android.settingslib.Utils;
 import com.android.settingslib.fuelgauge.BatterySaverUtils;
 import com.android.settingslib.utils.PowerUtil;
+import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.SystemUI;
+import com.android.systemui.plugins.ActivityStarter;
 import com.android.systemui.statusbar.phone.SystemUIDialog;
 import com.android.systemui.util.NotificationChannels;
+import com.android.systemui.volume.Events;
 
 import java.io.PrintWriter;
 import java.text.NumberFormat;
@@ -118,6 +123,7 @@
     private final Context mContext;
     private final NotificationManager mNoMan;
     private final PowerManager mPowerMan;
+    private final KeyguardManager mKeyguard;
     private final Handler mHandler = new Handler(Looper.getMainLooper());
     private final Receiver mReceiver = new Receiver();
     private final Intent mOpenBatterySettings = settings(Intent.ACTION_POWER_USAGE_SUMMARY);
@@ -141,6 +147,7 @@
     private boolean mHighTempWarning;
     private SystemUIDialog mHighTempDialog;
     private SystemUIDialog mThermalShutdownDialog;
+    @VisibleForTesting SystemUIDialog mUsbHighTempDialog;
 
     /**
      */
@@ -149,6 +156,7 @@
         mContext = context;
         mNoMan = mContext.getSystemService(NotificationManager.class);
         mPowerMan = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
+        mKeyguard = mContext.getSystemService(KeyguardManager.class);
         mReceiver.init();
     }
 
@@ -165,6 +173,8 @@
         pw.print("mHighTempDialog="); pw.println(mHighTempDialog != null ? "not null" : null);
         pw.print("mThermalShutdownDialog=");
         pw.println(mThermalShutdownDialog != null ? "not null" : null);
+        pw.print("mUsbHighTempDialog=");
+        pw.println(mUsbHighTempDialog != null ? "not null" : null);
     }
 
     private int getLowBatteryAutoTriggerDefaultLevel() {
@@ -434,6 +444,53 @@
     }
 
     @Override
+    public void showUsbHighTemperatureAlarm() {
+        mHandler.post(() -> showUsbHighTemperatureAlarmInternal());
+    }
+
+    private void showUsbHighTemperatureAlarmInternal() {
+        if (mUsbHighTempDialog != null) {
+            return;
+        }
+
+        final SystemUIDialog d = new SystemUIDialog(mContext, R.style.Theme_SystemUI_Dialog_Alert);
+        d.setCancelable(false);
+        d.setIconAttribute(android.R.attr.alertDialogIcon);
+        d.setTitle(R.string.high_temp_alarm_title);
+        d.setShowForAllUsers(true);
+        d.setMessage(mContext.getString(R.string.high_temp_alarm_notify_message, ""));
+        d.setPositiveButton((com.android.internal.R.string.ok),
+                (dialogInterface, which) -> mUsbHighTempDialog = null);
+        d.setNegativeButton((R.string.high_temp_alarm_help_care_steps),
+                (dialogInterface, which) -> {
+                    final String contextString = mContext.getString(
+                            R.string.high_temp_alarm_help_url);
+                    final Intent helpIntent = new Intent();
+                    helpIntent.setClassName("com.android.settings",
+                            "com.android.settings.HelpTrampoline");
+                    helpIntent.putExtra(Intent.EXTRA_TEXT, contextString);
+                    Dependency.get(ActivityStarter.class).startActivity(helpIntent,
+                            true /* dismissShade */, resultCode -> {
+                                mUsbHighTempDialog = null;
+                            });
+                });
+        d.setOnDismissListener(dialogInterface -> {
+            mUsbHighTempDialog = null;
+            Events.writeEvent(mContext, Events.EVENT_DISMISS_USB_OVERHEAT_ALARM,
+                    Events.DISMISS_REASON_USB_OVERHEAD_ALARM_CHANGED,
+                    mKeyguard.isKeyguardLocked());
+        });
+        d.getWindow().addFlags(WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON
+                | WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
+        d.show();
+        mUsbHighTempDialog = d;
+
+        Events.writeEvent(mContext, Events.EVENT_SHOW_USB_OVERHEAT_ALARM,
+                Events.SHOW_REASON_USB_OVERHEAD_ALARM_CHANGED,
+                mKeyguard.isKeyguardLocked());
+    }
+
+    @Override
     public void updateLowBatteryWarning() {
         updateNotification();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
index c43f572..7312cbc 100644
--- a/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
+++ b/packages/SystemUI/src/com/android/systemui/power/PowerUI.java
@@ -43,7 +43,6 @@
 import android.util.Slog;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.logging.MetricsLogger;
 import com.android.settingslib.utils.ThreadUtils;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
@@ -82,26 +81,19 @@
     private boolean mLowWarningShownThisChargeCycle;
     private boolean mSevereWarningShownThisChargeCycle;
     private Future mLastShowWarningTask;
+    private boolean mEnableSkinTemperatureWarning;
+    private boolean mEnableUsbTemperatureAlarm;
 
     private int mLowBatteryAlertCloseLevel;
     private final int[] mLowBatteryReminderLevels = new int[2];
 
     private long mScreenOffTime = -1;
 
-    private float mThresholdTemp;
-    private float[] mRecentTemps = new float[MAX_RECENT_TEMPS];
-    private int mNumTemps;
-    private long mNextLogTime;
     @VisibleForTesting IThermalService mThermalService;
 
     @VisibleForTesting int mBatteryLevel = 100;
     @VisibleForTesting int mBatteryStatus = BatteryManager.BATTERY_STATUS_UNKNOWN;
 
-    // by using the same instance (method references are not guaranteed to be the same object
-    // We create a method reference here so that we are guaranteed that we can remove a callback
-    // each time they are created).
-    private final Runnable mUpdateTempCallback = this::updateTemperatureWarning;
-
     public void start() {
         mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
         mHardwarePropertiesManager = (HardwarePropertiesManager)
@@ -128,7 +120,7 @@
         // to the temperature being too high.
         showThermalShutdownDialog();
 
-        initTemperatureWarning();
+        initTemperature();
     }
 
     @Override
@@ -137,7 +129,7 @@
 
         // Safe to modify mLastConfiguration here as it's only updated by the main thread (here).
         if ((mLastConfiguration.updateFrom(newConfig) & mask) != 0) {
-            mHandler.post(this::initTemperatureWarning);
+            mHandler.post(this::initTemperature);
         }
     }
 
@@ -383,30 +375,16 @@
         return canShowWarning || canShowSevereWarning;
     }
 
-    private void initTemperatureWarning() {
+    private void initTemperature() {
         ContentResolver resolver = mContext.getContentResolver();
         Resources resources = mContext.getResources();
-        if (Settings.Global.getInt(resolver, Settings.Global.SHOW_TEMPERATURE_WARNING,
-                resources.getInteger(R.integer.config_showTemperatureWarning)) == 0) {
-            return;
-        }
 
-        mThresholdTemp = Settings.Global.getFloat(resolver, Settings.Global.WARNING_TEMPERATURE,
-                resources.getInteger(R.integer.config_warningTemperature));
-
-        if (mThresholdTemp < 0f) {
-            // Get the shutdown temperature, adjust for warning tolerance.
-            float[] throttlingTemps = mHardwarePropertiesManager.getDeviceTemperatures(
-                    HardwarePropertiesManager.DEVICE_TEMPERATURE_SKIN,
-                    HardwarePropertiesManager.TEMPERATURE_SHUTDOWN);
-            if (throttlingTemps == null
-                    || throttlingTemps.length == 0
-                    || throttlingTemps[0] == HardwarePropertiesManager.UNDEFINED_TEMPERATURE) {
-                return;
-            }
-            mThresholdTemp = throttlingTemps[0] -
-                    resources.getInteger(R.integer.config_warningTemperatureTolerance);
-        }
+        mEnableSkinTemperatureWarning = Settings.Global.getInt(resolver,
+                Settings.Global.SHOW_TEMPERATURE_WARNING,
+                resources.getInteger(R.integer.config_showTemperatureWarning)) != 0;
+        mEnableUsbTemperatureAlarm = Settings.Global.getInt(resolver,
+                Settings.Global.SHOW_USB_TEMPERATURE_ALARM,
+                resources.getInteger(R.integer.config_showUsbPortAlarm)) != 0;
 
         if (mThermalService == null) {
             // Enable push notifications of throttling from vendor thermal
@@ -416,21 +394,27 @@
 
             if (b != null) {
                 mThermalService = IThermalService.Stub.asInterface(b);
-                try {
-                    mThermalService.registerThermalEventListenerWithType(
-                            new ThermalEventListener(), Temperature.TYPE_SKIN);
-                } catch (RemoteException e) {
-                    // Should never happen.
-                }
+                registerThermalEventListener();
             } else {
                 Slog.w(TAG, "cannot find thermalservice, no throttling push notifications");
             }
         }
+    }
 
-        setNextLogTime();
-
-        // We have passed all of the checks, start checking the temp
-        mHandler.post(mUpdateTempCallback);
+    @VisibleForTesting
+    void registerThermalEventListener() {
+        try {
+            if (mEnableSkinTemperatureWarning) {
+                mThermalService.registerThermalEventListenerWithType(
+                        new ThermalEventSkinListener(), Temperature.TYPE_SKIN);
+            }
+            if (mEnableUsbTemperatureAlarm) {
+                mThermalService.registerThermalEventListenerWithType(
+                        new ThermalEventUsbListener(), Temperature.TYPE_USB_PORT);
+            }
+        } catch (RemoteException e) {
+            Slog.e(TAG, "Failed to register thermal callback.", e);
+        }
     }
 
     private void showThermalShutdownDialog() {
@@ -440,81 +424,6 @@
         }
     }
 
-    @VisibleForTesting
-    protected void updateTemperatureWarning() {
-        float[] temps = mHardwarePropertiesManager.getDeviceTemperatures(
-                HardwarePropertiesManager.DEVICE_TEMPERATURE_SKIN,
-                HardwarePropertiesManager.TEMPERATURE_CURRENT);
-        if (temps.length != 0) {
-            float temp = temps[0];
-            mRecentTemps[mNumTemps++] = temp;
-
-            StatusBar statusBar = getComponent(StatusBar.class);
-            if (statusBar != null && !statusBar.isDeviceInVrMode()
-                    && temp >= mThresholdTemp) {
-                logAtTemperatureThreshold(temp);
-                mWarnings.showHighTemperatureWarning();
-            } else {
-                mWarnings.dismissHighTemperatureWarning();
-            }
-        }
-
-        logTemperatureStats();
-
-        // Remove any pending callbacks as we only want to enable one
-        mHandler.removeCallbacks(mUpdateTempCallback);
-        mHandler.postDelayed(mUpdateTempCallback, TEMPERATURE_INTERVAL);
-    }
-
-    private void logAtTemperatureThreshold(float temp) {
-        StringBuilder sb = new StringBuilder();
-        sb.append("currentTemp=").append(temp)
-                .append(",thresholdTemp=").append(mThresholdTemp)
-                .append(",batteryStatus=").append(mBatteryStatus)
-                .append(",recentTemps=");
-        for (int i = 0; i < mNumTemps; i++) {
-            sb.append(mRecentTemps[i]).append(',');
-        }
-        Slog.i(TAG, sb.toString());
-    }
-
-    /**
-     * Calculates and logs min, max, and average
-     * {@link HardwarePropertiesManager#DEVICE_TEMPERATURE_SKIN} over the past
-     * {@link #TEMPERATURE_LOGGING_INTERVAL}.
-     */
-    private void logTemperatureStats() {
-        if (mNextLogTime > System.currentTimeMillis() && mNumTemps != MAX_RECENT_TEMPS) {
-            return;
-        }
-
-        if (mNumTemps > 0) {
-            float sum = mRecentTemps[0], min = mRecentTemps[0], max = mRecentTemps[0];
-            for (int i = 1; i < mNumTemps; i++) {
-                float temp = mRecentTemps[i];
-                sum += temp;
-                if (temp > max) {
-                    max = temp;
-                }
-                if (temp < min) {
-                    min = temp;
-                }
-            }
-
-            float avg = sum / mNumTemps;
-            Slog.i(TAG, "avg=" + avg + ",min=" + min + ",max=" + max);
-            MetricsLogger.histogram(mContext, "device_skin_temp_avg", (int) avg);
-            MetricsLogger.histogram(mContext, "device_skin_temp_min", (int) min);
-            MetricsLogger.histogram(mContext, "device_skin_temp_max", (int) max);
-        }
-        setNextLogTime();
-        mNumTemps = 0;
-    }
-
-    private void setNextLogTime() {
-        mNextLogTime = System.currentTimeMillis() + TEMPERATURE_LOGGING_INTERVAL;
-    }
-
     public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
         pw.print("mLowBatteryAlertCloseLevel=");
         pw.println(mLowBatteryAlertCloseLevel);
@@ -541,34 +450,80 @@
                 Settings.Global.LOW_BATTERY_SOUND_TIMEOUT, 0));
         pw.print("bucket: ");
         pw.println(Integer.toString(findBatteryLevelBucket(mBatteryLevel)));
-        pw.print("mThresholdTemp=");
-        pw.println(Float.toString(mThresholdTemp));
-        pw.print("mNextLogTime=");
-        pw.println(Long.toString(mNextLogTime));
+        pw.print("mEnableSkinTemperatureWarning=");
+        pw.println(mEnableSkinTemperatureWarning);
+        pw.print("mEnableUsbTemperatureAlarm=");
+        pw.println(mEnableUsbTemperatureAlarm);
         mWarnings.dump(pw);
     }
 
     public interface WarningsUI {
         void update(int batteryLevel, int bucket, long screenOffTime);
+
         void updateEstimate(Estimate estimate);
+
         void updateThresholds(long lowThreshold, long severeThreshold);
+
         void dismissLowBatteryWarning();
+
         void showLowBatteryWarning(boolean playSound);
+
         void dismissInvalidChargerWarning();
+
         void showInvalidChargerWarning();
+
         void updateLowBatteryWarning();
+
         boolean isInvalidChargerWarningShowing();
+
         void dismissHighTemperatureWarning();
+
         void showHighTemperatureWarning();
+
+        /**
+         * Display USB overheat alarm
+         */
+        void showUsbHighTemperatureAlarm();
+
         void showThermalShutdownWarning();
+
         void dump(PrintWriter pw);
+
         void userSwitched();
     }
 
-    // Thermal event received from vendor thermal management subsystem
-    private final class ThermalEventListener extends IThermalEventListener.Stub {
+    // Thermal event received from thermal service manager subsystem
+    @VisibleForTesting
+    final class ThermalEventSkinListener extends IThermalEventListener.Stub {
         @Override public void notifyThrottling(Temperature temp) {
-            mHandler.post(mUpdateTempCallback);
+            int status = temp.getStatus();
+
+            if (status >= Temperature.THROTTLING_EMERGENCY) {
+                StatusBar statusBar = getComponent(StatusBar.class);
+                if (statusBar != null && !statusBar.isDeviceInVrMode()) {
+                    mWarnings.showHighTemperatureWarning();
+                    Slog.d(TAG, "ThermalEventSkinListener: notifyThrottling was called "
+                            + ", current skin status = " + status
+                            + ", temperature = " + temp.getValue());
+                }
+            } else {
+                mWarnings.dismissHighTemperatureWarning();
+            }
+        }
+    }
+
+    // Thermal event received from thermal service manager subsystem
+    @VisibleForTesting
+    final class ThermalEventUsbListener extends IThermalEventListener.Stub {
+        @Override public void notifyThrottling(Temperature temp) {
+            int status = temp.getStatus();
+
+            if (status >= Temperature.THROTTLING_EMERGENCY) {
+                mWarnings.showUsbHighTemperatureAlarm();
+                Slog.d(TAG, "ThermalEventUsbListener: notifyThrottling was called "
+                        + ", current usb port status = " + status
+                        + ", temperature = " + temp.getValue());
+            }
         }
     }
 }
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 cf3f89e..409d60f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavBarTintController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavBarTintController.java
@@ -135,7 +135,7 @@
         final Bitmap hardBitmap = SurfaceControl
                 .screenshot(new Rect(), mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels,
                         mNavigationBarView.getContext().getDisplay().getRotation());
-        if (cropRect.bottom <= hardBitmap.getHeight()
+        if (hardBitmap != null && cropRect.bottom <= hardBitmap.getHeight()
                 && cropRect.left + cropRect.width() <= hardBitmap.getWidth()) {
             final Bitmap cropBitmap = Bitmap.createBitmap(hardBitmap, cropRect.left, cropRect.top,
                     cropRect.width(), cropRect.height());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
index c9fa89e..faa2ab1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
@@ -23,18 +23,15 @@
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.SparseArray;
-import android.view.Display;
-import android.view.Display.Mode;
 import android.view.Gravity;
 import android.view.LayoutInflater;
-import android.view.Surface;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.WindowManager;
 import android.widget.FrameLayout;
 import android.widget.LinearLayout;
 import android.widget.Space;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.Dependency;
 import com.android.systemui.R;
 import com.android.systemui.plugins.PluginListener;
@@ -84,21 +81,21 @@
     private static final String WEIGHT_CENTERED_SUFFIX = "WC";
 
     private final List<NavBarButtonProvider> mPlugins = new ArrayList<>();
-    private final Display mDisplay;
 
     protected LayoutInflater mLayoutInflater;
     protected LayoutInflater mLandscapeInflater;
 
-    protected FrameLayout mRot0;
-    protected FrameLayout mRot90;
-    private boolean isRot0Landscape;
+    protected FrameLayout mHorizontal;
+    protected FrameLayout mVertical;
 
-    private SparseArray<ButtonDispatcher> mButtonDispatchers;
+    @VisibleForTesting
+    SparseArray<ButtonDispatcher> mButtonDispatchers;
     private String mCurrentLayout;
 
     private View mLastPortrait;
     private View mLastLandscape;
 
+    private boolean mIsVertical;
     private boolean mAlternativeOrder;
     private boolean mUsingCustomLayout;
 
@@ -107,14 +104,11 @@
     public NavigationBarInflaterView(Context context, AttributeSet attrs) {
         super(context, attrs);
         createInflaters();
-        mDisplay = ((WindowManager)
-                context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
-        Mode displayMode = mDisplay.getMode();
-        isRot0Landscape = displayMode.getPhysicalWidth() > displayMode.getPhysicalHeight();
         mOverviewProxyService = Dependency.get(OverviewProxyService.class);
     }
 
-    private void createInflaters() {
+    @VisibleForTesting
+    void createInflaters() {
         mLayoutInflater = LayoutInflater.from(mContext);
         Configuration landscape = new Configuration();
         landscape.setTo(mContext.getResources().getConfiguration());
@@ -132,13 +126,12 @@
 
     private void inflateChildren() {
         removeAllViews();
-        mRot0 = (FrameLayout) mLayoutInflater.inflate(R.layout.navigation_layout, this, false);
-        mRot0.setId(R.id.rot0);
-        addView(mRot0);
-        mRot90 = (FrameLayout) mLayoutInflater.inflate(R.layout.navigation_layout_rot90, this,
-                false);
-        mRot90.setId(R.id.rot90);
-        addView(mRot90);
+        mHorizontal = (FrameLayout) mLayoutInflater.inflate(R.layout.navigation_layout,
+                this /* root */, false /* attachToRoot */);
+        addView(mHorizontal);
+        mVertical = (FrameLayout) mLayoutInflater.inflate(R.layout.navigation_layout_vertical,
+                this /* root */, false /* attachToRoot */);
+        addView(mVertical);
         updateAlternativeOrder();
     }
 
@@ -198,12 +191,9 @@
         }
     }
 
-    public void updateButtonDispatchersCurrentView() {
+    void updateButtonDispatchersCurrentView() {
         if (mButtonDispatchers != null) {
-            final int rotation = mDisplay.getRotation();
-            final boolean portrait = rotation == Surface.ROTATION_0
-                    || rotation == Surface.ROTATION_180;
-            final View view = portrait ? mRot0 : mRot90;
+            View view = mIsVertical ? mVertical : mHorizontal;
             for (int i = 0; i < mButtonDispatchers.size(); i++) {
                 final ButtonDispatcher dispatcher = mButtonDispatchers.valueAt(i);
                 dispatcher.setCurrentView(view);
@@ -211,7 +201,13 @@
         }
     }
 
-    public void setAlternativeOrder(boolean alternativeOrder) {
+    void setVertical(boolean vertical) {
+        if (vertical != mIsVertical) {
+            mIsVertical = vertical;
+        }
+    }
+
+    void setAlternativeOrder(boolean alternativeOrder) {
         if (alternativeOrder != mAlternativeOrder) {
             mAlternativeOrder = alternativeOrder;
             updateAlternativeOrder();
@@ -219,10 +215,10 @@
     }
 
     private void updateAlternativeOrder() {
-        updateAlternativeOrder(mRot0.findViewById(R.id.ends_group));
-        updateAlternativeOrder(mRot0.findViewById(R.id.center_group));
-        updateAlternativeOrder(mRot90.findViewById(R.id.ends_group));
-        updateAlternativeOrder(mRot90.findViewById(R.id.center_group));
+        updateAlternativeOrder(mHorizontal.findViewById(R.id.ends_group));
+        updateAlternativeOrder(mHorizontal.findViewById(R.id.center_group));
+        updateAlternativeOrder(mVertical.findViewById(R.id.ends_group));
+        updateAlternativeOrder(mVertical.findViewById(R.id.center_group));
     }
 
     private void updateAlternativeOrder(View v) {
@@ -232,10 +228,10 @@
     }
 
     private void initiallyFill(ButtonDispatcher buttonDispatcher) {
-        addAll(buttonDispatcher, (ViewGroup) mRot0.findViewById(R.id.ends_group));
-        addAll(buttonDispatcher, (ViewGroup) mRot0.findViewById(R.id.center_group));
-        addAll(buttonDispatcher, (ViewGroup) mRot90.findViewById(R.id.ends_group));
-        addAll(buttonDispatcher, (ViewGroup) mRot90.findViewById(R.id.center_group));
+        addAll(buttonDispatcher, mHorizontal.findViewById(R.id.ends_group));
+        addAll(buttonDispatcher, mHorizontal.findViewById(R.id.center_group));
+        addAll(buttonDispatcher, mVertical.findViewById(R.id.ends_group));
+        addAll(buttonDispatcher, mVertical.findViewById(R.id.center_group));
     }
 
     private void addAll(ButtonDispatcher buttonDispatcher, ViewGroup parent) {
@@ -267,17 +263,23 @@
         String[] center = sets[1].split(BUTTON_SEPARATOR);
         String[] end = sets[2].split(BUTTON_SEPARATOR);
         // Inflate these in start to end order or accessibility traversal will be messed up.
-        inflateButtons(start, mRot0.findViewById(R.id.ends_group), isRot0Landscape, true);
-        inflateButtons(start, mRot90.findViewById(R.id.ends_group), !isRot0Landscape, true);
+        inflateButtons(start, mHorizontal.findViewById(R.id.ends_group),
+                false /* landscape */, true /* start */);
+        inflateButtons(start, mVertical.findViewById(R.id.ends_group),
+                true /* landscape */, true /* start */);
 
-        inflateButtons(center, mRot0.findViewById(R.id.center_group), isRot0Landscape, false);
-        inflateButtons(center, mRot90.findViewById(R.id.center_group), !isRot0Landscape, false);
+        inflateButtons(center, mHorizontal.findViewById(R.id.center_group),
+                false /* landscape */, false /* start */);
+        inflateButtons(center, mVertical.findViewById(R.id.center_group),
+                true /* landscape */, false /* start */);
 
-        addGravitySpacer(mRot0.findViewById(R.id.ends_group));
-        addGravitySpacer(mRot90.findViewById(R.id.ends_group));
+        addGravitySpacer(mHorizontal.findViewById(R.id.ends_group));
+        addGravitySpacer(mVertical.findViewById(R.id.ends_group));
 
-        inflateButtons(end, mRot0.findViewById(R.id.ends_group), isRot0Landscape, false);
-        inflateButtons(end, mRot90.findViewById(R.id.ends_group), !isRot0Landscape, false);
+        inflateButtons(end, mHorizontal.findViewById(R.id.ends_group),
+                false /* landscape */, false /* start */);
+        inflateButtons(end, mVertical.findViewById(R.id.ends_group),
+                true /* landscape */, false /* start */);
 
         updateButtonDispatchersCurrentView();
     }
@@ -472,8 +474,8 @@
                 mButtonDispatchers.valueAt(i).clear();
             }
         }
-        clearAllChildren(mRot0.findViewById(R.id.nav_buttons));
-        clearAllChildren(mRot90.findViewById(R.id.nav_buttons));
+        clearAllChildren(mHorizontal.findViewById(R.id.nav_buttons));
+        clearAllChildren(mVertical.findViewById(R.id.nav_buttons));
     }
 
     private void clearAllChildren(ViewGroup group) {
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 d6d3d08..f82b05e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -116,9 +116,11 @@
     final static boolean ALTERNATE_CAR_MODE_UI = false;
 
     View mCurrentView = null;
-    View[] mRotatedViews = new View[4];
+    private View mVertical;
+    private View mHorizontal;
 
-    boolean mVertical;
+    /** Indicates that navigation bar is vertical. */
+    private boolean mIsVertical;
     private int mCurrentRotation = -1;
 
     boolean mLongClickableAccessibilityButton;
@@ -350,7 +352,7 @@
     public NavigationBarView(Context context, AttributeSet attrs) {
         super(context, attrs);
 
-        mVertical = false;
+        mIsVertical = false;
         mLongClickableAccessibilityButton = false;
 
         // Set up the context group of buttons
@@ -471,7 +473,7 @@
 
     public void setOnVerticalChangedListener(OnVerticalChangedListener onVerticalChangedListener) {
         mOnVerticalChangedListener = onVerticalChangedListener;
-        notifyVerticalChangedListener(mVertical);
+        notifyVerticalChangedListener(mIsVertical);
     }
 
     @Override
@@ -547,10 +549,6 @@
         return mCurrentView;
     }
 
-    public View[] getAllViews() {
-        return mRotatedViews;
-    }
-
     public ButtonDispatcher getRecentsButton() {
         return mButtonDispatchers.get(R.id.recent_apps);
     }
@@ -657,7 +655,7 @@
 
         // Animate the back button's rotation to the new degrees and only in portrait move up the
         // back button to line up with the other buttons
-        float targetY = !mOverviewProxyService.shouldShowSwipeUpUI() && !mVertical && useAltBack
+        float targetY = !mOverviewProxyService.shouldShowSwipeUpUI() && !mIsVertical && useAltBack
                 ? - getResources().getDimension(R.dimen.navbar_back_button_ime_offset)
                 : 0;
         ObjectAnimator navBarAnimator = ObjectAnimator.ofPropertyValuesHolder(drawable,
@@ -669,7 +667,7 @@
     }
 
     private void orientHomeButton(KeyButtonDrawable drawable) {
-        drawable.setRotation(mVertical ? 90 : 0);
+        drawable.setRotation(mIsVertical ? 90 : 0);
     }
 
     private KeyButtonDrawable chooseNavigationIconDrawable(@DrawableRes int icon,
@@ -964,7 +962,7 @@
         getImeSwitchButton().setOnClickListener(mImeSwitcherClickListener);
 
         DockedStackExistsListener.register(mDockedListener);
-        updateRotatedViews();
+        updateOrientationViews();
         reloadNavIcons();
     }
 
@@ -1028,34 +1026,35 @@
         view.setTranslationY(posY);
     }
 
-    private void updateRotatedViews() {
-        mRotatedViews[Surface.ROTATION_0] =
-                mRotatedViews[Surface.ROTATION_180] = findViewById(R.id.rot0);
-        mRotatedViews[Surface.ROTATION_270] =
-                mRotatedViews[Surface.ROTATION_90] = findViewById(R.id.rot90);
+    private void updateOrientationViews() {
+        mHorizontal = findViewById(R.id.horizontal);
+        mVertical = findViewById(R.id.vertical);
 
         updateCurrentView();
     }
 
-    public boolean needsReorient(int rotation) {
+    boolean needsReorient(int rotation) {
         return mCurrentRotation != rotation;
     }
 
     private void updateCurrentView() {
-        final int rot = getContextDisplay().getRotation();
-        for (int i=0; i<4; i++) {
-            mRotatedViews[i].setVisibility(View.GONE);
-        }
-        mCurrentView = mRotatedViews[rot];
+        resetViews();
+        mCurrentView = mIsVertical ? mVertical : mHorizontal;
         mCurrentView.setVisibility(View.VISIBLE);
-        mNavigationInflaterView.setAlternativeOrder(rot == Surface.ROTATION_90);
+        mNavigationInflaterView.setVertical(mIsVertical);
+        mCurrentRotation = getContextDisplay().getRotation();
+        mNavigationInflaterView.setAlternativeOrder(mCurrentRotation == Surface.ROTATION_90);
         mNavigationInflaterView.updateButtonDispatchersCurrentView();
         updateLayoutTransitionsEnabled();
-        mCurrentRotation = rot;
+    }
+
+    private void resetViews() {
+        mHorizontal.setVisibility(View.GONE);
+        mVertical.setVisibility(View.GONE);
     }
 
     private void updateRecentsIcon() {
-        mDockedIcon.setRotation(mDockedStackExists && mVertical ? 90 : 0);
+        mDockedIcon.setRotation(mDockedStackExists && mIsVertical ? 90 : 0);
         getRecentsButton().setImageDrawable(mDockedStackExists ? mDockedIcon : mRecentIcon);
         mBarTransitions.reapplyDarkIntensity();
     }
@@ -1077,7 +1076,7 @@
     }
 
     public boolean isVertical() {
-        return mVertical;
+        return mIsVertical;
     }
 
     public void reorient() {
@@ -1101,7 +1100,7 @@
         updateTaskSwitchHelper();
         updateNavButtonIcons();
 
-        getHomeButton().setVertical(mVertical);
+        getHomeButton().setVertical(mIsVertical);
     }
 
     private void updateTaskSwitchHelper() {
@@ -1134,9 +1133,12 @@
                     "onSizeChanged: (%dx%d) old: (%dx%d)", w, h, oldw, oldh));
 
         final boolean newVertical = w > 0 && h > w;
-        if (newVertical != mVertical) {
-            mVertical = newVertical;
-            //Log.v(TAG, String.format("onSizeChanged: h=%d, w=%d, vert=%s", h, w, mVertical?"y":"n"));
+        if (newVertical != mIsVertical) {
+            mIsVertical = newVertical;
+            if (DEBUG) {
+                Log.d(TAG, String.format("onSizeChanged: h=%d, w=%d, vert=%s", h, w,
+                        mIsVertical ? "y" : "n"));
+            }
             reorient();
             notifyVerticalChangedListener(newVertical);
         }
@@ -1347,7 +1349,7 @@
 
         pw.println(String.format("      disabled=0x%08x vertical=%s menu=%s darkIntensity=%.2f",
                         mDisabledFlags,
-                        mVertical ? "true" : "false",
+                        mIsVertical ? "true" : "false",
                         getMenuButton().isVisible() ? "true" : "false",
                         getLightTransitionsController().getCurrentDarkIntensity()));
 
diff --git a/packages/SystemUI/src/com/android/systemui/volume/Events.java b/packages/SystemUI/src/com/android/systemui/volume/Events.java
index ca55e1f..1596ddb 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/Events.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/Events.java
@@ -53,6 +53,8 @@
     public static final int EVENT_TOUCH_LEVEL_DONE = 16;  // (stream|int) (level|bool)
     public static final int EVENT_ZEN_CONFIG_CHANGED = 17; // (allow/disallow|string)
     public static final int EVENT_RINGER_TOGGLE = 18; // (ringer_mode)
+    public static final int EVENT_SHOW_USB_OVERHEAT_ALARM = 19; // (reason|int) (keyguard|bool)
+    public static final int EVENT_DISMISS_USB_OVERHEAT_ALARM = 20; // (reason|int) (keyguard|bool)
 
     private static final String[] EVENT_TAGS = {
             "show_dialog",
@@ -73,7 +75,9 @@
             "mute_changed",
             "touch_level_done",
             "zen_mode_config_changed",
-            "ringer_toggle"
+            "ringer_toggle",
+            "show_usb_overheat_alarm",
+            "dismiss_usb_overheat_alarm"
     };
 
     public static final int DISMISS_REASON_UNKNOWN = 0;
@@ -85,6 +89,7 @@
     public static final int DISMISS_REASON_DONE_CLICKED = 6;
     public static final int DISMISS_STREAM_GONE = 7;
     public static final int DISMISS_REASON_OUTPUT_CHOOSER = 8;
+    public static final int DISMISS_REASON_USB_OVERHEAD_ALARM_CHANGED = 9;
     public static final String[] DISMISS_REASONS = {
             "unknown",
             "touch_outside",
@@ -94,16 +99,19 @@
             "settings_clicked",
             "done_clicked",
             "a11y_stream_changed",
-            "output_chooser"
+            "output_chooser",
+            "usb_temperature_below_threshold"
     };
 
     public static final int SHOW_REASON_UNKNOWN = 0;
     public static final int SHOW_REASON_VOLUME_CHANGED = 1;
     public static final int SHOW_REASON_REMOTE_VOLUME_CHANGED = 2;
+    public static final int SHOW_REASON_USB_OVERHEAD_ALARM_CHANGED = 3;
     public static final String[] SHOW_REASONS = {
         "unknown",
         "volume_changed",
-        "remote_volume_changed"
+        "remote_volume_changed",
+        "usb_temperature_above_threshold"
     };
 
     public static final int ICON_STATE_UNKNOWN = 0;
@@ -181,6 +189,19 @@
                 case EVENT_SUPPRESSOR_CHANGED:
                     sb.append(list[0]).append(' ').append(list[1]);
                     break;
+                case EVENT_SHOW_USB_OVERHEAT_ALARM:
+                    MetricsLogger.visible(context, MetricsEvent.POWER_OVERHEAT_ALARM);
+                    MetricsLogger.histogram(context, "show_usb_overheat_alarm",
+                            (Boolean) list[1] ? 1 : 0);
+                    sb.append(SHOW_REASONS[(Integer) list[0]]).append(" keyguard=").append(list[1]);
+                    break;
+                case EVENT_DISMISS_USB_OVERHEAT_ALARM:
+                    MetricsLogger.hidden(context, MetricsEvent.POWER_OVERHEAT_ALARM);
+                    MetricsLogger.histogram(context, "dismiss_usb_overheat_alarm",
+                            (Boolean) list[1] ? 1 : 0);
+                    sb.append(DISMISS_REASONS[(Integer) list[0]])
+                        .append(" keyguard=").append(list[1]);
+                    break;
                 default:
                     sb.append(Arrays.asList(list));
                     break;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java b/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
index bf6cc53..cd500b4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerNotificationWarningsTest.java
@@ -16,9 +16,8 @@
 
 package com.android.systemui.power;
 
-import static android.test.MoreAsserts.assertNotEqual;
+import static com.google.common.truth.Truth.assertThat;
 
-import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
 
@@ -38,7 +37,6 @@
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.util.NotificationChannels;
 
-import java.util.concurrent.TimeUnit;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -151,4 +149,13 @@
         verify(mMockNotificationManager, times(1)).cancelAsUser(anyString(),
                 eq(SystemMessage.NOTE_THERMAL_SHUTDOWN), any());
     }
+
+    @Test
+    public void testShowUsbHighTemperatureAlarm() {
+        mPowerNotificationWarnings.showUsbHighTemperatureAlarm();
+        waitForIdleSync(mContext.getMainThreadHandler());
+        assertThat(mPowerNotificationWarnings.mUsbHighTempDialog).isNotNull();
+
+        mPowerNotificationWarnings.mUsbHighTempDialog.dismiss();
+    }
 }
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 c28e74e..4a4e247 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/power/PowerUITest.java
@@ -14,14 +14,14 @@
 
 package com.android.systemui.power;
 
-import static android.os.HardwarePropertiesManager.DEVICE_TEMPERATURE_SKIN;
-import static android.os.HardwarePropertiesManager.TEMPERATURE_CURRENT;
-import static android.os.HardwarePropertiesManager.TEMPERATURE_SHUTDOWN;
 import static android.provider.Settings.Global.SHOW_TEMPERATURE_WARNING;
+import static android.provider.Settings.Global.SHOW_USB_TEMPERATURE_ALARM;
 
 import static junit.framework.Assert.assertFalse;
 import static junit.framework.Assert.assertTrue;
 
+import static org.mockito.Matchers.eq;
+import static org.mockito.Mockito.anyObject;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
@@ -32,8 +32,10 @@
 import android.content.Intent;
 import android.os.BatteryManager;
 import android.os.HardwarePropertiesManager;
+import android.os.IThermalEventListener;
 import android.os.IThermalService;
 import android.os.PowerManager;
+import android.os.Temperature;
 import android.provider.Settings;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.testing.AndroidTestingRunner;
@@ -80,6 +82,8 @@
     private EnhancedEstimates mEnhancedEstimates;
     @Mock private PowerManager mPowerManager;
     @Mock private IThermalService mThermalServiceMock;
+    private IThermalEventListener mThermalEventUsbListener;
+    private IThermalEventListener mThermalEventSkinListener;
 
     @Before
     public void setup() {
@@ -93,78 +97,86 @@
         mContext.addMockSystemService(Context.POWER_SERVICE, mPowerManager);
 
         createPowerUi();
+        mThermalEventSkinListener = mPowerUI.new ThermalEventSkinListener();
+        mThermalEventUsbListener = mPowerUI.new ThermalEventUsbListener();
     }
 
     @Test
-    public void testNoConfig_NoWarnings() {
-        setOverThreshold();
-        Settings.Global.putString(mContext.getContentResolver(), SHOW_TEMPERATURE_WARNING, null);
-        TestableResources resources = mContext.getOrCreateTestableResources();
-        resources.addOverride(R.integer.config_showTemperatureWarning, 0);
-        resources.addOverride(R.integer.config_warningTemperature, 55);
-
+    public void testSkinWarning_throttlingCritical() throws Exception {
         mPowerUI.start();
-        verify(mMockWarnings, never()).showHighTemperatureWarning();
-    }
 
-    @Test
-    public void testConfig_NoWarnings() {
-        setUnderThreshold();
-        Settings.Global.putString(mContext.getContentResolver(), SHOW_TEMPERATURE_WARNING, null);
-        TestableResources resources = mContext.getOrCreateTestableResources();
-        resources.addOverride(R.integer.config_showTemperatureWarning, 1);
-        resources.addOverride(R.integer.config_warningTemperature, 55);
+        final Temperature temp = getCriticalStatusTemp(Temperature.TYPE_SKIN, "skin1");
+        mThermalEventSkinListener.notifyThrottling(temp);
 
-        mPowerUI.start();
-        verify(mMockWarnings, never()).showHighTemperatureWarning();
-    }
-
-    @Test
-    public void testConfig_Warnings() {
-        setOverThreshold();
-        Settings.Global.putString(mContext.getContentResolver(), SHOW_TEMPERATURE_WARNING, null);
-        TestableResources resources = mContext.getOrCreateTestableResources();
-        resources.addOverride(R.integer.config_showTemperatureWarning, 1);
-        resources.addOverride(R.integer.config_warningTemperature, 55);
-
-        mPowerUI.start();
-        // Guarantees mHandler has processed all messages.
+        // dismiss skin high temperature warning when throttling status is critical
         TestableLooper.get(this).processAllMessages();
-        verify(mMockWarnings).showHighTemperatureWarning();
+        verify(mMockWarnings, never()).showHighTemperatureWarning();
+        verify(mMockWarnings, times(1)).dismissHighTemperatureWarning();
     }
 
     @Test
-    public void testSettingOverrideConfig() {
-        setOverThreshold();
+    public void testSkinWarning_throttlingEmergency() throws Exception {
+        mPowerUI.start();
+
+        final Temperature temp = getEmergencyStatusTemp(Temperature.TYPE_SKIN, "skin2");
+        mThermalEventSkinListener.notifyThrottling(temp);
+
+        // show skin high temperature warning when throttling status is emergency
+        TestableLooper.get(this).processAllMessages();
+        verify(mMockWarnings, times(1)).showHighTemperatureWarning();
+        verify(mMockWarnings, never()).dismissHighTemperatureWarning();
+    }
+
+    @Test
+    public void testUsbAlarm_throttlingCritical() throws Exception {
+        mPowerUI.start();
+
+        final Temperature temp = getCriticalStatusTemp(Temperature.TYPE_USB_PORT, "usb1");
+        mThermalEventUsbListener.notifyThrottling(temp);
+
+        // not show usb high temperature alarm when throttling status is critical
+        TestableLooper.get(this).processAllMessages();
+        verify(mMockWarnings, never()).showUsbHighTemperatureAlarm();
+    }
+
+    @Test
+    public void testUsbAlarm_throttlingEmergency() throws Exception {
+        mPowerUI.start();
+
+        final Temperature temp = getEmergencyStatusTemp(Temperature.TYPE_USB_PORT, "usb2");
+        mThermalEventUsbListener.notifyThrottling(temp);
+
+        // show usb high temperature alarm when throttling status is emergency
+        TestableLooper.get(this).processAllMessages();
+        verify(mMockWarnings, times(1)).showUsbHighTemperatureAlarm();
+    }
+
+    @Test
+    public void testSettingOverrideConfig_enableSkinTemperatureWarning() throws Exception {
         Settings.Global.putInt(mContext.getContentResolver(), SHOW_TEMPERATURE_WARNING, 1);
         TestableResources resources = mContext.getOrCreateTestableResources();
         resources.addOverride(R.integer.config_showTemperatureWarning, 0);
-        resources.addOverride(R.integer.config_warningTemperature, 55);
 
         mPowerUI.start();
-        // Guarantees mHandler has processed all messages.
+        mPowerUI.registerThermalEventListener();
+
         TestableLooper.get(this).processAllMessages();
-        verify(mMockWarnings).showHighTemperatureWarning();
+        verify(mThermalServiceMock, times(1))
+                .registerThermalEventListenerWithType(anyObject(), eq(Temperature.TYPE_SKIN));
     }
 
     @Test
-    public void testShutdownBasedThreshold() {
-        int tolerance = 2;
-        Settings.Global.putString(mContext.getContentResolver(), SHOW_TEMPERATURE_WARNING, null);
+    public void testSettingOverrideConfig_enableUsbTemperatureAlarm() throws Exception {
+        Settings.Global.putInt(mContext.getContentResolver(), SHOW_USB_TEMPERATURE_ALARM, 1);
         TestableResources resources = mContext.getOrCreateTestableResources();
-        resources.addOverride(R.integer.config_showTemperatureWarning, 1);
-        resources.addOverride(R.integer.config_warningTemperature, -1);
-        resources.addOverride(R.integer.config_warningTemperatureTolerance, tolerance);
-        when(mHardProps.getDeviceTemperatures(DEVICE_TEMPERATURE_SKIN, TEMPERATURE_SHUTDOWN))
-                .thenReturn(new float[] { 55 + tolerance });
+        resources.addOverride(R.integer.config_showUsbPortAlarm, 0);
 
-        setCurrentTemp(54); // Below threshold.
         mPowerUI.start();
-        verify(mMockWarnings, never()).showHighTemperatureWarning();
+        mPowerUI.registerThermalEventListener();
 
-        setCurrentTemp(56); // Above threshold.
-        mPowerUI.updateTemperatureWarning();
-        verify(mMockWarnings).showHighTemperatureWarning();
+        TestableLooper.get(this).processAllMessages();
+        verify(mThermalServiceMock, times(1))
+                .registerThermalEventListenerWithType(anyObject(), eq(Temperature.TYPE_USB_PORT));
     }
 
     @Test
@@ -532,17 +544,14 @@
         verify(mEnhancedEstimates, times(2)).getEstimate();
     }
 
-    private void setCurrentTemp(float temp) {
-        when(mHardProps.getDeviceTemperatures(DEVICE_TEMPERATURE_SKIN, TEMPERATURE_CURRENT))
-                .thenReturn(new float[] { temp });
+    private Temperature getEmergencyStatusTemp(int type, String name) {
+        final float value = 65;
+        return new Temperature(value, type, name, Temperature.THROTTLING_EMERGENCY);
     }
 
-    private void setOverThreshold() {
-        setCurrentTemp(50000);
-    }
-
-    private void setUnderThreshold() {
-        setCurrentTemp(5);
+    private Temperature getCriticalStatusTemp(int type, String name) {
+        final float value = 60;
+        return new Temperature(value, type, name, Temperature.THROTTLING_CRITICAL);
     }
 
     private void createPowerUi() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarInflaterViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarInflaterViewTest.java
new file mode 100644
index 0000000..093749a
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarInflaterViewTest.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
+import android.util.SparseArray;
+import android.view.View;
+import android.widget.FrameLayout;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.CommandQueue;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+/** atest NavigationBarInflaterViewTest */
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+@SmallTest
+public class NavigationBarInflaterViewTest extends SysuiTestCase {
+
+    private NavigationBarInflaterView mNavBarInflaterView;
+
+    private static final int BUTTON_ID = 0;
+
+    @Before
+    public void setUp() {
+        mContext.putComponent(CommandQueue.class, mock(CommandQueue.class));
+
+        mNavBarInflaterView = spy(new NavigationBarInflaterView(mContext, null));
+        doNothing().when(mNavBarInflaterView).createInflaters();
+
+        mNavBarInflaterView.mButtonDispatchers = new SparseArray<>(1);
+        mNavBarInflaterView.mButtonDispatchers.put(BUTTON_ID, new ButtonDispatcher(BUTTON_ID));
+
+        initializeViews();
+    }
+
+    private void initializeViews() {
+        mNavBarInflaterView.mVertical = mock(FrameLayout.class);
+        mNavBarInflaterView.mHorizontal = mock(FrameLayout.class);
+        initializeLayout(mNavBarInflaterView.mVertical);
+        initializeLayout(mNavBarInflaterView.mHorizontal);
+    }
+
+    private void initializeLayout(FrameLayout layout) {
+        View verticalChildView = mock(View.class);
+        verticalChildView.setId(BUTTON_ID);
+        doReturn(layout).when(verticalChildView).getParent();
+        doReturn(verticalChildView).when(layout).findViewById(BUTTON_ID);
+    }
+
+    @After
+    public void tearDown() {
+        mNavBarInflaterView = null;
+    }
+
+    @Test
+    public void testUpdateButtonDispatchersCurrentView_isVerticalTrue() {
+        mNavBarInflaterView.setVertical(true);
+
+        mNavBarInflaterView.updateButtonDispatchersCurrentView();
+
+        ButtonDispatcher button = mNavBarInflaterView.mButtonDispatchers.get(BUTTON_ID);
+        assertEquals("Buttons need to be set to vertical layout",
+                mNavBarInflaterView.mVertical.getId(),
+                ((View) button.getCurrentView().getParent()).getId());
+    }
+
+    @Test
+    public void testUpdateButtonDispatchersCurrentView_isVerticalFalse() {
+        mNavBarInflaterView.setVertical(false);
+
+        mNavBarInflaterView.updateButtonDispatchersCurrentView();
+
+        ButtonDispatcher button = mNavBarInflaterView.mButtonDispatchers.get(BUTTON_ID);
+        assertEquals("Buttons need to be set to horizon layout",
+                mNavBarInflaterView.mHorizontal.getId(),
+                ((View) button.getCurrentView().getParent()).getId());
+    }
+}
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 e4da859..f72d411 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
@@ -38,6 +38,7 @@
 import android.graphics.Color;
 import android.os.Handler;
 import android.os.Looper;
+import android.support.test.filters.FlakyTest;
 import android.support.test.filters.SmallTest;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
@@ -251,6 +252,7 @@
         assertScrimTint(mScrimBehind, false /* tinted */);
     }
 
+    @FlakyTest(bugId = 124858892)
     @Test
     public void transitionToUnlocked() {
         mScrimController.setPanelExpansion(0f);
@@ -295,6 +297,7 @@
         Assert.assertEquals(mScrimState, ScrimState.BOUNCER_SCRIMMED);
     }
 
+    @FlakyTest(bugId = 124858892)
     @Test
     public void panelExpansion() {
         mScrimController.setPanelExpansion(0f);
@@ -317,6 +320,7 @@
                 mScrimBehindAlpha, mScrimBehind.getViewAlpha(), 0.01f);
     }
 
+    @FlakyTest(bugId = 124858892)
     @Test
     public void panelExpansionAffectsAlpha() {
         mScrimController.setPanelExpansion(0f);
diff --git a/proto/Android.bp b/proto/Android.bp
index 817a54d..7f826b3 100644
--- a/proto/Android.bp
+++ b/proto/Android.bp
@@ -6,6 +6,7 @@
     },
     srcs: ["src/**/*.proto"],
     no_framework_libs: true,
+    sdk_version: "9",
     // Pin java_version until jarjar is certified to support later versions. http://b/72703434
     java_version: "1.8",
     target: {
diff --git a/proto/src/metrics_constants/metrics_constants.proto b/proto/src/metrics_constants/metrics_constants.proto
index 530d115..33555c4 100644
--- a/proto/src/metrics_constants/metrics_constants.proto
+++ b/proto/src/metrics_constants/metrics_constants.proto
@@ -247,6 +247,12 @@
     LOCATION_GONE = 6; // the view isn't laid out at all
   }
 
+  // Subtypes for profile logging
+  enum ActiveUserProfile {
+    PARENT_PROFILE = 1;
+    MANAGED_PROFILE = 2;
+  }
+
   // Known visual elements: views or controls.
   enum View {
     // Unknown view
@@ -6162,6 +6168,11 @@
     // OS: P
     FIELD_AUTOFILL_SESSION_ID = 1456;
 
+    // FIELD: Device USB overheat alarm trigger.
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: P
+    POWER_OVERHEAT_ALARM = 1457;
+
     // ---- End P Constants, all P constants go above this line ----
 
     // Time since this notification last interrupted (visibly or audible) the user
@@ -7002,6 +7013,10 @@
     // Different display can have different orientations, so need to log display id
     FIELD_DISPLAY_ID = 1660;
 
+    // ACTION: Changing from work to parent profile or vice versa
+    // OS: Q
+    ACTION_SWITCH_SHARE_PROFILE = 1661;
+
     // ---- End Q Constants, all Q constants go above this line ----
     // Add new aosp constants above this line.
     // END OF AOSP CONSTANTS
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index e0fb337..1cca813 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -30,6 +30,7 @@
 import android.annotation.UserIdInt;
 import android.app.ActivityManagerInternal;
 import android.app.ActivityThread;
+import android.content.AutofillOptions;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -699,12 +700,31 @@
         }
 
         @Override
-        public boolean isCompatibilityModeRequested(@NonNull String packageName,
+        public AutofillOptions getAutofillOptions(@NonNull String packageName,
                 long versionCode, @UserIdInt int userId) {
-            return mAutofillCompatState.isCompatibilityModeRequested(
+            final int loggingLevel;
+            if (verbose) {
+                loggingLevel = AutofillManager.FLAG_ADD_CLIENT_VERBOSE
+                        | AutofillManager.FLAG_ADD_CLIENT_DEBUG;
+            } else if (debug) {
+                loggingLevel = AutofillManager.FLAG_ADD_CLIENT_DEBUG;
+            } else {
+                loggingLevel = AutofillManager.NO_LOGGING;
+            }
+            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);
+                }
+            }
+
+            return options;
+        }
     }
 
     /**
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 15dce4a..364e537 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -28,6 +28,7 @@
 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;
@@ -1169,6 +1170,13 @@
         return mWhitelistedAugmentAutofillPackages.contains(packageName);
     }
 
+    @GuardedBy("mLock")
+    void setAugmentedAutofillWhitelistLocked(@NonNull AutofillOptions options,
+            @NonNull String packageName) {
+        // TODO(b/122595322): need to setwhitelisted activities as well.
+        options.augmentedEnabled = mWhitelistedAugmentAutofillPackages.contains(packageName);
+    }
+
     private void whitelistForAugmentedAutofillPackages(@NonNull List<String> packages) {
         // TODO(b/123100824): add CTS test for when it's null
         synchronized (mLock) {
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 915c131..ed459db 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1060,7 +1060,8 @@
             handleRegisterNetworkRequest(new NetworkRequestInfo(
                     null, networkRequest, new Binder()));
         } else {
-            handleReleaseNetworkRequest(networkRequest, Process.SYSTEM_UID);
+            handleReleaseNetworkRequest(networkRequest, Process.SYSTEM_UID,
+                    /* callOnUnavailable */ false);
         }
     }
 
@@ -2641,11 +2642,25 @@
             return true;
         }
 
+        private boolean maybeHandleNetworkFactoryMessage(Message msg) {
+            switch (msg.what) {
+                default:
+                    return false;
+                case NetworkFactory.EVENT_UNFULFILLABLE_REQUEST: {
+                    handleReleaseNetworkRequest((NetworkRequest) msg.obj, msg.sendingUid,
+                            /* callOnUnavailable */ true);
+                    break;
+                }
+            }
+            return true;
+        }
+
         @Override
         public void handleMessage(Message msg) {
-            if (!maybeHandleAsyncChannelMessage(msg) &&
-                    !maybeHandleNetworkMonitorMessage(msg) &&
-                    !maybeHandleNetworkAgentInfoMessage(msg)) {
+            if (!maybeHandleAsyncChannelMessage(msg)
+                    && !maybeHandleNetworkMonitorMessage(msg)
+                    && !maybeHandleNetworkAgentInfoMessage(msg)
+                    && !maybeHandleNetworkFactoryMessage(msg)) {
                 maybeHandleNetworkAgentMessage(msg);
             }
         }
@@ -2787,6 +2802,9 @@
         if (mNetworkFactoryInfos.containsKey(msg.replyTo)) {
             if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
                 if (VDBG) log("NetworkFactory connected");
+                // Finish setting up the full connection
+                mNetworkFactoryInfos.get(msg.replyTo).asyncChannel.sendMessage(
+                        AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
                 // A network factory has connected.  Send it all current NetworkRequests.
                 for (NetworkRequestInfo nri : mNetworkRequests.values()) {
                     if (nri.request.isListen()) continue;
@@ -2957,7 +2975,8 @@
         if (existingRequest != null) { // remove the existing request.
             if (DBG) log("Replacing " + existingRequest.request + " with "
                     + nri.request + " because their intents matched.");
-            handleReleaseNetworkRequest(existingRequest.request, getCallingUid());
+            handleReleaseNetworkRequest(existingRequest.request, getCallingUid(),
+                    /* callOnUnavailable */ false);
         }
         handleRegisterNetworkRequest(nri);
     }
@@ -2983,7 +3002,7 @@
             int callingUid) {
         NetworkRequestInfo nri = findExistingNetworkRequestInfo(pendingIntent);
         if (nri != null) {
-            handleReleaseNetworkRequest(nri.request, callingUid);
+            handleReleaseNetworkRequest(nri.request, callingUid, /* callOnUnavailable */ false);
         }
     }
 
@@ -3066,7 +3085,8 @@
         callCallbackForRequest(nri, null, ConnectivityManager.CALLBACK_UNAVAIL, 0);
     }
 
-    private void handleReleaseNetworkRequest(NetworkRequest request, int callingUid) {
+    private void handleReleaseNetworkRequest(NetworkRequest request, int callingUid,
+            boolean callOnUnavailable) {
         final NetworkRequestInfo nri =
                 getNriForAppRequest(request, callingUid, "release NetworkRequest");
         if (nri == null) {
@@ -3076,6 +3096,9 @@
             log("releasing " + nri.request + " (release request)");
         }
         handleRemoveNetworkRequest(nri);
+        if (callOnUnavailable) {
+            callCallbackForRequest(nri, null, ConnectivityManager.CALLBACK_UNAVAIL, 0);
+        }
     }
 
     private void handleRemoveNetworkRequest(final NetworkRequestInfo nri) {
@@ -3507,7 +3530,8 @@
                     break;
                 }
                 case EVENT_RELEASE_NETWORK_REQUEST: {
-                    handleReleaseNetworkRequest((NetworkRequest) msg.obj, msg.arg1);
+                    handleReleaseNetworkRequest((NetworkRequest) msg.obj, msg.arg1,
+                            /* callOnUnavailable */ false);
                     break;
                 }
                 case EVENT_SET_ACCEPT_UNVALIDATED: {
diff --git a/services/core/java/com/android/server/EventLogTags.logtags b/services/core/java/com/android/server/EventLogTags.logtags
index 0ed5beb..4d39f9a 100644
--- a/services/core/java/com/android/server/EventLogTags.logtags
+++ b/services/core/java/com/android/server/EventLogTags.logtags
@@ -145,7 +145,7 @@
 # ---------------------------
 # SystemServer.run() starts:
 3010 boot_progress_system_run (time|2|3)
-
+3011 system_server_start (start_count|1),(uptime|2|3),(elapse_time|2|3)
 
 # ---------------------------
 # PackageManagerService.java
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 7c46f1d..375c5c4 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -187,6 +187,7 @@
 import android.app.usage.UsageEvents;
 import android.app.usage.UsageStatsManagerInternal;
 import android.appwidget.AppWidgetManager;
+import android.content.AutofillOptions;
 import android.content.BroadcastReceiver;
 import android.content.ComponentCallbacks2;
 import android.content.ComponentName;
@@ -1486,6 +1487,8 @@
 
     private static String sTheRealBuildSerial = Build.UNKNOWN;
 
+    private ParcelFileDescriptor[] mLifeMonitorFds;
+
     final class UiHandler extends Handler {
         public UiHandler() {
             super(com.android.server.UiThread.get().getLooper(), null, true);
@@ -4741,12 +4744,12 @@
 
 
             // Figure out whether the app needs to run in autofill compat mode.
-            boolean isAutofillCompatEnabled = false;
+            AutofillOptions autofillOptions = null;
             if (UserHandle.getAppId(app.info.uid) >= Process.FIRST_APPLICATION_UID) {
                 final AutofillManagerInternal afm = LocalServices.getService(
                         AutofillManagerInternal.class);
                 if (afm != null) {
-                    isAutofillCompatEnabled = afm.isCompatibilityModeRequested(
+                    autofillOptions = afm.getAutofillOptions(
                             app.info.packageName, app.info.versionCode, app.userId);
                 }
             }
@@ -4779,7 +4782,7 @@
                         new Configuration(app.getWindowProcessController().getConfiguration()),
                         app.compat, getCommonServicesLocked(app.isolated),
                         mCoreSettingsObserver.getCoreSettingsLocked(),
-                        buildSerial, isAutofillCompatEnabled, contentCaptureOptions);
+                        buildSerial, autofillOptions, contentCaptureOptions);
             } else {
                 thread.bindApplication(processName, appInfo, providers, null, profilerInfo,
                         null, null, null, testMode,
@@ -4788,7 +4791,7 @@
                         new Configuration(app.getWindowProcessController().getConfiguration()),
                         app.compat, getCommonServicesLocked(app.isolated),
                         mCoreSettingsObserver.getCoreSettingsLocked(),
-                        buildSerial, isAutofillCompatEnabled, contentCaptureOptions);
+                        buildSerial, autofillOptions, contentCaptureOptions);
             }
             if (profilerInfo != null) {
                 profilerInfo.closeFd();
@@ -18500,4 +18503,24 @@
     private boolean isOnOffloadQueue(int flags) {
         return (mEnableOffloadQueue && ((flags & Intent.FLAG_RECEIVER_OFFLOAD) != 0));
     }
+
+    @Override
+    public ParcelFileDescriptor getLifeMonitor() {
+        if (!isCallerShell()) {
+            throw new SecurityException("Only shell can call it");
+        }
+        synchronized (this) {
+            try {
+                if (mLifeMonitorFds == null) {
+                    mLifeMonitorFds = ParcelFileDescriptor.createPipe();
+                }
+                // The returned FD will be closed, but we want to keep our reader open,
+                // so return a dup instead.
+                return mLifeMonitorFds[0].dup();
+            } catch (IOException e) {
+                Slog.w(TAG, "Unable to create pipe", e);
+                return null;
+            }
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 924018e..aa85c83 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -407,6 +407,10 @@
             return new SyntheticPasswordManager(getContext(), storage, getUserManager());
         }
 
+        public boolean hasBiometrics() {
+            return BiometricManager.hasBiometrics(mContext);
+        }
+
         public int binderGetCallingUid() {
             return Binder.getCallingUid();
         }
@@ -2434,7 +2438,7 @@
             notifyActivePasswordMetricsAvailable(userCredential, userId);
             unlockKeystore(authResult.authToken.deriveKeyStorePassword(), userId);
             // Reset lockout
-            if (BiometricManager.hasBiometrics(mContext)) {
+            if (mInjector.hasBiometrics()) {
                 BiometricManager bm = mContext.getSystemService(BiometricManager.class);
                 Slog.i(TAG, "Resetting lockout, length: "
                         + authResult.gkResponse.getPayload().length);
diff --git a/services/core/java/com/android/server/media/MediaSessionRecord.java b/services/core/java/com/android/server/media/MediaSessionRecord.java
index b221241..152cf7f 100644
--- a/services/core/java/com/android/server/media/MediaSessionRecord.java
+++ b/services/core/java/com/android/server/media/MediaSessionRecord.java
@@ -77,6 +77,7 @@
     private final int mUserId;
     private final String mPackageName;
     private final String mTag;
+    private final Bundle mSessionInfo;
     private final ControllerLink mController;
     private final MediaSession.Token mSessionToken;
     private final SessionLink mSession;
@@ -121,13 +122,14 @@
     private String mMetadataDescription;
 
     public MediaSessionRecord(int ownerPid, int ownerUid, int userId, String ownerPackageName,
-            SessionCallbackLink cb, String tag, MediaSessionService.ServiceImpl service,
-            Looper handlerLooper) {
+            SessionCallbackLink cb, String tag, Bundle sessionInfo,
+            MediaSessionService.ServiceImpl service, Looper handlerLooper) {
         mOwnerPid = ownerPid;
         mOwnerUid = ownerUid;
         mUserId = userId;
         mPackageName = ownerPackageName;
         mTag = tag;
+        mSessionInfo = sessionInfo;
         mController = new ControllerLink(new ControllerStub());
         mSessionToken = new MediaSession.Token(mController);
         mSession = new SessionLink(new SessionStub());
@@ -1309,6 +1311,11 @@
         }
 
         @Override
+        public Bundle getSessionInfo() {
+            return mSessionInfo;
+        }
+
+        @Override
         public PendingIntent getLaunchPendingIntent() {
             return mLaunchIntent;
         }
diff --git a/services/core/java/com/android/server/media/MediaSessionServiceImpl.java b/services/core/java/com/android/server/media/MediaSessionServiceImpl.java
index 62d9b20..b86328b 100644
--- a/services/core/java/com/android/server/media/MediaSessionServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaSessionServiceImpl.java
@@ -549,9 +549,11 @@
     }
 
     private MediaSessionRecord createSessionInternal(int callerPid, int callerUid, int userId,
-            String callerPackageName, SessionCallbackLink cb, String tag) throws RemoteException {
+            String callerPackageName, SessionCallbackLink cb, String tag, Bundle sessionInfo)
+            throws RemoteException {
         synchronized (mLock) {
-            return createSessionLocked(callerPid, callerUid, userId, callerPackageName, cb, tag);
+            return createSessionLocked(callerPid, callerUid, userId, callerPackageName, cb,
+                    tag, sessionInfo);
         }
     }
 
@@ -563,7 +565,7 @@
      * 4. It needs to be added to the relevant user record.
      */
     private MediaSessionRecord createSessionLocked(int callerPid, int callerUid, int userId,
-            String callerPackageName, SessionCallbackLink cb, String tag) {
+            String callerPackageName, SessionCallbackLink cb, String tag, Bundle sessionInfo) {
         FullUserRecord user = getFullUserRecordLocked(userId);
         if (user == null) {
             Log.w(TAG, "Request from invalid user: " +  userId + ", pkg=" + callerPackageName);
@@ -571,7 +573,7 @@
         }
 
         final MediaSessionRecord session = new MediaSessionRecord(callerPid, callerUid, userId,
-                callerPackageName, cb, tag, this, mHandler.getLooper());
+                callerPackageName, cb, tag, sessionInfo, this, mHandler.getLooper());
         try {
             cb.getBinder().linkToDeath(session, 0);
         } catch (RemoteException e) {
@@ -991,7 +993,7 @@
 
         @Override
         public SessionLink createSession(String packageName, SessionCallbackLink cb, String tag,
-                int userId) throws RemoteException {
+                Bundle sessionInfo, int userId) throws RemoteException {
             final int pid = Binder.getCallingPid();
             final int uid = Binder.getCallingUid();
             final long token = Binder.clearCallingIdentity();
@@ -1002,8 +1004,8 @@
                 if (cb == null) {
                     throw new IllegalArgumentException("Controller callback cannot be null");
                 }
-                return createSessionInternal(pid, uid, resolvedUserId, packageName, cb, tag)
-                        .getSessionBinder();
+                return createSessionInternal(pid, uid, resolvedUserId, packageName, cb, tag,
+                        sessionInfo).getSessionBinder();
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
diff --git a/services/core/java/com/android/server/notification/NotificationShellCmd.java b/services/core/java/com/android/server/notification/NotificationShellCmd.java
index 2aaa1ed..26cc0c1 100644
--- a/services/core/java/com/android/server/notification/NotificationShellCmd.java
+++ b/services/core/java/com/android/server/notification/NotificationShellCmd.java
@@ -16,6 +16,7 @@
 
 package com.android.server.notification;
 
+import android.app.ActivityManager;
 import android.app.INotificationManager;
 import android.app.Notification;
 import android.app.NotificationChannel;
@@ -49,12 +50,12 @@
     private static final String USAGE =
               "usage: cmd notification SUBCMD [args]\n\n"
             + "SUBCMDs:\n"
-            + "  allow_listener COMPONENT [user_id]\n"
-            + "  disallow_listener COMPONENT [user_id]\n"
-            + "  allow_assistant COMPONENT\n"
-            + "  remove_assistant COMPONENT\n"
-            + "  allow_dnd PACKAGE\n"
-            + "  disallow_dnd PACKAGE\n"
+            + "  allow_listener COMPONENT [user_id (current user if not specified)]\n"
+            + "  disallow_listener COMPONENT [user_id (current user if not specified)]\n"
+            + "  allow_assistant COMPONENT [user_id (current user if not specified)]\n"
+            + "  remove_assistant COMPONENT [user_id (current user if not specified)]\n"
+            + "  allow_dnd PACKAGE [user_id (current user if not specified)]\n"
+            + "  disallow_dnd PACKAGE [user_id (current user if not specified)]\n"
             + "  suspend_package PACKAGE\n"
             + "  unsuspend_package PACKAGE\n"
             + "  post [--help | flags] TAG TEXT";
@@ -109,14 +110,24 @@
         try {
             switch (cmd.replace('-', '_')) {
                 case "allow_dnd": {
-                    mBinderService.setNotificationPolicyAccessGranted(
-                            getNextArgRequired(), true);
+                    String packageName = getNextArgRequired();
+                    int userId = ActivityManager.getCurrentUser();
+                    if (peekNextArg() != null) {
+                        userId = Integer.parseInt(getNextArgRequired());
+                    }
+                    mBinderService.setNotificationPolicyAccessGrantedForUser(
+                            packageName, userId, true);
                 }
                 break;
 
                 case "disallow_dnd": {
-                    mBinderService.setNotificationPolicyAccessGranted(
-                            getNextArgRequired(), false);
+                    String packageName = getNextArgRequired();
+                    int userId = ActivityManager.getCurrentUser();
+                    if (peekNextArg() != null) {
+                        userId = Integer.parseInt(getNextArgRequired());
+                    }
+                    mBinderService.setNotificationPolicyAccessGrantedForUser(
+                            packageName, userId, false);
                 }
                 break;
                 case "allow_listener": {
@@ -125,13 +136,11 @@
                         pw.println("Invalid listener - must be a ComponentName");
                         return -1;
                     }
-                    String userId = getNextArg();
-                    if (userId == null) {
-                        mBinderService.setNotificationListenerAccessGranted(cn, true);
-                    } else {
-                        mBinderService.setNotificationListenerAccessGrantedForUser(
-                                cn, Integer.parseInt(userId), true);
+                    int userId = ActivityManager.getCurrentUser();
+                    if (peekNextArg() != null) {
+                        userId = Integer.parseInt(getNextArgRequired());
                     }
+                    mBinderService.setNotificationListenerAccessGrantedForUser(cn, userId, true);
                 }
                 break;
                 case "disallow_listener": {
@@ -140,13 +149,11 @@
                         pw.println("Invalid listener - must be a ComponentName");
                         return -1;
                     }
-                    String userId = getNextArg();
-                    if (userId == null) {
-                        mBinderService.setNotificationListenerAccessGranted(cn, false);
-                    } else {
-                        mBinderService.setNotificationListenerAccessGrantedForUser(
-                                cn, Integer.parseInt(userId), false);
+                    int userId = ActivityManager.getCurrentUser();
+                    if (peekNextArg() != null) {
+                        userId = Integer.parseInt(getNextArgRequired());
                     }
+                    mBinderService.setNotificationListenerAccessGrantedForUser(cn, userId, false);
                 }
                 break;
                 case "allow_assistant": {
@@ -155,7 +162,11 @@
                         pw.println("Invalid assistant - must be a ComponentName");
                         return -1;
                     }
-                    mBinderService.setNotificationAssistantAccessGranted(cn, true);
+                    int userId = ActivityManager.getCurrentUser();
+                    if (peekNextArg() != null) {
+                        userId = Integer.parseInt(getNextArgRequired());
+                    }
+                    mBinderService.setNotificationAssistantAccessGrantedForUser(cn, userId, true);
                 }
                 break;
                 case "disallow_assistant": {
@@ -164,7 +175,11 @@
                         pw.println("Invalid assistant - must be a ComponentName");
                         return -1;
                     }
-                    mBinderService.setNotificationAssistantAccessGranted(cn, false);
+                    int userId = ActivityManager.getCurrentUser();
+                    if (peekNextArg() != null) {
+                        userId = Integer.parseInt(getNextArgRequired());
+                    }
+                    mBinderService.setNotificationAssistantAccessGrantedForUser(cn, userId, false);
                 }
                 break;
                 case "suspend_package": {
@@ -176,6 +191,7 @@
                     // only use for testing
                     mDirectService.simulatePackageSuspendBroadcast(false, getNextArgRequired());
                 }
+                break;
                 case "distract_package": {
                     // only use for testing
                     // Flag values are in
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 2c47ec0..660309c 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -722,7 +722,8 @@
 
         if (!channel.equals(updatedChannel)) {
             // only log if there are real changes
-            MetricsLogger.action(getChannelLog(updatedChannel, pkg));
+            MetricsLogger.action(getChannelLog(updatedChannel, pkg)
+                    .setSubtype(fromUser ? 1 : 0));
         }
 
         if (updatedChannel.canBypassDnd() != mAreChannelsBypassingDnd
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index 62c4815..9e912843 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -20,7 +20,6 @@
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
-import android.app.AppDetailsActivity;
 import android.app.AppGlobals;
 import android.app.IApplicationThread;
 import android.app.PendingIntent;
@@ -367,7 +366,8 @@
         private ResolveInfo getHiddenAppActivityInfo(String packageName, int callingUid,
                 UserHandle user) {
             Intent intent = new Intent();
-            intent.setComponent(new ComponentName(packageName, AppDetailsActivity.class.getName()));
+            intent.setComponent(new ComponentName(packageName,
+                    PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME));
             final PackageManagerInternal pmInt =
                     LocalServices.getService(PackageManagerInternal.class);
             List<ResolveInfo> apps = pmInt.queryIntentActivities(intent,
diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java
index f06da49..bd74174 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerService.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerService.java
@@ -483,11 +483,12 @@
             }
         }
 
-        if (params.isStaged) {
+        boolean isApex = (params.installFlags & PackageManager.INSTALL_APEX) != 0;
+        if (params.isStaged || isApex) {
             mContext.enforceCallingOrSelfPermission(Manifest.permission.INSTALL_PACKAGES, TAG);
         }
 
-        if ((params.installFlags & PackageManager.INSTALL_APEX) != 0) {
+        if (isApex) {
             if (!mApexManager.isApexSupported()) {
                 throw new IllegalArgumentException(
                     "This device doesn't support the installation of APEX files");
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 1b71904..56ef33a 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -322,18 +322,7 @@
         public boolean handleMessage(Message msg) {
             switch (msg.what) {
                 case MSG_COMMIT:
-                    synchronized (mLock) {
-                        try {
-                            commitLocked();
-                        } catch (PackageManagerException e) {
-                            final String completeMsg = ExceptionUtils.getCompleteMessage(e);
-                            Slog.e(TAG,
-                                    "Commit of session " + sessionId + " failed: " + completeMsg);
-                            destroyInternal();
-                            dispatchSessionFinished(e.error, completeMsg, null);
-                        }
-                    }
-
+                    handleCommit();
                     break;
                 case MSG_ON_PACKAGE_INSTALLED:
                     final SomeArgs args = (SomeArgs) msg.obj;
@@ -1073,38 +1062,66 @@
         mCallback.onSessionSealedBlocking(this);
     }
 
-    @GuardedBy("mLock")
-    private void commitLocked()
-            throws PackageManagerException {
+    private void handleCommit() {
         if (params.isStaged) {
             mStagingManager.commitSession(this);
             destroyInternal();
             dispatchSessionFinished(PackageManager.INSTALL_SUCCEEDED, "Session staged", null);
             return;
         }
+
         if ((params.installFlags & PackageManager.INSTALL_APEX) != 0) {
-            throw new PackageManagerException(
-                PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
-                "APEX packages can only be installed using staged sessions.");
+            destroyInternal();
+            dispatchSessionFinished(PackageManager.INSTALL_FAILED_INTERNAL_ERROR,
+                    "APEX packages can only be installed using staged sessions.", null);
+            return;
         }
+
+        // For a multiPackage session, read the child sessions
+        // outside of the lock, because reading the child
+        // sessions with the lock held could lead to deadlock
+        // (b/123391593).
+        List<PackageInstallerSession> childSessions = null;
+        if (isMultiPackage()) {
+            final int[] childSessionIds = getChildSessionIds();
+            childSessions = new ArrayList<>(childSessionIds.length);
+            for (int childSessionId : childSessionIds) {
+                childSessions.add(mSessionProvider.getSession(childSessionId));
+            }
+        }
+
+        try {
+            synchronized (mLock) {
+                commitNonStagedLocked(childSessions);
+            }
+        } catch (PackageManagerException e) {
+            final String completeMsg = ExceptionUtils.getCompleteMessage(e);
+            Slog.e(TAG, "Commit of session " + sessionId + " failed: " + completeMsg);
+            destroyInternal();
+            dispatchSessionFinished(e.error, completeMsg, null);
+        }
+    }
+
+    @GuardedBy("mLock")
+    private void commitNonStagedLocked(List<PackageInstallerSession> childSessions)
+            throws PackageManagerException {
         final PackageManagerService.ActiveInstallSession committingSession =
                 makeSessionActiveLocked();
         if (committingSession == null) {
             return;
         }
         if (isMultiPackage()) {
-            final int[] childSessionIds = getChildSessionIds();
-            List<PackageManagerService.ActiveInstallSession> childSessions =
-                    new ArrayList<>(childSessionIds.length);
+            List<PackageManagerService.ActiveInstallSession> activeChildSessions =
+                    new ArrayList<>(childSessions.size());
             boolean success = true;
             PackageManagerException failure = null;
-            for (int childSessionId : getChildSessionIds()) {
-                final PackageInstallerSession session = mSessionProvider.getSession(childSessionId);
+            for (int i = 0; i < childSessions.size(); ++i) {
+                final PackageInstallerSession session = childSessions.get(i);
                 try {
                     final PackageManagerService.ActiveInstallSession activeSession =
                             session.makeSessionActiveLocked();
                     if (activeSession != null) {
-                        childSessions.add(activeSession);
+                        activeChildSessions.add(activeSession);
                     }
                 } catch (PackageManagerException e) {
                     failure = e;
@@ -1119,7 +1136,7 @@
                 }
                 return;
             }
-            mPm.installStage(childSessions);
+            mPm.installStage(activeChildSessions);
         } else {
             mPm.installStage(committingSession);
         }
@@ -1887,6 +1904,9 @@
                     false, true).rethrowAsRuntimeException();
         }
         synchronized (mLock) {
+            assertCallerIsOwnerOrRootLocked();
+            assertPreparedAndNotSealedLocked("addChildSessionId");
+
             final int indexOfSession = mChildSessionIds.indexOfKey(childSessionId);
             if (indexOfSession >= 0) {
                 return;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 07d460e..4bca5e0 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -121,7 +121,6 @@
 import android.annotation.UserIdInt;
 import android.app.ActivityManager;
 import android.app.ActivityManagerInternal;
-import android.app.AppDetailsActivity;
 import android.app.AppOpsManager;
 import android.app.BroadcastOptions;
 import android.app.IActivityManager;
@@ -4212,6 +4211,55 @@
         return -1;
     }
 
+    /**
+     * Check if any package sharing/holding a uid has a low enough target SDK.
+     *
+     * @param uid The uid of the packages
+     * @param higherTargetSDK The target SDK that might be higher than the searched package
+     *
+     * @return {@code true} if there is a package sharing/holding the uid with
+     * {@code package.targetSDK < higherTargetSDK}
+     */
+    private boolean hasTargetSdkInUidLowerThan(int uid, int higherTargetSDK) {
+        int userId = UserHandle.getUserId(uid);
+
+        synchronized (mPackages) {
+            Object obj = mSettings.getSettingLPr(UserHandle.getAppId(uid));
+            if (obj == null) {
+                return false;
+            }
+
+            if (obj instanceof PackageSetting) {
+                final PackageSetting ps = (PackageSetting) obj;
+
+                if (!ps.getInstalled(userId)) {
+                    return false;
+                }
+
+                return ps.pkg.applicationInfo.targetSdkVersion < higherTargetSDK;
+            } else if (obj instanceof SharedUserSetting) {
+                final SharedUserSetting sus = (SharedUserSetting) obj;
+
+                final int numPkgs = sus.packages.size();
+                for (int i = 0; i < numPkgs; i++) {
+                    final PackageSetting ps = sus.packages.valueAt(i);
+
+                    if (!ps.getInstalled(userId)) {
+                        continue;
+                    }
+
+                    if (ps.pkg.applicationInfo.targetSdkVersion < higherTargetSDK) {
+                        return true;
+                    }
+                }
+
+                return false;
+            } else {
+                return false;
+            }
+        }
+    }
+
     @Override
     public int[] getPackageGids(String packageName, int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
@@ -5280,13 +5328,21 @@
 
     @Override
     public void grantRuntimePermission(String packageName, String permName, final int userId) {
-        mPermissionManager.grantRuntimePermission(permName, packageName, false /*overridePolicy*/,
+        boolean overridePolicy = (checkUidPermission(
+                Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY, Binder.getCallingUid())
+                == PackageManager.PERMISSION_GRANTED);
+
+        mPermissionManager.grantRuntimePermission(permName, packageName, overridePolicy,
                 getCallingUid(), userId, mPermissionCallback);
     }
 
     @Override
     public void revokeRuntimePermission(String packageName, String permName, int userId) {
-        mPermissionManager.revokeRuntimePermission(permName, packageName, false /*overridePolicy*/,
+        boolean overridePolicy = (checkUidPermission(
+                Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY, Binder.getCallingUid())
+                == PackageManager.PERMISSION_GRANTED);
+
+        mPermissionManager.revokeRuntimePermission(permName, packageName, overridePolicy,
                 getCallingUid(), userId, mPermissionCallback);
     }
 
@@ -5329,10 +5385,37 @@
 
     @Override
     public void updatePermissionFlags(String permName, String packageName, int flagMask,
-            int flagValues, int userId) {
+            int flagValues, boolean checkAdjustPolicyFlagPermission, int userId) {
+        int callingUid = getCallingUid();
+        boolean overridePolicy = false;
+
+        if (callingUid != Process.SYSTEM_UID && callingUid != Process.ROOT_UID) {
+            long callingIdentity = Binder.clearCallingIdentity();
+            try {
+                if ((flagMask & FLAG_PERMISSION_POLICY_FIXED) != 0) {
+                    if (checkAdjustPolicyFlagPermission) {
+                        mContext.enforceCallingOrSelfPermission(
+                                Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY,
+                                "Need " + Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY
+                                        + " to change policy flags");
+                    } else if (!hasTargetSdkInUidLowerThan(callingUid, Build.VERSION_CODES.Q)) {
+                        throw new IllegalArgumentException(
+                                Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY + " needs "
+                                        + " to be checked for packages targeting "
+                                        + Build.VERSION_CODES.Q + " or later when changing policy "
+                                        + "flags");
+                    }
+
+                    overridePolicy = true;
+                }
+            } finally {
+                Binder.restoreCallingIdentity(callingIdentity);
+            }
+        }
+
         mPermissionManager.updatePermissionFlags(
-                permName, packageName, flagMask, flagValues, getCallingUid(), userId,
-                mPermissionCallback);
+                permName, packageName, flagMask, flagValues, callingUid, userId,
+                overridePolicy, mPermissionCallback);
     }
 
     /**
@@ -12867,8 +12950,14 @@
                 "setPackagesSuspendedAsUser");
 
         final int callingUid = Binder.getCallingUid();
-        if (callingUid != Process.ROOT_UID && callingUid != Process.SYSTEM_UID
-                && getPackageUid(callingPackage, 0, userId) != callingUid) {
+        final int packageUid = getPackageUid(callingPackage, 0, userId);
+        final boolean allowedCallingUid = callingUid == Process.ROOT_UID
+                || callingUid == Process.SYSTEM_UID;
+        final boolean allowedPackageUid = packageUid == callingUid;
+        final boolean allowedShell = callingUid == SHELL_UID
+                && UserHandle.isSameApp(packageUid, callingUid);
+
+        if (!allowedCallingUid && !allowedShell && !allowedPackageUid) {
             throw new SecurityException("Calling package " + callingPackage + " in user "
                     + userId + " does not belong to calling uid " + callingUid);
         }
@@ -19948,8 +20037,11 @@
 
     private @Nullable String getDocumenterPackageName() {
         final Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
+        intent.addCategory(Intent.CATEGORY_OPENABLE);
+        intent.setType("*/*");
+        final String resolvedType = intent.resolveTypeIfNeeded(mContext.getContentResolver());
 
-        final List<ResolveInfo> matches = queryIntentActivitiesInternal(intent, null,
+        final List<ResolveInfo> matches = queryIntentActivitiesInternal(intent, resolvedType,
                 MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE
                         | MATCH_DISABLED_COMPONENTS,
                 UserHandle.myUserId());
@@ -20104,13 +20196,9 @@
         }
         // Only allow apps with CHANGE_COMPONENT_ENABLED_STATE permission to change hidden
         // app details activity
-        if (AppDetailsActivity.class.getName().equals(className)) {
-            if (mContext.checkCallingOrSelfPermission(
-                    android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE)
-                    != PackageManager.PERMISSION_GRANTED) {
-                Slog.e(TAG, "Cannot disable a protected component: " + packageName);
-                return;
-            }
+        if (PackageManager.APP_DETAILS_ACTIVITY_CLASS_NAME.equals(className)
+                && !allowedByPermission) {
+            throw new SecurityException("Cannot disable a system-generated component");
         }
 
         synchronized (mPackages) {
@@ -22997,7 +23085,7 @@
         public void updatePermissionFlagsTEMP(String permName, String packageName, int flagMask,
                 int flagValues, int userId) {
             PackageManagerService.this.updatePermissionFlags(
-                    permName, packageName, flagMask, flagValues, userId);
+                    permName, packageName, flagMask, flagValues, true, userId);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index d0f192d..3744f68 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -1324,6 +1324,7 @@
 
     @Override
     public ParcelFileDescriptor getUserIcon(int targetUserId) {
+        checkManageUsersPermission("get user icon");
         String iconPath;
         synchronized (mPackagesLock) {
             UserInfo targetUserInfo = getUserInfoNoChecks(targetUserId);
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 6369179..93a3d0a 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -206,6 +206,11 @@
         // STOPSHIP(b/112545973): remove once feature enabled by default
         if (StorageManager.hasIsolatedStorage()) {
             MEDIA_AURAL_PERMISSIONS.add(Manifest.permission.READ_MEDIA_AUDIO);
+
+            // STOPSHIP(b/124466734): remove these manual grants once the legacy
+            // permission logic is unified with PermissionController
+            MEDIA_AURAL_PERMISSIONS.add(Manifest.permission.READ_EXTERNAL_STORAGE);
+            MEDIA_AURAL_PERMISSIONS.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
         }
     }
 
@@ -215,6 +220,11 @@
         if (StorageManager.hasIsolatedStorage()) {
             MEDIA_VISUAL_PERMISSIONS.add(Manifest.permission.READ_MEDIA_VIDEO);
             MEDIA_VISUAL_PERMISSIONS.add(Manifest.permission.READ_MEDIA_IMAGES);
+
+            // STOPSHIP(b/124466734): remove these manual grants once the legacy
+            // permission logic is unified with PermissionController
+            MEDIA_VISUAL_PERMISSIONS.add(Manifest.permission.READ_EXTERNAL_STORAGE);
+            MEDIA_VISUAL_PERMISSIONS.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
         }
     }
 
@@ -642,16 +652,10 @@
         // Location
         if (locationPackageNames != null) {
             for (String packageName : locationPackageNames) {
-                // STOPSHIP: remove this force-granting of legacy storage
-                // permissions once b/124466734 is resolved
-                final Set<String> storageWorkaround = new ArraySet<>();
-                storageWorkaround.add(Manifest.permission.READ_EXTERNAL_STORAGE);
-                storageWorkaround.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
-
                 grantPermissionsToSystemPackage(packageName, userId,
                         CONTACTS_PERMISSIONS, CALENDAR_PERMISSIONS, MICROPHONE_PERMISSIONS,
                         PHONE_PERMISSIONS, SMS_PERMISSIONS, CAMERA_PERMISSIONS,
-                        SENSORS_PERMISSIONS, STORAGE_PERMISSIONS, storageWorkaround);
+                        SENSORS_PERMISSIONS, STORAGE_PERMISSIONS, MEDIA_AURAL_PERMISSIONS);
                 grantSystemFixedPermissionsToSystemPackage(packageName, userId,
                         LOCATION_PERMISSIONS, ACTIVITY_RECOGNITION_PERMISSIONS);
             }
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 8df5a71..03da962 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -35,6 +35,7 @@
 import static android.content.pm.PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET;
+import static android.content.pm.PackageManager.MASK_PERMISSION_FLAGS;
 import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
 import static android.os.UserHandle.getAppId;
 import static android.os.UserHandle.getUid;
@@ -1031,7 +1032,8 @@
                                     updatedUserIds = ArrayUtils.appendInt(updatedUserIds, userId);
                                 }
 
-                                permissionsState.updatePermissionFlags(bp, userId, flags, flags);
+                                permissionsState.updatePermissionFlags(bp, userId,
+                                        MASK_PERMISSION_FLAGS, flags);
                             }
                         } break;
 
@@ -1081,7 +1083,8 @@
                                     updatedUserIds = ArrayUtils.appendInt(updatedUserIds, userId);
                                 }
 
-                                permissionsState.updatePermissionFlags(bp, userId, flags, flags);
+                                permissionsState.updatePermissionFlags(bp, userId,
+                                        MASK_PERMISSION_FLAGS, flags);
                             }
                         } break;
 
@@ -1198,29 +1201,23 @@
                         if ((flags & FLAG_PERMISSION_REVOKE_WHEN_REQUESTED) != 0) {
                             BasePermission bp = mSettings.getPermissionLocked(permission);
 
-                            ps.updatePermissionFlags(bp, userId,
-                                    FLAG_PERMISSION_REVOKE_WHEN_REQUESTED
-                                            | FLAG_PERMISSION_USER_FIXED | FLAG_PERMISSION_USER_SET,
-                                    0);
-                            updatedUserIds = ArrayUtils.appendInt(updatedUserIds,
-                                    userId);
+                            int flagsToRemove = FLAG_PERMISSION_REVOKE_WHEN_REQUESTED;
 
                             if ((flags & (FLAG_PERMISSION_GRANTED_BY_DEFAULT
                                     | FLAG_PERMISSION_POLICY_FIXED | FLAG_PERMISSION_SYSTEM_FIXED))
-                                    == 0) {
-                                if (supportsRuntimePermissions) {
-                                    int revokeResult = ps.revokeRuntimePermission(bp, userId);
-                                    if (revokeResult != PERMISSION_OPERATION_FAILURE) {
-                                        if (DEBUG_PERMISSIONS) {
-                                            Slog.i(TAG, "Revoking runtime permission "
-                                                    + permission + " for " + pkgName
-                                                    + " as it is now requested");
-                                        }
+                                    == 0 && supportsRuntimePermissions) {
+                                int revokeResult = ps.revokeRuntimePermission(bp, userId);
+                                if (revokeResult != PERMISSION_OPERATION_FAILURE) {
+                                    if (DEBUG_PERMISSIONS) {
+                                        Slog.i(TAG, "Revoking runtime permission "
+                                                + permission + " for " + pkgName
+                                                + " as it is now requested");
                                     }
-                                } else {
-                                    setAppOpMode(permission, pkg, userId, MODE_IGNORED);
                                 }
 
+                                flagsToRemove |=
+                                        FLAG_PERMISSION_USER_FIXED | FLAG_PERMISSION_USER_SET;
+
                                 List<String> fgPerms = mBackgroundPermissions.get(permission);
                                 if (fgPerms != null) {
                                     int numFgPerms = fgPerms.size();
@@ -1238,6 +1235,9 @@
                                     }
                                 }
                             }
+
+                            ps.updatePermissionFlags(bp, userId, flagsToRemove, 0);
+                            updatedUserIds = ArrayUtils.appendInt(updatedUserIds, userId);
                         }
                     }
                 }
@@ -1935,7 +1935,7 @@
                     if ((flags & PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED) != 0) {
                         updatePermissionFlags(permission, pkg.packageName,
                                 PackageManager.FLAG_PERMISSION_REVIEW_REQUIRED, 0, callingUid,
-                                userId, callback);
+                                userId, false, callback);
                     }
                 }
             }
@@ -2441,7 +2441,8 @@
     }
 
     private void updatePermissionFlags(String permName, String packageName, int flagMask,
-            int flagValues, int callingUid, int userId, PermissionCallback callback) {
+            int flagValues, int callingUid, int userId, boolean overridePolicy,
+            PermissionCallback callback) {
         if (!mUserManagerInt.exists(userId)) {
             return;
         }
@@ -2454,6 +2455,11 @@
                 false, // requirePermissionWhenSameUser
                 "updatePermissionFlags");
 
+        if ((flagMask & FLAG_PERMISSION_POLICY_FIXED) != 0 && !overridePolicy) {
+            throw new SecurityException("updatePermissionFlags requires "
+                    + Manifest.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY);
+        }
+
         // Only the system can change these flags and nothing else.
         if (callingUid != Process.SYSTEM_UID) {
             flagMask &= ~PackageManager.FLAG_PERMISSION_SYSTEM_FIXED;
@@ -2745,9 +2751,11 @@
         }
         @Override
         public void updatePermissionFlags(String permName, String packageName, int flagMask,
-                int flagValues, int callingUid, int userId, PermissionCallback callback) {
+                int flagValues, int callingUid, int userId, boolean overridePolicy,
+                PermissionCallback callback) {
             PermissionManagerService.this.updatePermissionFlags(
-                    permName, packageName, flagMask, flagValues, callingUid, userId, callback);
+                    permName, packageName, flagMask, flagValues, callingUid, userId,
+                    overridePolicy, callback);
         }
         @Override
         public boolean updatePermissionFlagsForAllApps(int flagMask, int flagValues, int callingUid,
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
index 1dd2408..305f165 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerServiceInternal.java
@@ -147,7 +147,7 @@
      */
     public abstract void updatePermissionFlags(@NonNull String permName,
             @NonNull String packageName, int flagMask, int flagValues, int callingUid, int userId,
-            @Nullable PermissionCallback callback);
+            boolean overridePolicy, @Nullable PermissionCallback callback);
     /**
      * Updates the flags for all applications by replacing the flags in the specified mask
      * with the provided flag values.
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index c87a81d..68dab34 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -2316,14 +2316,15 @@
         boolean allowWhenLocked = (win.isInputMethodWindow() || imeTarget == this)
                 && showImeOverKeyguard;
 
-        if (isKeyguardLocked() && isKeyguardOccluded()) {
+        final boolean isKeyguardShowing = mKeyguardDelegate.isShowing();
+
+        if (isKeyguardShowing && isKeyguardOccluded()) {
             // Show SHOW_WHEN_LOCKED windows if Keyguard is occluded.
             allowWhenLocked |= win.canShowWhenLocked()
                     // Show error dialogs over apps that are shown on lockscreen
                     || (attrs.privateFlags & PRIVATE_FLAG_SYSTEM_ERROR) != 0;
         }
 
-        boolean keyguardLocked = isKeyguardLocked();
         boolean hideDockDivider = attrs.type == TYPE_DOCK_DIVIDER
                 && !mWindowManagerInternal.isStackVisible(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
         // If AOD is showing, the IME should be hidden. However, sometimes the AOD is considered
@@ -2333,7 +2334,7 @@
         // now shown.
         final boolean hideIme = win.isInputMethodWindow()
                 && (mAodShowing || !mDefaultDisplayPolicy.isWindowManagerDrawComplete());
-        return (keyguardLocked && !allowWhenLocked && win.getDisplayId() == DEFAULT_DISPLAY)
+        return (isKeyguardShowing && !allowWhenLocked && win.getDisplayId() == DEFAULT_DISPLAY)
                 || hideDockDivider || hideIme;
     }
 
diff --git a/services/core/java/com/android/server/role/TEST_MAPPING b/services/core/java/com/android/server/role/TEST_MAPPING
index 0b967be..0d7bc14 100644
--- a/services/core/java/com/android/server/role/TEST_MAPPING
+++ b/services/core/java/com/android/server/role/TEST_MAPPING
@@ -7,11 +7,14 @@
                     "include-filter": "android.cts.statsd.atom.UidAtomTests#testRoleHolder"
                 }
             ]
-        }
-    ],
-    "postsubmit": [
+        },
         {
-            "name": "CtsRoleTestCases"
+            "name": "CtsRoleTestCases",
+            "options": [
+                {
+                    "exclude-annotation": "androidx.test.filters.FlakyTest"
+                }
+            ]
         }
     ]
 }
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index c14f126..11839a5 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -966,36 +966,45 @@
         }
 
         getHandler().post(() -> {
-            final RollbackData rollbackData = getRollbackForPackage(packageName);
-            for (int userId : userIds) {
-                if (rollbackData == null || !rollbackData.inProgress) {
-                    Log.e(TAG, "Request to restore userData for: " + packageName
-                                  + ", but no rollback in progress.");
-                    continue;
-                }
-                final PackageRollbackInfo info = getPackageRollbackInfo(rollbackData, packageName);
-                final boolean changedRollbackData = mAppDataRollbackHelper.restoreAppData(
-                        rollbackData.rollbackId, info, userId, appId, seInfo);
-
-                // We've updated metadata about this rollback, so save it to flash.
-                if (changedRollbackData) {
-                    try {
-                        mRollbackStore.saveAvailableRollback(rollbackData);
-                    } catch (IOException ioe) {
-                        // TODO(narayan): What is the right thing to do here ? This isn't a fatal
-                        // error, since it will only result in us trying to restore data again,
-                        // which will be a no-op if there's no data available.
-                        Log.e(TAG, "Unable to save available rollback: " + packageName, ioe);
-                    }
-                }
-            }
-
+            restoreUserDataInternal(packageName, userIds, appId, ceDataInode, seInfo, token);
             final PackageManagerInternal pmi = LocalServices.getService(
                     PackageManagerInternal.class);
             pmi.finishPackageInstall(token, false);
         });
     }
 
+    private void restoreUserDataInternal(String packageName, int[] userIds, int appId,
+            long ceDataInode, String seInfo, int token) {
+        final RollbackData rollbackData = getRollbackForPackage(packageName);
+        if (rollbackData == null) {
+            return;
+        }
+
+        if (!rollbackData.inProgress) {
+            Log.e(TAG, "Request to restore userData for: " + packageName
+                    + ", but no rollback in progress.");
+            return;
+        }
+
+        for (int userId : userIds) {
+            final PackageRollbackInfo info = getPackageRollbackInfo(rollbackData, packageName);
+            final boolean changedRollbackData = mAppDataRollbackHelper.restoreAppData(
+                    rollbackData.rollbackId, info, userId, appId, seInfo);
+
+            // We've updated metadata about this rollback, so save it to flash.
+            if (changedRollbackData) {
+                try {
+                    mRollbackStore.saveAvailableRollback(rollbackData);
+                } catch (IOException ioe) {
+                    // TODO(narayan): What is the right thing to do here ? This isn't a fatal
+                    // error, since it will only result in us trying to restore data again,
+                    // which will be a no-op if there's no data available.
+                    Log.e(TAG, "Unable to save available rollback: " + packageName, ioe);
+                }
+            }
+        }
+    }
+
     @Override
     public boolean notifyStagedSession(int sessionId) {
         final LinkedBlockingQueue<Boolean> result = new LinkedBlockingQueue<>();
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index 9ea819e..9f04166 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -46,6 +46,7 @@
 import static android.content.Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED;
 import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS;
 import static android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP;
+import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
 import static android.content.pm.ActivityInfo.DOCUMENT_LAUNCH_ALWAYS;
 import static android.content.pm.ActivityInfo.LAUNCH_MULTIPLE;
 import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
@@ -1457,6 +1458,14 @@
                 // This task was started because of movement of the activity based on affinity...
                 // Now that we are actually launching it, we can assign the base intent.
                 reusedActivity.getTaskRecord().setIntent(mStartActivity);
+            } else {
+                final boolean taskOnHome =
+                        (mStartActivity.intent.getFlags() & FLAG_ACTIVITY_TASK_ON_HOME) != 0;
+                if (taskOnHome) {
+                    reusedActivity.getTaskRecord().intent.addFlags(FLAG_ACTIVITY_TASK_ON_HOME);
+                } else {
+                    reusedActivity.getTaskRecord().intent.removeFlags(FLAG_ACTIVITY_TASK_ON_HOME);
+                }
             }
 
             // This code path leads to delivering a new intent, we want to make sure we schedule it
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index 84cd8d1..2d5c97f 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -257,7 +257,7 @@
         mOriginalWidth = originalWidth;
         mOriginalHeight = originalHeight;
 
-        final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+        final SurfaceControl.Transaction t = mService.mTransactionFactory.make();
         try {
             mSurfaceControl = displayContent.makeOverlay()
                     .setName("ScreenshotSurface")
@@ -267,13 +267,13 @@
 
             // In case display bounds change, screenshot buffer and surface may mismatch so set a
             // scaling mode.
-            SurfaceControl.Transaction t2 = new SurfaceControl.Transaction();
+            SurfaceControl.Transaction t2 = mService.mTransactionFactory.make();
             t2.setOverrideScalingMode(mSurfaceControl, Surface.SCALING_MODE_SCALE_TO_WINDOW);
             t2.apply(true /* sync */);
 
             // Capture a screenshot into the surface we just created.
             final int displayId = display.getDisplayId();
-            final Surface surface = new Surface();
+            final Surface surface = mService.mSurfaceFactory.make();
             surface.copyFrom(mSurfaceControl);
             if (mService.mDisplayManagerInternal.screenshot(displayId, surface)) {
                 t.setLayer(mSurfaceControl, SCREEN_FREEZE_LAYER_SCREENSHOT);
diff --git a/services/core/java/com/android/server/wm/SurfaceFactory.java b/services/core/java/com/android/server/wm/SurfaceFactory.java
new file mode 100644
index 0000000..076b7df
--- /dev/null
+++ b/services/core/java/com/android/server/wm/SurfaceFactory.java
@@ -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.
+ */
+
+package com.android.server.wm;
+
+import android.view.Surface;
+
+/**
+ * Helper class to inject custom {@link Surface} objects into window manager.
+ */
+interface SurfaceFactory {
+    Surface make();
+};
+
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 74fb3fa..dddc6b7 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -50,6 +50,7 @@
 import android.view.WindowManager;
 import android.view.animation.Animation;
 
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ToBooleanFunction;
 
 import java.io.PrintWriter;
@@ -700,24 +701,37 @@
         mWallpaperTokens.remove(token);
     }
 
+
+    @VisibleForTesting
+    boolean canScreenshotWallpaper() {
+        return canScreenshotWallpaper(getTopVisibleWallpaper());
+    }
+
+    private boolean canScreenshotWallpaper(WindowState wallpaperWindowState) {
+        if (!mService.mPolicy.isScreenOn()) {
+            if (DEBUG_SCREENSHOT) {
+                Slog.i(TAG_WM, "Attempted to take screenshot while display was off.");
+            }
+            return false;
+        }
+
+        if (wallpaperWindowState == null) {
+            if (DEBUG_SCREENSHOT) {
+                Slog.i(TAG_WM, "No visible wallpaper to screenshot");
+            }
+            return false;
+        }
+        return true;
+    }
+
     /**
      * Take a screenshot of the wallpaper if it's visible.
      *
      * @return Bitmap of the wallpaper
      */
     Bitmap screenshotWallpaperLocked() {
-        if (!mService.mPolicy.isScreenOn()) {
-            if (DEBUG_SCREENSHOT) {
-                Slog.i(TAG_WM, "Attempted to take screenshot while display was off.");
-            }
-            return null;
-        }
-
         final WindowState wallpaperWindowState = getTopVisibleWallpaper();
-        if (wallpaperWindowState == null) {
-            if (DEBUG_SCREENSHOT) {
-                Slog.i(TAG_WM, "No visible wallpaper to screenshot");
-            }
+        if (!canScreenshotWallpaper(wallpaperWindowState)) {
             return null;
         }
 
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 7efd1a7..e19c7c6 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -209,6 +209,7 @@
 import android.view.IWindowSessionCallback;
 import android.view.InputChannel;
 import android.view.InputDevice;
+import android.view.InputEvent;
 import android.view.InputEventReceiver;
 import android.view.InsetsState;
 import android.view.KeyEvent;
@@ -814,8 +815,9 @@
 
     SurfaceBuilderFactory mSurfaceBuilderFactory = SurfaceControl.Builder::new;
     TransactionFactory mTransactionFactory = SurfaceControl.Transaction::new;
+    SurfaceFactory mSurfaceFactory = Surface::new;
 
-    private final SurfaceControl.Transaction mTransaction = mTransactionFactory.make();
+    private final SurfaceControl.Transaction mTransaction;
 
     static void boostPriorityForLockedSection() {
         sThreadPriorityBooster.boost();
@@ -909,9 +911,21 @@
     public static WindowManagerService main(final Context context, final InputManagerService im,
             final boolean showBootMsgs, final boolean onlyCore, WindowManagerPolicy policy,
             ActivityTaskManagerService atm) {
+        return main(context, im, showBootMsgs, onlyCore, policy, atm,
+                SurfaceControl.Transaction::new);
+    }
+
+    /**
+     * Creates and returns an instance of the WindowManagerService. This call allows the caller
+     * to override the {@link TransactionFactory} to stub functionality under test.
+     */
+    @VisibleForTesting
+    public static WindowManagerService main(final Context context, final InputManagerService im,
+            final boolean showBootMsgs, final boolean onlyCore, WindowManagerPolicy policy,
+            ActivityTaskManagerService atm, TransactionFactory transactionFactory) {
         DisplayThread.getHandler().runWithScissors(() ->
                 sInstance = new WindowManagerService(context, im, showBootMsgs, onlyCore, policy,
-                        atm), 0);
+                        atm, transactionFactory), 0);
         return sInstance;
     }
 
@@ -933,7 +947,7 @@
 
     private WindowManagerService(Context context, InputManagerService inputManager,
             boolean showBootMsgs, boolean onlyCore, WindowManagerPolicy policy,
-            ActivityTaskManagerService atm) {
+            ActivityTaskManagerService atm, TransactionFactory transactionFactory) {
         installLock(this, INDEX_WINDOW);
         mGlobalLock = atm.getGlobalLock();
         mAtmService = atm;
@@ -962,6 +976,9 @@
         mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
         mDisplayWindowSettings = new DisplayWindowSettings(this);
 
+
+        mTransactionFactory = transactionFactory;
+        mTransaction = mTransactionFactory.make();
         mPolicy = policy;
         mAnimator = new WindowAnimator(this);
         mRoot = new RootWindowContainer(this);
@@ -7404,4 +7421,16 @@
             }
         }
     }
+
+    @Override
+    public boolean injectInputAfterTransactionsApplied(InputEvent ev, int mode) {
+        synchronized (mGlobalLock) {
+            mWindowPlacerLocked.performSurfacePlacementIfScheduled();
+            new SurfaceControl.Transaction()
+                    .syncInputWindows()
+                    .apply(true);
+        }
+
+        return mInputManager.injectInputEvent(ev, mode);
+    }
 }
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 2ee58fe..cc791787 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -85,6 +85,12 @@
         return mDeferDepth > 0;
     }
 
+    void performSurfacePlacementIfScheduled() {
+        if (mTraversalScheduled) {
+            performSurfacePlacement();
+        }
+    }
+
     final void performSurfacePlacement() {
         performSurfacePlacement(false /* force */);
     }
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index d178c3a..fe94168 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -2248,7 +2248,7 @@
             measCorrClass, "getToaGpsNanosecondsOfWeek", "()J");
 
         method_correctionsGetSingleSatCorrectionList = env->GetMethodID(
-            measCorrClass, "getSingleSatCorrectionList", "()Ljava.util.List;");
+            measCorrClass, "getSingleSatelliteCorrectionList", "()Ljava.util.List;");
     }
 
     jdouble latitudeDegreesCorr = env->CallDoubleMethod(
@@ -2285,15 +2285,15 @@
         if (firstGnssMeasurementCorrectionInjected == false) {
             jclass singleSatCorrClass = env->GetObjectClass(singleSatCorrectionObj);
             method_correctionSatFlags = env->GetMethodID(
-                singleSatCorrClass, "getSingleSatCorrectionFlags", "()I");
+                singleSatCorrClass, "getSingleSatelliteCorrectionFlags", "()I");
             method_correctionSatConstType = env->GetMethodID(
                 singleSatCorrClass, "getConstellationType", "()I");
             method_correctionSatId= env->GetMethodID(
-                singleSatCorrClass, "getSatId", "()I");
+                singleSatCorrClass, "getSatelliteId", "()I");
             method_correctionSatCarrierFreq = env->GetMethodID(
                 singleSatCorrClass, "getCarrierFrequencyHz", "()F");
             method_correctionSatIsLosProb = env->GetMethodID(
-                singleSatCorrClass,"getProbSatIsLos", "()F");
+                singleSatCorrClass,"getProbabilityLineOfSight", "()F");
             method_correctionSatEpl = env->GetMethodID(
                 singleSatCorrClass, "getExcessPathLengthMeters", "()F");
             method_correctionSatEplUnc = env->GetMethodID(
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index ae48dad..3070488 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -134,6 +134,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.PermissionChecker;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageDataObserver;
@@ -171,6 +172,7 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.ParcelFileDescriptor;
+import android.os.ParcelableException;
 import android.os.PersistableBundle;
 import android.os.PowerManager;
 import android.os.PowerManagerInternal;
@@ -187,6 +189,7 @@
 import android.os.UserManagerInternal;
 import android.os.UserManagerInternal.UserRestrictionsListener;
 import android.os.storage.StorageManager;
+import android.permission.PermissionControllerManager;
 import android.provider.CalendarContract;
 import android.provider.ContactsContract.QuickContact;
 import android.provider.ContactsInternal;
@@ -1890,6 +1893,21 @@
             return LocalServices.getService(ActivityTaskManagerInternal.class);
         }
 
+        @NonNull PermissionControllerManager getPermissionControllerManager(
+                @NonNull UserHandle user) {
+            if (user.equals(mContext.getUser())) {
+                return mContext.getSystemService(PermissionControllerManager.class);
+            } else {
+                try {
+                    return mContext.createPackageContextAsUser(mContext.getPackageName(), 0,
+                            user).getSystemService(PermissionControllerManager.class);
+                } catch (NameNotFoundException notPossible) {
+                    // not possible
+                    throw new IllegalStateException(notPossible);
+                }
+            }
+        }
+
         UsageStatsManagerInternal getUsageStatsManagerInternal() {
             return LocalServices.getService(UsageStatsManagerInternal.class);
         }
@@ -11582,8 +11600,11 @@
     }
 
     @Override
-    public boolean setPermissionGrantState(ComponentName admin, String callerPackage,
-            String packageName, String permission, int grantState) throws RemoteException {
+    public void setPermissionGrantState(ComponentName admin, String callerPackage,
+            String packageName, String permission, int grantState, RemoteCallback callback)
+            throws RemoteException {
+        Preconditions.checkNotNull(callback);
+
         UserHandle user = mInjector.binderGetCallingUserHandle();
         synchronized (getLockObject()) {
             // Ensure the caller is a DO/PO or a permission grant state delegate.
@@ -11591,53 +11612,60 @@
                     DELEGATION_PERMISSION_GRANT);
             long ident = mInjector.binderClearCallingIdentity();
             try {
-                if (getTargetSdk(packageName, user.getIdentifier())
-                        < android.os.Build.VERSION_CODES.M) {
-                    return false;
+                boolean isPostQAdmin = getTargetSdk(callerPackage, user.getIdentifier())
+                        >= android.os.Build.VERSION_CODES.Q;
+                if (!isPostQAdmin) {
+                    // Legacy admins assume that they cannot control pre-M apps
+                    if (getTargetSdk(packageName, user.getIdentifier())
+                            < android.os.Build.VERSION_CODES.M) {
+                        callback.sendResult(null);
+                        return;
+                    }
                 }
-                if (!isRuntimePermission(permission)) {
-                    return false;
+                try {
+                    if (!isRuntimePermission(permission)) {
+                        callback.sendResult(null);
+                        return;
+                    }
+                } catch (NameNotFoundException e) {
+                    throw new RemoteException(
+                            "Cannot check if " + permission + "is a runtime permission", e, false,
+                            true);
                 }
-                final PackageManager packageManager = mInjector.getPackageManager();
-                switch (grantState) {
-                    case DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED: {
-                        mInjector.getPackageManagerInternal().grantRuntimePermission(packageName,
-                                permission, user.getIdentifier(), true /* override policy */);
-                        packageManager.updatePermissionFlags(permission, packageName,
-                                PackageManager.FLAG_PERMISSION_POLICY_FIXED,
-                                PackageManager.FLAG_PERMISSION_POLICY_FIXED, user);
-                    } break;
 
-                    case DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED: {
-                        mInjector.getPackageManagerInternal().revokeRuntimePermission(packageName,
-                                permission, user.getIdentifier(), true /* override policy */);
-                        packageManager.updatePermissionFlags(permission, packageName,
-                                PackageManager.FLAG_PERMISSION_POLICY_FIXED,
-                                PackageManager.FLAG_PERMISSION_POLICY_FIXED, user);
-                    } break;
+                if (grantState == DevicePolicyManager.PERMISSION_GRANT_STATE_GRANTED
+                        || grantState == DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED
+                        || grantState == DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT) {
+                    mInjector.getPermissionControllerManager(user)
+                            .setRuntimePermissionGrantStateByDeviceAdmin(callerPackage,
+                                    packageName, permission, grantState, mContext.getMainExecutor(),
+                                    (permissionWasSet) -> {
+                                        if (isPostQAdmin && !permissionWasSet) {
+                                            callback.sendResult(null);
+                                            return;
+                                        }
 
-                    case DevicePolicyManager.PERMISSION_GRANT_STATE_DEFAULT: {
-                        packageManager.updatePermissionFlags(permission, packageName,
-                                PackageManager.FLAG_PERMISSION_POLICY_FIXED, 0, user);
-                    } break;
+                                        final boolean isDelegate = (admin == null);
+                                        DevicePolicyEventLogger
+                                                .createEvent(DevicePolicyEnums
+                                                        .SET_PERMISSION_GRANT_STATE)
+                                                .setAdmin(callerPackage)
+                                                .setStrings(permission)
+                                                .setInt(grantState)
+                                                .setBoolean(isDelegate)
+                                                .write();
+
+                                        callback.sendResult(Bundle.EMPTY);
+                                    });
                 }
-            } catch (SecurityException se) {
-                return false;
-            } catch (NameNotFoundException e) {
-                return false;
+            } catch (SecurityException e) {
+                Slog.e(LOG_TAG, "Could not set permission grant state", e);
+
+                callback.sendResult(null);
             } finally {
                 mInjector.binderRestoreCallingIdentity(ident);
             }
         }
-        final boolean isDelegate = (admin == null);
-        DevicePolicyEventLogger
-                .createEvent(DevicePolicyEnums.SET_PERMISSION_GRANT_STATE)
-                .setAdmin(callerPackage)
-                .setStrings(permission)
-                .setInt(grantState)
-                .setBoolean(isDelegate)
-                .write();
-        return true;
     }
 
     @Override
@@ -11654,8 +11682,26 @@
         synchronized (getLockObject()) {
             long ident = mInjector.binderClearCallingIdentity();
             try {
-                int granted = mIPackageManager.checkPermission(permission,
-                        packageName, user.getIdentifier());
+                int granted;
+                if (getTargetSdk(callerPackage, user.getIdentifier())
+                        < android.os.Build.VERSION_CODES.Q) {
+                    // The per-Q behavior was to not check the app-ops state.
+                    granted = mIPackageManager.checkPermission(permission, packageName,
+                            user.getIdentifier());
+                } else {
+                    try {
+                        int uid = packageManager.getPackageUidAsUser(packageName,
+                                user.getIdentifier());
+
+                        // TODO: Prevent noting the app-op
+                        granted = PermissionChecker.checkPermission(mContext, permission, -1,
+                                uid, packageName);
+                    } catch (NameNotFoundException e) {
+                        throw new RemoteException(
+                                "Cannot check if " + permission + "is a runtime permission", e,
+                                false, true);
+                    }
+                }
                 int permFlags = packageManager.getPermissionFlags(permission, packageName, user);
                 if ((permFlags & PackageManager.FLAG_PERMISSION_POLICY_FIXED)
                         != PackageManager.FLAG_PERMISSION_POLICY_FIXED) {
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 4700b96..8d88c5a 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -310,6 +310,7 @@
 
     private boolean mOnlyCore;
     private boolean mFirstBoot;
+    private final int mStartCount;
     private final boolean mRuntimeRestart;
     private final long mRuntimeStartElapsedTime;
     private final long mRuntimeStartUptime;
@@ -317,6 +318,9 @@
     private static final String START_SENSOR_SERVICE = "StartSensorService";
     private static final String START_HIDL_SERVICES = "StartHidlServices";
 
+    private static final String SYSPROP_START_COUNT = "sys.system_server.start_count";
+    private static final String SYSPROP_START_ELAPSED = "sys.system_server.start_elapsed";
+    private static final String SYSPROP_START_UPTIME = "sys.system_server.start_uptime";
 
     private Future<?> mSensorServiceStart;
     private Future<?> mZygotePreload;
@@ -346,16 +350,33 @@
     public SystemServer() {
         // Check for factory test mode.
         mFactoryTestMode = FactoryTest.getMode();
-        // Remember if it's runtime restart(when sys.boot_completed is already set) or reboot
-        mRuntimeRestart = "1".equals(SystemProperties.get("sys.boot_completed"));
 
+        // Record process start information.
+        // Note SYSPROP_START_COUNT will increment by *2* on a FDE device when it fully boots;
+        // one for the password screen, second for the actual boot.
+        mStartCount = SystemProperties.getInt(SYSPROP_START_COUNT, 0) + 1;
         mRuntimeStartElapsedTime = SystemClock.elapsedRealtime();
         mRuntimeStartUptime = SystemClock.uptimeMillis();
+
+        // Remember if it's runtime restart(when sys.boot_completed is already set) or reboot
+        // We don't use "mStartCount > 1" here because it'll be wrong on a FDE device.
+        // TODO: mRuntimeRestart will *not* be set to true if the proccess crashes before
+        // sys.boot_completed is set. Fix it.
+        mRuntimeRestart = "1".equals(SystemProperties.get("sys.boot_completed"));
     }
 
     private void run() {
         try {
             traceBeginAndSlog("InitBeforeStartServices");
+
+            // Record the process start information in sys props.
+            SystemProperties.set(SYSPROP_START_COUNT, String.valueOf(mStartCount));
+            SystemProperties.set(SYSPROP_START_ELAPSED, String.valueOf(mRuntimeStartElapsedTime));
+            SystemProperties.set(SYSPROP_START_UPTIME, String.valueOf(mRuntimeStartUptime));
+
+            EventLog.writeEvent(EventLogTags.SYSTEM_SERVER_START,
+                    mStartCount, mRuntimeStartUptime, mRuntimeStartElapsedTime);
+
             // If a device's clock is before 1970 (before 0), a lot of
             // APIs crash dealing with negative numbers, notably
             // java.io.File#setLastModified, so instead we fake it and
diff --git a/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java b/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java
index 5cb6cbb..26b1224 100644
--- a/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java
+++ b/services/tests/servicestests/src/com/android/server/backup/testutils/IPackageManagerStub.java
@@ -213,7 +213,8 @@
 
     @Override
     public void updatePermissionFlags(String permissionName, String packageName, int flagMask,
-        int flagValues, int userId) throws RemoteException {
+            int flagValues, boolean checkAdjustPolicyFlagPermission, int userId)
+            throws RemoteException {
 
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
index 74d4739..bf71318 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
@@ -106,6 +106,11 @@
         }
 
         @Override
+        public boolean hasBiometrics() {
+            return false;
+        }
+
+        @Override
         public int binderGetCallingUid() {
             return Process.SYSTEM_UID;
         }
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
index 2627ec7..c072d4e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppChangeTransitionTests.java
@@ -59,8 +59,7 @@
     public void setUpOnDisplay(DisplayContent dc) {
         mStack = createTaskStackOnDisplay(WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, dc);
         mTask = createTaskInStack(mStack, 0 /* userId */);
-        mToken = WindowTestUtils.createTestAppWindowToken(dc);
-        mToken.mSkipOnParentChanged = false;
+        mToken = WindowTestUtils.createTestAppWindowToken(dc, false /* skipOnParentChanged */);
 
         mTask.addChild(mToken, 0);
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
index afadc79..b91f3ec 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java
@@ -55,8 +55,11 @@
 
     @Before
     public void setUp() throws Exception {
-        spyOn(mWm.mRoot);
-        doNothing().when(mWm.mRoot).performSurfacePlacement(anyBoolean());
+        synchronized (mWm.mGlobalLock) {
+            // Hold the lock to protect the stubbing from being accessed by other threads.
+            spyOn(mWm.mRoot);
+            doNothing().when(mWm.mRoot).performSurfacePlacement(anyBoolean());
+        }
         mDc = mWm.getDefaultDisplayContentLocked();
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java
index 108ee180b..e007c86 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java
@@ -18,7 +18,6 @@
 
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.view.SurfaceControl.Transaction;
 
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
 
@@ -30,6 +29,9 @@
 import android.platform.test.annotations.Presubmit;
 import android.view.SurfaceControl;
 
+import androidx.test.filters.FlakyTest;
+import androidx.test.filters.SmallTest;
+
 import com.android.server.wm.WindowTestUtils.TestAppWindowToken;
 
 import org.junit.Before;
@@ -38,8 +40,6 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
-import androidx.test.filters.FlakyTest;
-import androidx.test.filters.SmallTest;
 
 /**
  * Animation related tests for the {@link AppWindowToken} class.
@@ -55,8 +55,6 @@
     private TestAppWindowToken mToken;
 
     @Mock
-    private Transaction mTransaction;
-    @Mock
     private AnimationAdapter mSpec;
 
     @Before
@@ -65,7 +63,6 @@
 
         mToken = createTestAppWindowToken(mDisplayContent, WINDOWING_MODE_FULLSCREEN,
                 ACTIVITY_TYPE_STANDARD, false /* skipOnParentChanged */);
-        mToken.setPendingTransaction(mTransaction);
     }
 
     @Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
index 1dd72ec..2c575f5 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java
@@ -60,7 +60,7 @@
  * Tests for the {@link AppWindowToken} class.
  *
  * Build/Install/Run:
- *  atest FrameworksServicesTests:AppWindowTokenTests
+ *  atest WmTests:AppWindowTokenTests
  */
 @SmallTest
 @Presubmit
@@ -76,9 +76,9 @@
     public void setUp() throws Exception {
         mStack = createTaskStackOnDisplay(mDisplayContent);
         mTask = createTaskInStack(mStack, 0 /* userId */);
-        mToken = WindowTestUtils.createTestAppWindowToken(mDisplayContent);
+        mToken = WindowTestUtils.createTestAppWindowToken(mDisplayContent,
+                false /* skipOnParentChanged */);
 
-        mToken.mSkipOnParentChanged = false;
         mTask.addChild(mToken, 0);
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/MockSurfaceControlBuilder.java b/services/tests/wmtests/src/com/android/server/wm/MockSurfaceControlBuilder.java
new file mode 100644
index 0000000..66139e6
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/MockSurfaceControlBuilder.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static org.mockito.Mockito.mock;
+
+import android.view.SurfaceControl;
+
+/**
+ * Stubbed {@link SurfaceControl.Builder} class that returns a mocked SurfaceControl instance
+ * that can be used for unit testing.
+ */
+class MockSurfaceControlBuilder extends SurfaceControl.Builder {
+    @Override
+    public SurfaceControl.Builder setParent(SurfaceControl sc) {
+        return this;
+    }
+
+    @Override
+    public SurfaceControl build() {
+        return mock(SurfaceControl.class);
+    }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java b/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java
new file mode 100644
index 0000000..d919fc8
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/StubTransaction.java
@@ -0,0 +1,251 @@
+/*
+ * 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.wm;
+
+import android.graphics.Matrix;
+import android.graphics.Rect;
+import android.graphics.Region;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.view.InputWindowHandle;
+import android.view.Surface;
+import android.view.SurfaceControl;
+
+/**
+ * Stubbed {@link android.view.SurfaceControl.Transaction} class that can be used when unit
+ * testing to avoid calls to native code.
+ */
+public class StubTransaction extends SurfaceControl.Transaction {
+    @Override
+    public void apply() {
+    }
+
+    @Override
+    public void close() {
+    }
+
+    @Override
+    public void apply(boolean sync) {
+    }
+
+    @Override
+    public SurfaceControl.Transaction setVisibility(SurfaceControl sc, boolean visible) {
+        return this;
+    }
+
+    @Override
+    public SurfaceControl.Transaction show(SurfaceControl sc) {
+        return this;
+    }
+
+    @Override
+    public SurfaceControl.Transaction hide(SurfaceControl sc) {
+        return this;
+    }
+
+    @Override
+    public SurfaceControl.Transaction setPosition(SurfaceControl sc, float x, float y) {
+        return this;
+    }
+
+    @Override
+    public SurfaceControl.Transaction setBufferSize(SurfaceControl sc,
+            int w, int h) {
+        return this;
+    }
+
+    @Override
+    public SurfaceControl.Transaction setLayer(SurfaceControl sc, int z) {
+        return this;
+    }
+
+    @Override
+    public SurfaceControl.Transaction setRelativeLayer(SurfaceControl sc, SurfaceControl relativeTo,
+            int z) {
+        return this;
+    }
+
+    @Override
+    public SurfaceControl.Transaction setTransparentRegionHint(SurfaceControl sc,
+            Region transparentRegion) {
+        return this;
+    }
+
+    @Override
+    public SurfaceControl.Transaction setAlpha(SurfaceControl sc, float alpha) {
+        return this;
+    }
+
+    @Override
+    public SurfaceControl.Transaction setInputWindowInfo(SurfaceControl sc,
+            InputWindowHandle handle) {
+        return this;
+    }
+
+    @Override
+    public SurfaceControl.Transaction transferTouchFocus(IBinder fromToken, IBinder toToken) {
+        return this;
+    }
+
+    @Override
+    public SurfaceControl.Transaction setGeometry(SurfaceControl sc, Rect sourceCrop,
+            Rect destFrame, @Surface.Rotation int orientation) {
+        return this;
+    }
+
+    @Override
+    public SurfaceControl.Transaction setMatrix(SurfaceControl sc,
+            float dsdx, float dtdx, float dtdy, float dsdy) {
+        return this;
+    }
+
+    @Override
+    public SurfaceControl.Transaction setMatrix(SurfaceControl sc, Matrix matrix, float[] float9) {
+        return this;
+    }
+
+    @Override
+    public SurfaceControl.Transaction setColorTransform(SurfaceControl sc, float[] matrix,
+            float[] translation) {
+        return this;
+    }
+
+    @Override
+    public SurfaceControl.Transaction setWindowCrop(SurfaceControl sc, Rect crop) {
+        return this;
+    }
+
+    @Override
+    public SurfaceControl.Transaction setWindowCrop(SurfaceControl sc, int width, int height) {
+        return this;
+    }
+
+    @Override
+    public SurfaceControl.Transaction setCornerRadius(SurfaceControl sc, float cornerRadius) {
+        return this;
+    }
+
+    @Override
+    public SurfaceControl.Transaction setLayerStack(SurfaceControl sc, int layerStack) {
+        return this;
+    }
+
+    @Override
+    public SurfaceControl.Transaction deferTransactionUntil(SurfaceControl sc, IBinder handle,
+            long frameNumber) {
+        return this;
+    }
+
+    @Override
+    public SurfaceControl.Transaction deferTransactionUntilSurface(SurfaceControl sc,
+            Surface barrierSurface,
+            long frameNumber) {
+        return this;
+    }
+
+    @Override
+    public SurfaceControl.Transaction reparentChildren(SurfaceControl sc, IBinder newParentHandle) {
+        return this;
+    }
+
+    @Override
+    public SurfaceControl.Transaction reparent(SurfaceControl sc, SurfaceControl newParent) {
+        return this;
+    }
+
+    @Override
+    public SurfaceControl.Transaction detachChildren(SurfaceControl sc) {
+        return this;
+    }
+
+    @Override
+    public SurfaceControl.Transaction setOverrideScalingMode(SurfaceControl sc,
+            int overrideScalingMode) {
+        return this;
+    }
+
+    @Override
+    public SurfaceControl.Transaction setColor(SurfaceControl sc, float[] color) {
+        return this;
+    }
+
+    @Override
+    public SurfaceControl.Transaction setGeometryAppliesWithResize(SurfaceControl sc) {
+        return this;
+    }
+
+    @Override
+    public SurfaceControl.Transaction setSecure(SurfaceControl sc, boolean isSecure) {
+        return this;
+    }
+
+    @Override
+    public SurfaceControl.Transaction setOpaque(SurfaceControl sc, boolean isOpaque) {
+        return this;
+    }
+
+    @Override
+    public SurfaceControl.Transaction setDisplaySurface(IBinder displayToken, Surface surface) {
+        return this;
+    }
+
+    @Override
+    public SurfaceControl.Transaction setDisplayLayerStack(IBinder displayToken, int layerStack) {
+        return this;
+    }
+
+    @Override
+    public SurfaceControl.Transaction setDisplayProjection(IBinder displayToken,
+            int orientation, Rect layerStackRect, Rect displayRect) {
+        return this;
+    }
+
+    @Override
+    public SurfaceControl.Transaction setDisplaySize(IBinder displayToken, int width, int height) {
+        return this;
+    }
+
+    @Override
+    public SurfaceControl.Transaction setAnimationTransaction() {
+        return this;
+    }
+
+    @Override
+    public SurfaceControl.Transaction setEarlyWakeup() {
+        return this;
+    }
+
+    @Override
+    public SurfaceControl.Transaction setMetadata(int key, int data) {
+        return this;
+    }
+
+    @Override
+    public SurfaceControl.Transaction setMetadata(int key, Parcel data) {
+        return this;
+    }
+
+    @Override
+    public SurfaceControl.Transaction merge(SurfaceControl.Transaction other) {
+        return this;
+    }
+
+    @Override
+    public SurfaceControl.Transaction remove(SurfaceControl sc) {
+        return this;
+    }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index 712cd1e..366acea 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -167,7 +167,7 @@
 
         mWindowManagerPolicy = new TestWindowManagerPolicy(this::getWindowManagerService);
         mWindowManagerService = WindowManagerService.main(
-                context, ims, false, false, mWindowManagerPolicy, atms);
+                context, ims, false, false, mWindowManagerPolicy, atms, StubTransaction::new);
 
         mWindowManagerService.onInitReady();
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
index d07230e..6249bde 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WallpaperControllerTests.java
@@ -21,11 +21,9 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
 
-import static junit.framework.TestCase.assertNotNull;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 
-import static org.junit.Assert.assertNull;
-
-import android.graphics.Bitmap;
 import android.os.IBinder;
 import android.platform.test.annotations.Presubmit;
 
@@ -37,7 +35,7 @@
  * Tests for the {@link WallpaperController} class.
  *
  * Build/Install/Run:
- *  atest FrameworksServicesTests:WallpaperControllerTests
+ *  atest WmTests:WallpaperControllerTests
  */
 @SmallTest
 @Presubmit
@@ -49,34 +47,29 @@
         synchronized (mWm.mGlobalLock) {
             // No wallpaper
             final DisplayContent dc = createNewDisplay();
-            Bitmap wallpaperBitmap = dc.mWallpaperController.screenshotWallpaperLocked();
-            assertNull(wallpaperBitmap);
+            assertFalse(dc.mWallpaperController.canScreenshotWallpaper());
 
             // No wallpaper WSA Surface
             WindowToken wallpaperWindowToken = new WallpaperWindowToken(mWm, mock(IBinder.class),
                     true, dc, true /* ownerCanManageAppTokens */);
             WindowState wallpaperWindow = createWindow(null /* parent */, TYPE_WALLPAPER,
                     wallpaperWindowToken, "wallpaperWindow");
-            wallpaperBitmap = dc.mWallpaperController.screenshotWallpaperLocked();
-            assertNull(wallpaperBitmap);
+            assertFalse(dc.mWallpaperController.canScreenshotWallpaper());
 
             // Wallpaper with not visible WSA surface.
             wallpaperWindow.mWinAnimator.mSurfaceController = windowSurfaceController;
             wallpaperWindow.mWinAnimator.mLastAlpha = 1;
-            wallpaperBitmap = dc.mWallpaperController.screenshotWallpaperLocked();
-            assertNull(wallpaperBitmap);
+            assertFalse(dc.mWallpaperController.canScreenshotWallpaper());
 
             when(windowSurfaceController.getShown()).thenReturn(true);
 
             // Wallpaper with WSA alpha set to 0.
             wallpaperWindow.mWinAnimator.mLastAlpha = 0;
-            wallpaperBitmap = dc.mWallpaperController.screenshotWallpaperLocked();
-            assertNull(wallpaperBitmap);
+            assertFalse(dc.mWallpaperController.canScreenshotWallpaper());
 
             // Wallpaper window with WSA Surface
             wallpaperWindow.mWinAnimator.mLastAlpha = 1;
-            wallpaperBitmap = dc.mWallpaperController.screenshotWallpaperLocked();
-            assertNotNull(wallpaperBitmap);
+            assertTrue(dc.mWallpaperController.canScreenshotWallpaper());
         }
     }
 }
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
index 5bfa0c6..da1defa 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java
@@ -28,7 +28,6 @@
 import android.os.IBinder;
 import android.view.IApplicationToken;
 import android.view.IWindow;
-import android.view.SurfaceControl.Transaction;
 import android.view.WindowManager;
 
 /**
@@ -72,7 +71,6 @@
     static class TestAppWindowToken extends AppWindowToken {
         boolean mOnTop = false;
         private boolean mSkipPrepareSurfaces;
-        private Transaction mPendingTransactionOverride;
         boolean mSkipOnParentChanged = true;
 
         private TestAppWindowToken(DisplayContent dc, boolean skipOnParentChanged) {
@@ -126,17 +124,6 @@
         void setSkipPrepareSurfaces(boolean ignore) {
             mSkipPrepareSurfaces = ignore;
         }
-
-        void setPendingTransaction(Transaction transaction) {
-            mPendingTransactionOverride = transaction;
-        }
-
-        @Override
-        public Transaction getPendingTransaction() {
-            return mPendingTransactionOverride == null
-                    ? super.getPendingTransaction()
-                    : mPendingTransactionOverride;
-        }
     }
 
     /**
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index 0d7d085..d202e16 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -37,7 +37,10 @@
 
 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
 
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
+
+import static org.mockito.Mockito.mock;
+
 
 import android.content.Context;
 import android.content.res.Configuration;
@@ -47,6 +50,8 @@
 import android.view.Display;
 import android.view.DisplayInfo;
 import android.view.IWindow;
+import android.view.Surface;
+import android.view.SurfaceControl.Transaction;
 import android.view.WindowManager;
 
 import com.android.server.AttributeCache;
@@ -96,10 +101,9 @@
     private MockTracker mMockTracker;
 
     /**
-     * To restore the original SurfaceControl.Transaction factory if any tests changed
-     * {@link WindowManagerService#mTransactionFactory}.
+     * Spied {@link Transaction} class than can be used to verify calls.
      */
-    private TransactionFactory mOriginalTransactionFactory;
+    Transaction mTransaction;
 
     @Rule
     public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule =
@@ -129,11 +133,21 @@
         // in the set up are clear. This can be removed when b/37850063 is fixed.
         try {
             mMockSession = mock(Session.class);
+            mTransaction = spy(StubTransaction.class);
 
             final Context context = getInstrumentation().getTargetContext();
 
             mWm = mSystemServicesTestRule.getWindowManagerService();
-            mOriginalTransactionFactory = mWm.mTransactionFactory;
+
+            // Setup factory classes to prevent calls to native code.
+
+            // Return a spied Transaction class than can be used to verify calls.
+            mWm.mTransactionFactory = () -> mTransaction;
+            // Return a SurfaceControl.Builder class that creates mocked SurfaceControl instances.
+            mWm.mSurfaceBuilderFactory = (unused) -> new MockSurfaceControlBuilder();
+            // Return mocked Surface instances.
+            mWm.mSurfaceFactory = () -> mock(Surface.class);
+
             beforeCreateDisplay();
 
             context.getDisplay().getDisplayInfo(mDisplayInfo);
@@ -183,7 +197,6 @@
             // stable state to clean up for consistency.
             waitUntilHandlersIdle();
 
-            mWm.mTransactionFactory = mOriginalTransactionFactory;
             final LinkedList<WindowState> nonCommonWindows = new LinkedList<>();
 
             synchronized (mWm.mGlobalLock) {
diff --git a/telecomm/java/android/telecom/CallIdentification.java b/telecomm/java/android/telecom/CallIdentification.java
index 87834fd..cde7f60 100644
--- a/telecomm/java/android/telecom/CallIdentification.java
+++ b/telecomm/java/android/telecom/CallIdentification.java
@@ -45,13 +45,13 @@
      * {@link CallIdentification} for a screened call.
      */
     public static class Builder {
-        private String mName;
-        private String mDescription;
-        private String mDetails;
+        private CharSequence mName;
+        private CharSequence mDescription;
+        private CharSequence mDetails;
         private Icon mPhoto;
         private int mNuisanceConfidence = CallIdentification.CONFIDENCE_UNKNOWN;
         private String mPackageName;
-        private String mAppName;
+        private CharSequence mAppName;
 
         /**
          * Default builder constructor.
@@ -67,7 +67,7 @@
          * @param callIdAppName The app name.
          * @hide
          */
-        public Builder(String callIdPackageName, String callIdAppName) {
+        public Builder(String callIdPackageName, CharSequence callIdAppName) {
             mPackageName = callIdPackageName;
             mAppName = callIdAppName;
         }
@@ -80,7 +80,7 @@
          * @param name The name associated with the call, or {@code null} if none is provided.
          * @return Builder instance.
          */
-        public Builder setName(@Nullable String name) {
+        public Builder setName(@Nullable CharSequence name) {
             mName = name;
             return this;
         }
@@ -97,7 +97,7 @@
          * @param description The call description, or {@code null} if none is provided.
          * @return Builder instance.
          */
-        public Builder setDescription(@Nullable String description) {
+        public Builder setDescription(@Nullable CharSequence description) {
             mDescription = description;
             return this;
         }
@@ -114,7 +114,7 @@
          * @param details The call details, or {@code null} if none is provided.
          * @return Builder instance.
          */
-        public Builder setDetails(@Nullable String details) {
+        public Builder setDetails(@Nullable CharSequence details) {
             mDetails = details;
             return this;
         }
@@ -241,10 +241,10 @@
      *                             call identification.
      * @hide
      */
-    private CallIdentification(@Nullable String name, @Nullable String description,
-            @Nullable String details, @Nullable Icon photo,
+    private CallIdentification(@Nullable CharSequence name, @Nullable CharSequence description,
+            @Nullable CharSequence details, @Nullable Icon photo,
             @NuisanceConfidence int nuisanceConfidence, @NonNull String callScreeningPackageName,
-            @NonNull String callScreeningAppName) {
+            @NonNull CharSequence callScreeningAppName) {
         mName = name;
         mDescription = description;
         mDetails = details;
@@ -254,13 +254,13 @@
         mCallScreeningPackageName = callScreeningPackageName;
     }
 
-    private String mName;
-    private String mDescription;
-    private String mDetails;
+    private CharSequence mName;
+    private CharSequence mDescription;
+    private CharSequence mDetails;
     private Icon mPhoto;
     private int mNuisanceConfidence;
     private String mCallScreeningPackageName;
-    private String mCallScreeningAppName;
+    private CharSequence mCallScreeningAppName;
 
     @Override
     public int describeContents() {
@@ -269,13 +269,13 @@
 
     @Override
     public void writeToParcel(Parcel parcel, int i) {
-        parcel.writeString(mName);
-        parcel.writeString(mDescription);
-        parcel.writeString(mDetails);
+        parcel.writeCharSequence(mName);
+        parcel.writeCharSequence(mDescription);
+        parcel.writeCharSequence(mDetails);
         parcel.writeParcelable(mPhoto, 0);
         parcel.writeInt(mNuisanceConfidence);
         parcel.writeString(mCallScreeningPackageName);
-        parcel.writeString(mCallScreeningAppName);
+        parcel.writeCharSequence(mCallScreeningAppName);
     }
 
     /**
@@ -286,13 +286,13 @@
 
                 @Override
                 public CallIdentification createFromParcel(Parcel source) {
-                    String name = source.readString();
-                    String description = source.readString();
-                    String details = source.readString();
+                    CharSequence name = source.readCharSequence();
+                    CharSequence description = source.readCharSequence();
+                    CharSequence details = source.readCharSequence();
                     Icon photo = source.readParcelable(ClassLoader.getSystemClassLoader());
                     int nuisanceConfidence = source.readInt();
                     String callScreeningPackageName = source.readString();
-                    String callScreeningAppName = source.readString();
+                    CharSequence callScreeningAppName = source.readCharSequence();
                     return new CallIdentification(name, description, details, photo,
                             nuisanceConfidence, callScreeningPackageName, callScreeningAppName);
                 }
@@ -311,7 +311,7 @@
      *
      * @return The name associated with the number, or {@code null} if none was provided.
      */
-    public final @Nullable String getName() {
+    public final @Nullable CharSequence getName() {
         return mName;
     }
 
@@ -325,7 +325,7 @@
      *
      * @return The call description, or {@code null} if none was provided.
      */
-    public final @Nullable String getDescription() {
+    public final @Nullable CharSequence getDescription() {
         return mDescription;
     }
 
@@ -340,7 +340,7 @@
      *
      * @return The call details, or {@code null} if none was provided.
      */
-    public final @Nullable String getDetails() {
+    public final @Nullable CharSequence getDetails() {
         return mDetails;
     }
 
@@ -363,8 +363,7 @@
      *
      * @return The nuisance confidence.
      */
-    public final @NuisanceConfidence
-    int getNuisanceConfidence() {
+    public final @NuisanceConfidence int getNuisanceConfidence() {
         return mNuisanceConfidence;
     }
 
@@ -387,7 +386,7 @@
      *
      * @return The name of the app.
      */
-    public final @NonNull String getCallScreeningAppName() {
+    public final @NonNull CharSequence getCallScreeningAppName() {
         return mCallScreeningAppName;
     }
 
@@ -407,7 +406,7 @@
      * @param callScreeningAppName The app name.
      * @hide
      */
-    public void setCallScreeningAppName(@NonNull String callScreeningAppName) {
+    public void setCallScreeningAppName(@NonNull CharSequence callScreeningAppName) {
         mCallScreeningAppName = callScreeningAppName;
     }
 
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index ad98e36..c0444bb 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -2992,9 +2992,9 @@
         /* Default value is 1024 kbps */
         sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_BANDWIDTH_INT, 1024);
         /* Default value is 10 seconds */
-        sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_ENTRY_OR_EXIT_HYSTERESIS_TIME_LONG, 10000);
+        sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_ENTRY_OR_EXIT_HYSTERESIS_TIME_LONG, 10000);
         /* Default value is 10 seconds. */
-        sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_DATA_SWITCH_HYSTERESIS_TIME_LONG, 10000);
+        sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_DATA_SWITCH_HYSTERESIS_TIME_LONG, 10000);
         sDefaults.putAll(Gps.getDefaults());
         sDefaults.putIntArray(KEY_CDMA_ENHANCED_ROAMING_INDICATOR_FOR_HOME_NETWORK_INT_ARRAY,
                 new int[] {
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index a1aee6d..3dc1199 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -1569,6 +1569,17 @@
     /** @hide */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
     public @TelephonyManager.NetworkType int getDataNetworkType() {
+        final NetworkRegistrationState iwlanRegState = getNetworkRegistrationState(
+                NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TransportType.WLAN);
+        if (iwlanRegState != null
+                && iwlanRegState.getRegState() == NetworkRegistrationState.REG_STATE_HOME) {
+            // If the device is on IWLAN, return IWLAN as the network type. This is to simulate the
+            // behavior of legacy mode device. In the future caller should use
+            // getNetworkRegistrationState() to retrieve the actual data network type on cellular
+            // or on IWLAN.
+            return iwlanRegState.getAccessNetworkTechnology();
+        }
+
         final NetworkRegistrationState regState = getNetworkRegistrationState(
                 NetworkRegistrationState.DOMAIN_PS, AccessNetworkConstants.TransportType.WWAN);
         if (regState != null) {
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index 94f26a8..c28d1fb 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -2081,7 +2081,7 @@
         try {
             ISub iSub = ISub.Stub.asInterface(ServiceManager.getService("isub"));
             if (iSub != null) {
-                subId = iSub.getActiveSubIdList();
+                subId = iSub.getActiveSubIdList(/*visibleOnly*/true);
             }
         } catch (RemoteException ex) {
             // ignore it
@@ -2866,7 +2866,7 @@
      *
      * @hide
      */
-    private boolean shouldHideSubscription(SubscriptionInfo info) {
+    public boolean shouldHideSubscription(SubscriptionInfo info) {
         if (info == null) return false;
 
         // If hasCarrierPrivileges or canManageSubscription returns true, it means caller
@@ -2874,8 +2874,14 @@
         boolean hasCarrierPrivilegePermission = (info.isEmbedded() && canManageSubscription(info))
                 || TelephonyManager.from(mContext).hasCarrierPrivileges(info.getSubscriptionId());
 
-        return (!TextUtils.isEmpty(info.getGroupUuid()) && info.isOpportunistic()
-                && !hasCarrierPrivilegePermission);
+        return isInvisibleSubscription(info) && !hasCarrierPrivilegePermission;
+    }
+
+    /**
+     * @hide
+     */
+    public static boolean isInvisibleSubscription(SubscriptionInfo info) {
+        return info != null && !TextUtils.isEmpty(info.getGroupUuid()) && info.isOpportunistic();
     }
 
     /**
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 0b72679..f1869b0 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -10306,24 +10306,25 @@
 
     /**
      * Returns if the usage of multiple SIM cards at the same time to register on the network
-     * (e.g. Dual Standby or Dual Active) is restricted.
+     * (e.g. Dual Standby or Dual Active) is supported by the device and by the carrier.
      *
-     * @return true if usage of multiple SIMs is restricted, false otherwise.
+     * <p>Requires Permission: {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
+     * or that the calling app has carrier privileges (see {@link #hasCarrierPrivileges}).
      *
-     * @hide
+     * @return true if usage of multiple SIMs is supported, false otherwise.
      */
-    @SystemApi
-    @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
-    public boolean isMultisimCarrierRestricted() {
+    @SuppressAutoDoc // Blocked by b/72967236 - no support for carrier privileges
+    @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
+    public boolean isMultisimSupported() {
         try {
             ITelephony service = getITelephony();
             if (service != null) {
-                return service.isMultisimCarrierRestricted();
+                return service.isMultisimSupported(getOpPackageName());
             }
         } catch (RemoteException e) {
-            Log.e(TAG, "isMultisimCarrierRestricted RemoteException", e);
+            Log.e(TAG, "isMultisimSupported RemoteException", e);
         }
-        return true;
+        return false;
     }
 
     /**
@@ -10338,8 +10339,8 @@
     @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
     public void switchMultiSimConfig(int numOfSims) {
         //only proceed if multi-sim is not restricted
-        if (isMultisimCarrierRestricted()) {
-            Rlog.e(TAG, "switchMultiSimConfig not possible. It is restricted.");
+        if (!isMultisimSupported()) {
+            Rlog.e(TAG, "switchMultiSimConfig not possible. It is restricted or not supported.");
             return;
         }
 
diff --git a/telephony/java/com/android/internal/telephony/ISub.aidl b/telephony/java/com/android/internal/telephony/ISub.aidl
index 75a4d82..79e0aa1 100755
--- a/telephony/java/com/android/internal/telephony/ISub.aidl
+++ b/telephony/java/com/android/internal/telephony/ISub.aidl
@@ -275,7 +275,7 @@
 
     void clearDefaultsForInactiveSubIds();
 
-    int[] getActiveSubIdList();
+    int[] getActiveSubIdList(boolean visibleOnly);
 
     int setSubscriptionProperty(int subId, String propKey, String propValue);
 
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index c54a606..d183837 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -1834,10 +1834,12 @@
     void setMultisimCarrierRestriction(boolean isMultisimCarrierRestricted);
 
     /**
-     * Returns if the usage of multiple SIM cards at the same time is restricted.
-     * @hide
+     * Returns if the usage of multiple SIM cards at the same time is supported.
+     *
+     * @param callingPackage The package making the call.
+     * @return true if multisim is supported, false otherwise.
      */
-    boolean isMultisimCarrierRestricted();
+    boolean isMultisimSupported(String callingPackage);
 
     /**
      * Switch configs to enable multi-sim or switch back to single-sim
diff --git a/telephony/java/com/android/internal/telephony/TelephonyProperties.java b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
index 603c4c2..030c3f4 100644
--- a/telephony/java/com/android/internal/telephony/TelephonyProperties.java
+++ b/telephony/java/com/android/internal/telephony/TelephonyProperties.java
@@ -188,18 +188,17 @@
      */
     static final String PROPERTY_IGNORE_NITZ = "telephony.test.ignore.nitz";
 
-     /**
+    /**
      * Property to set multi sim feature.
      * Type:  String(dsds, dsda)
      */
     static final String PROPERTY_MULTI_SIM_CONFIG = "persist.radio.multisim.config";
 
-     /**
+    /**
      * Property to indicate if reboot is required when changing modems configurations
      * Type:  String(true, false) default is false; most devices don't need reboot
      */
-    String PROPERTY_REBOOT_REQUIRED_ON_MODEM_CHANGE =
-             "persist.radio.reboot_on_modem_change";
+    String PROPERTY_REBOOT_REQUIRED_ON_MODEM_CHANGE = "persist.radio.reboot_on_modem_change";
 
     /**
      * Property to store default subscription.
diff --git a/test-mock/api/test-current.txt b/test-mock/api/test-current.txt
index 0cb8f22..6765316 100644
--- a/test-mock/api/test-current.txt
+++ b/test-mock/api/test-current.txt
@@ -1,6 +1,10 @@
 // Signature format: 2.0
 package android.test.mock {
 
+  public class MockContext extends android.content.Context {
+    method public android.view.Display getDisplay();
+  }
+
   @Deprecated public class MockPackageManager extends android.content.pm.PackageManager {
     method public boolean arePermissionsIndividuallyControlled();
     method public String getDefaultBrowserPackageNameAsUser(int);
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index a10fb4e..ed524f6 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -154,6 +154,7 @@
 import android.text.TextUtils;
 import android.util.ArraySet;
 import android.util.Log;
+import android.util.SparseArray;
 
 import com.android.internal.net.VpnConfig;
 import com.android.internal.util.ArrayUtils;
@@ -748,6 +749,10 @@
         // mExpectations is non-empty.
         private boolean mExpectingAdditions;
 
+        // Used to collect the networks requests managed by this factory. This is a duplicate of
+        // the internal information stored in the NetworkFactory (which is private).
+        private SparseArray<NetworkRequest> mNetworkRequests = new SparseArray<>();
+
         public MockNetworkFactory(Looper looper, Context context, String logTag,
                 NetworkCapabilities filter) {
             super(looper, context, logTag, filter);
@@ -800,6 +805,7 @@
                 }
 
                 // Add the request.
+                mNetworkRequests.put(request.requestId, request);
                 super.handleAddRequest(request, score, factorySerialNumber);
                 mExpectations.notify();
             }
@@ -817,11 +823,17 @@
                 }
 
                 // Remove the request.
+                mNetworkRequests.remove(request.requestId);
                 super.handleRemoveRequest(request);
                 mExpectations.notify();
             }
         }
 
+        // Trigger releasing the request as unfulfillable
+        public void triggerUnfulfillable(NetworkRequest r) {
+            super.releaseRequestAsUnfulfillableByAnyFactory(r);
+        }
+
         private void assertNoExpectations() {
             if (mExpectations.size() != 0) {
                 fail("Can't add expectation, " + mExpectations.size() + " already pending");
@@ -861,9 +873,11 @@
             assertEquals(msg, 0, count);
         }
 
-        public void waitForNetworkRequests(final int count) throws InterruptedException {
+        public SparseArray<NetworkRequest> waitForNetworkRequests(final int count)
+                throws InterruptedException {
             waitForRequests();
             assertEquals(count, getMyRequestCount());
+            return mNetworkRequests;
         }
     }
 
@@ -3533,6 +3547,55 @@
         networkCallback.assertNoCallback();
     }
 
+    /**
+     * Validate the callback flow for a factory releasing a request as unfulfillable.
+     */
+    @Test
+    public void testUnfulfillableNetworkRequest() throws Exception {
+        NetworkRequest nr = new NetworkRequest.Builder().addTransportType(
+                NetworkCapabilities.TRANSPORT_WIFI).build();
+        final TestNetworkCallback networkCallback = new TestNetworkCallback();
+
+        final HandlerThread handlerThread = new HandlerThread("testUnfulfillableNetworkRequest");
+        handlerThread.start();
+        NetworkCapabilities filter = new NetworkCapabilities()
+                .addTransportType(TRANSPORT_WIFI)
+                .addCapability(NET_CAPABILITY_INTERNET);
+        final MockNetworkFactory testFactory = new MockNetworkFactory(handlerThread.getLooper(),
+                mServiceContext, "testFactory", filter);
+        testFactory.setScoreFilter(40);
+
+        // Register the factory and expect it to receive the default request.
+        testFactory.expectAddRequestsWithScores(0);
+        testFactory.register();
+        SparseArray<NetworkRequest> requests = testFactory.waitForNetworkRequests(1);
+
+        assertEquals(1, requests.size()); // have 1 request at this point
+        int origRequestId = requests.valueAt(0).requestId;
+
+        // Now file the test request and expect it.
+        testFactory.expectAddRequestsWithScores(0);
+        mCm.requestNetwork(nr, networkCallback);
+        requests = testFactory.waitForNetworkRequests(2); // have 2 requests at this point
+
+        int newRequestId = 0;
+        for (int i = 0; i < requests.size(); ++i) {
+            if (requests.valueAt(i).requestId != origRequestId) {
+                newRequestId = requests.valueAt(i).requestId;
+                break;
+            }
+        }
+
+        // Simulate the factory releasing the request as unfulfillable and expect onUnavailable!
+        testFactory.expectRemoveRequests(1);
+        testFactory.triggerUnfulfillable(requests.get(newRequestId));
+        networkCallback.expectCallback(CallbackState.UNAVAILABLE, null);
+        testFactory.waitForRequests();
+
+        testFactory.unregister();
+        handlerThread.quit();
+    }
+
     private static class TestKeepaliveCallback extends PacketKeepaliveCallback {
 
         public static enum CallbackType { ON_STARTED, ON_STOPPED, ON_ERROR };
diff --git a/wifi/java/android/net/wifi/WifiInfo.java b/wifi/java/android/net/wifi/WifiInfo.java
index af9fdfb..089b59a 100644
--- a/wifi/java/android/net/wifi/WifiInfo.java
+++ b/wifi/java/android/net/wifi/WifiInfo.java
@@ -137,6 +137,16 @@
     private boolean mOsuAp;
 
     /**
+     * Fully qualified domain name of a Passpoint configuration
+     */
+    private String mFqdn;
+
+    /**
+     * Name of Passpoint credential provider
+     */
+    private String mProviderFriendlyName;
+
+    /**
      * If connected to a network suggestion or specifier, store the package name of the app,
      * else null.
      */
@@ -223,6 +233,8 @@
         setEphemeral(false);
         setOsuAp(false);
         setNetworkSuggestionOrSpecifierPackageName(null);
+        setFQDN(null);
+        setProviderFriendlyName(null);
         txBad = 0;
         txSuccess = 0;
         rxSuccess = 0;
@@ -257,6 +269,8 @@
             mNetworkSuggestionOrSpecifierPackageName =
                     source.mNetworkSuggestionOrSpecifierPackageName;
             mOsuAp = source.mOsuAp;
+            mFqdn = source.mFqdn;
+            mProviderFriendlyName = source.mProviderFriendlyName;
             txBad = source.txBad;
             txRetries = source.txRetries;
             txSuccess = source.txSuccess;
@@ -504,6 +518,34 @@
     }
 
     /** {@hide} */
+    @SystemApi
+    public boolean isPasspointAp() {
+        return mFqdn != null && mProviderFriendlyName != null;
+    }
+
+    /** {@hide} */
+    public void setFQDN(@Nullable String fqdn) {
+        mFqdn = fqdn;
+    }
+
+    /** {@hide} */
+    @SystemApi
+    public @Nullable String getFqdn() {
+        return mFqdn;
+    }
+
+    /** {@hide} */
+    public void setProviderFriendlyName(@Nullable String providerFriendlyName) {
+        mProviderFriendlyName = providerFriendlyName;
+    }
+
+    /** {@hide} */
+    @SystemApi
+    public @Nullable String getProviderFriendlyName() {
+        return mProviderFriendlyName;
+    }
+
+    /** {@hide} */
     public void setNetworkSuggestionOrSpecifierPackageName(@Nullable String packageName) {
         mNetworkSuggestionOrSpecifierPackageName = packageName;
     }
@@ -677,6 +719,8 @@
         mSupplicantState.writeToParcel(dest, flags);
         dest.writeInt(mOsuAp ? 1 : 0);
         dest.writeString(mNetworkSuggestionOrSpecifierPackageName);
+        dest.writeString(mFqdn);
+        dest.writeString(mProviderFriendlyName);
     }
 
     /** Implement the Parcelable interface {@hide} */
@@ -716,6 +760,8 @@
                 info.mSupplicantState = SupplicantState.CREATOR.createFromParcel(in);
                 info.mOsuAp = in.readInt() != 0;
                 info.mNetworkSuggestionOrSpecifierPackageName = in.readString();
+                info.mFqdn = in.readString();
+                info.mProviderFriendlyName = in.readString();
                 return info;
             }
 
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index 7caace6..6c645fc 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -1738,10 +1738,7 @@
      * @deprecated This is no longer supported.
      */
     @Deprecated
-    @RequiresPermission(anyOf = {
-            android.Manifest.permission.NETWORK_SETTINGS,
-            android.Manifest.permission.NETWORK_SETUP_WIZARD
-    })
+    @RequiresPermission(android.Manifest.permission.NETWORK_SETTINGS)
     public void removePasspointConfiguration(String fqdn) {
         try {
             if (!mService.removePasspointConfiguration(fqdn, mContext.getOpPackageName())) {
diff --git a/wifi/tests/src/android/net/wifi/WifiInfoTest.java b/wifi/tests/src/android/net/wifi/WifiInfoTest.java
index 948dcfa..b303496 100644
--- a/wifi/tests/src/android/net/wifi/WifiInfoTest.java
+++ b/wifi/tests/src/android/net/wifi/WifiInfoTest.java
@@ -36,6 +36,8 @@
     private static final long TEST_TX_BAD = 3;
     private static final long TEST_RX_SUCCESS = 4;
     private static final String TEST_PACKAGE_NAME = "com.test.example";
+    private static final String TEST_FQDN = "test.com";
+    private static final String TEST_PROVIDER_NAME = "test";
 
     /**
      *  Verify parcel write/read with WifiInfo.
@@ -49,6 +51,8 @@
         writeWifiInfo.rxSuccess = TEST_RX_SUCCESS;
         writeWifiInfo.setTrusted(true);
         writeWifiInfo.setOsuAp(true);
+        writeWifiInfo.setFQDN(TEST_FQDN);
+        writeWifiInfo.setProviderFriendlyName(TEST_PROVIDER_NAME);
         writeWifiInfo.setNetworkSuggestionOrSpecifierPackageName(TEST_PACKAGE_NAME);
 
         Parcel parcel = Parcel.obtain();
@@ -64,6 +68,9 @@
         assertEquals(TEST_RX_SUCCESS, readWifiInfo.rxSuccess);
         assertTrue(readWifiInfo.isTrusted());
         assertTrue(readWifiInfo.isOsuAp());
+        assertTrue(readWifiInfo.isPasspointAp());
         assertEquals(TEST_PACKAGE_NAME, readWifiInfo.getNetworkSuggestionOrSpecifierPackageName());
+        assertEquals(TEST_FQDN, readWifiInfo.getFqdn());
+        assertEquals(TEST_PROVIDER_NAME, readWifiInfo.getProviderFriendlyName());
     }
 }